From ba64c93a44c5bdd78b01ef868435dc427f0cf4d4 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Mon, 5 Sep 2022 22:43:26 +0900 Subject: [PATCH 001/175] Lower generator expression to HIR --- crates/hir-def/src/body/lower.rs | 26 ++++++++++++++++++++++++-- crates/hir-def/src/body/pretty.rs | 7 +++++-- crates/hir-def/src/expr.rs | 13 +++++++++++++ crates/hir-ty/src/infer/expr.rs | 2 +- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 3b3297f7811c..c4f91e49a6e1 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -29,8 +29,9 @@ use crate::{ builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, db::DefDatabase, expr::{ - dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, FloatTypeWrapper, Label, LabelId, - Literal, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, Statement, + dummy_expr_id, Array, BindingAnnotation, ClosureKind, Expr, ExprId, FloatTypeWrapper, + Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat, RecordLitField, + Statement, }, intern::Interned, item_scope::BuiltinShadowMode, @@ -97,6 +98,7 @@ pub(super) fn lower( name_to_pat_grouping: Default::default(), is_lowering_inside_or_pat: false, is_lowering_assignee_expr: false, + is_lowering_generator: false, } .collect(params, body) } @@ -111,6 +113,7 @@ struct ExprCollector<'a> { name_to_pat_grouping: FxHashMap>, is_lowering_inside_or_pat: bool, is_lowering_assignee_expr: bool, + is_lowering_generator: bool, } impl ExprCollector<'_> { @@ -358,6 +361,7 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::Return { expr }, syntax_ptr) } ast::Expr::YieldExpr(e) => { + self.is_lowering_generator = true; let expr = e.expr().map(|e| self.collect_expr(e)); self.alloc_expr(Expr::Yield { expr }, syntax_ptr) } @@ -459,13 +463,31 @@ impl ExprCollector<'_> { .ret_type() .and_then(|r| r.ty()) .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it))); + + let prev_is_lowering_generator = self.is_lowering_generator; + self.is_lowering_generator = false; + let body = self.collect_expr_opt(e.body()); + + let closure_kind = if self.is_lowering_generator { + let movability = if e.static_token().is_some() { + Movability::Static + } else { + Movability::Movable + }; + ClosureKind::Generator(movability) + } else { + ClosureKind::Closure + }; + self.is_lowering_generator = prev_is_lowering_generator; + self.alloc_expr( Expr::Closure { args: args.into(), arg_types: arg_types.into(), ret_type, body, + closure_kind, }, syntax_ptr, ) diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index f2fed954444e..35686af38854 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -3,7 +3,7 @@ use std::fmt::{self, Write}; use crate::{ - expr::{Array, BindingAnnotation, Literal, Statement}, + expr::{Array, BindingAnnotation, ClosureKind, Literal, Movability, Statement}, pretty::{print_generic_args, print_path, print_type_ref}, type_ref::TypeRef, }; @@ -350,7 +350,10 @@ impl<'a> Printer<'a> { self.print_expr(*index); w!(self, "]"); } - Expr::Closure { args, arg_types, ret_type, body } => { + Expr::Closure { args, arg_types, ret_type, body, closure_kind } => { + if let ClosureKind::Generator(Movability::Static) = closure_kind { + w!(self, "static "); + } w!(self, "|"); for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() { if i != 0 { diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs index 419d3feec3b6..162646550207 100644 --- a/crates/hir-def/src/expr.rs +++ b/crates/hir-def/src/expr.rs @@ -198,6 +198,7 @@ pub enum Expr { arg_types: Box<[Option>]>, ret_type: Option>, body: ExprId, + closure_kind: ClosureKind, }, Tuple { exprs: Box<[ExprId]>, @@ -211,6 +212,18 @@ pub enum Expr { Underscore, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ClosureKind { + Closure, + Generator(Movability), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Movability { + Static, + Movable, +} + #[derive(Debug, Clone, Eq, PartialEq)] pub enum Array { ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool }, diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 2d04a864a2cf..f0382846a6af 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -216,7 +216,7 @@ impl<'a> InferenceContext<'a> { self.diverges = Diverges::Maybe; TyBuilder::unit() } - Expr::Closure { body, args, ret_type, arg_types } => { + Expr::Closure { body, args, ret_type, arg_types, closure_kind: _ } => { assert_eq!(args.len(), arg_types.len()); let mut sig_tys = Vec::new(); From aeeb9e08b252b24c7cdba0a30e8dd153231c082d Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 9 Sep 2022 15:20:18 +0900 Subject: [PATCH 002/175] Add `TyBuilder` method to build `Substitution` for generator --- crates/hir-ty/src/builder.rs | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs index 94d7806cb6e8..3ae7fb2a617c 100644 --- a/crates/hir-ty/src/builder.rs +++ b/crates/hir-ty/src/builder.rs @@ -9,8 +9,8 @@ use chalk_ir::{ AdtId, BoundVar, DebruijnIndex, Scalar, }; use hir_def::{ - builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId, - TypeAliasId, + builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId, + GenericDefId, TraitId, TypeAliasId, }; use smallvec::SmallVec; @@ -205,6 +205,38 @@ impl TyBuilder<()> { ) } + /// Creates a `TyBuilder` to build `Substitution` for a generator defined in `parent`. + /// + /// A generator's substitution consists of: + /// - generic parameters in scope on `parent` + /// - resume type of generator + /// - yield type of generator ([`Generator::Yield`](std::ops::Generator::Yield)) + /// - return type of generator ([`Generator::Return`](std::ops::Generator::Return)) + /// in this order. + /// + /// This method prepopulates the builder with placeholder substitution of `parent`, so you + /// should only push exactly 3 `GenericArg`s before building. + pub fn subst_for_generator(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> { + let parent_subst = match parent.as_generic_def_id() { + Some(parent) => generics(db.upcast(), parent).placeholder_subst(db), + // Static initializers *may* contain generators. + None => Substitution::empty(Interner), + }; + let builder = TyBuilder::new( + (), + parent_subst + .iter(Interner) + .map(|arg| match arg.constant(Interner) { + Some(c) => ParamKind::Const(c.data(Interner).ty.clone()), + None => ParamKind::Type, + }) + // These represent resume type, yield type, and return type of generator. + .chain(std::iter::repeat(ParamKind::Type).take(3)) + .collect(), + ); + builder.use_parent_substs(&parent_subst) + } + pub fn build(self) -> Substitution { let ((), subst) = self.build_internal(); subst From 77c40f878de2c5bfca8aba5a09fd16d805944727 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Tue, 6 Sep 2022 17:48:06 +0900 Subject: [PATCH 003/175] Implement type inference for generator and yield expressions --- crates/hir-ty/src/db.rs | 6 +++ crates/hir-ty/src/infer.rs | 5 ++- crates/hir-ty/src/infer/closure.rs | 6 +++ crates/hir-ty/src/infer/expr.rs | 67 ++++++++++++++++++++++-------- crates/hir-ty/src/mapping.rs | 12 ++++++ 5 files changed, 78 insertions(+), 18 deletions(-) diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index b385b1cafaef..c4f7685cd140 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -116,6 +116,8 @@ pub trait HirDatabase: DefDatabase + Upcast { fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId; #[salsa::interned] fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId; + #[salsa::interned] + fn intern_generator(&self, id: (DefWithBodyId, ExprId)) -> InternedGeneratorId; #[salsa::invoke(chalk_db::associated_ty_data_query)] fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc; @@ -218,6 +220,10 @@ impl_intern_key!(InternedOpaqueTyId); pub struct InternedClosureId(salsa::InternId); impl_intern_key!(InternedClosureId); +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct InternedGeneratorId(salsa::InternId); +impl_intern_key!(InternedGeneratorId); + /// This exists just for Chalk, because Chalk just has a single `FnDefId` where /// we have different IDs for struct and enum variant constructors. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 10ffde87eef1..d351eb599ce4 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -332,7 +332,7 @@ pub struct InferenceResult { /// unresolved or missing subpatterns or subpatterns of mismatched types. pub type_of_pat: ArenaMap, type_mismatches: FxHashMap, - /// Interned Unknown to return references to. + /// Interned common types to return references to. standard_types: InternedStandardTypes, /// Stores the types which were implicitly dereferenced in pattern binding modes. pub pat_adjustments: FxHashMap>, @@ -412,6 +412,8 @@ pub(crate) struct InferenceContext<'a> { /// closures, but currently this is the only field that will change there, /// so it doesn't make sense. return_ty: Ty, + /// The resume type and the yield type, respectively, of the generator being inferred. + resume_yield_tys: Option<(Ty, Ty)>, diverges: Diverges, breakables: Vec, } @@ -476,6 +478,7 @@ impl<'a> InferenceContext<'a> { table: unify::InferenceTable::new(db, trait_env.clone()), trait_env, return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature + resume_yield_tys: None, db, owner, body, diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 3ead929098bc..094e460dbf79 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -12,6 +12,7 @@ use crate::{ use super::{Expectation, InferenceContext}; impl InferenceContext<'_> { + // This function handles both closures and generators. pub(super) fn deduce_closure_type_from_expectations( &mut self, closure_expr: ExprId, @@ -27,6 +28,11 @@ impl InferenceContext<'_> { // Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here. let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty); + // Generators are not Fn* so return early. + if matches!(closure_ty.kind(Interner), TyKind::Generator(..)) { + return; + } + // Deduction based on the expected `dyn Fn` is done separately. if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) { if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) { diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index f0382846a6af..e3d6be23e658 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -10,7 +10,10 @@ use chalk_ir::{ cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind, }; use hir_def::{ - expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp}, + expr::{ + ArithOp, Array, BinaryOp, ClosureKind, CmpOp, Expr, ExprId, LabelId, Literal, Statement, + UnaryOp, + }, generics::TypeOrConstParamData, path::{GenericArg, GenericArgs}, resolver::resolver_for_expr, @@ -216,7 +219,7 @@ impl<'a> InferenceContext<'a> { self.diverges = Diverges::Maybe; TyBuilder::unit() } - Expr::Closure { body, args, ret_type, arg_types, closure_kind: _ } => { + Expr::Closure { body, args, ret_type, arg_types, closure_kind } => { assert_eq!(args.len(), arg_types.len()); let mut sig_tys = Vec::new(); @@ -244,20 +247,40 @@ impl<'a> InferenceContext<'a> { ), }) .intern(Interner); - let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into(); - let closure_ty = - TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone())) - .intern(Interner); + + let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) { + // FIXME: report error when there are more than 1 parameter. + let resume_ty = match sig_tys.first() { + // When `sig_tys.len() == 1` the first type is the return type, not the + // first parameter type. + Some(ty) if sig_tys.len() > 1 => ty.clone(), + _ => self.result.standard_types.unit.clone(), + }; + let yield_ty = self.table.new_type_var(); + + let subst = TyBuilder::subst_for_generator(self.db, self.owner) + .push(resume_ty.clone()) + .push(yield_ty.clone()) + .push(ret_ty.clone()) + .build(); + + let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into(); + let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner); + + (generator_ty, Some((resume_ty, yield_ty))) + } else { + let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into(); + let closure_ty = + TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone())) + .intern(Interner); + + (closure_ty, None) + }; // Eagerly try to relate the closure type with the expected // type, otherwise we often won't have enough information to // infer the body. - self.deduce_closure_type_from_expectations( - tgt_expr, - &closure_ty, - &sig_ty, - expected, - ); + self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected); // Now go through the argument patterns for (arg_pat, arg_ty) in args.iter().zip(sig_tys) { @@ -266,6 +289,8 @@ impl<'a> InferenceContext<'a> { let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); + let prev_resume_yield_tys = + mem::replace(&mut self.resume_yield_tys, resume_yield_tys); self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| { this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); @@ -273,8 +298,9 @@ impl<'a> InferenceContext<'a> { self.diverges = prev_diverges; self.return_ty = prev_ret_ty; + self.resume_yield_tys = prev_resume_yield_tys; - closure_ty + ty } Expr::Call { callee, args, .. } => { let callee_ty = self.infer_expr(*callee, &Expectation::none()); @@ -423,11 +449,18 @@ impl<'a> InferenceContext<'a> { TyKind::Never.intern(Interner) } Expr::Yield { expr } => { - // FIXME: track yield type for coercion - if let Some(expr) = expr { - self.infer_expr(*expr, &Expectation::none()); + if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() { + if let Some(expr) = expr { + self.infer_expr_coerce(*expr, &Expectation::has_type(yield_ty)); + } else { + let unit = self.result.standard_types.unit.clone(); + let _ = self.coerce(Some(tgt_expr), &unit, &yield_ty); + } + resume_ty + } else { + // FIXME: report error (yield expr in non-generator) + TyKind::Error.intern(Interner) } - TyKind::Never.intern(Interner) } Expr::RecordLit { path, fields, spread, .. } => { let (ty, def_id) = self.resolve_variant(path.as_deref(), false); diff --git a/crates/hir-ty/src/mapping.rs b/crates/hir-ty/src/mapping.rs index d765fee0e1f4..f80fb39c1f84 100644 --- a/crates/hir-ty/src/mapping.rs +++ b/crates/hir-ty/src/mapping.rs @@ -103,6 +103,18 @@ impl From for chalk_ir::ClosureId { } } +impl From> for crate::db::InternedGeneratorId { + fn from(id: chalk_ir::GeneratorId) -> Self { + Self::from_intern_id(id.0) + } +} + +impl From for chalk_ir::GeneratorId { + fn from(id: crate::db::InternedGeneratorId) -> Self { + chalk_ir::GeneratorId(id.as_intern_id()) + } +} + pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId { chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id)) } From 447596cccccf7ba47d93fe447d31717a8936601e Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 9 Sep 2022 15:25:42 +0900 Subject: [PATCH 004/175] Implement `RustIrDatabase::generator_datum()` --- crates/hir-ty/src/chalk_db.rs | 65 ++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index faec99c7d33c..c5cf6729d119 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -11,6 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; use base_db::CrateId; use hir_def::{ + expr::Movability, lang_item::{lang_attr, LangItemTarget}, AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId, }; @@ -26,9 +27,9 @@ use crate::{ to_assoc_type_id, to_chalk_trait_id, traits::ChalkContext, utils::generics, - AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy, - ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, - TyExt, TyKind, WhereClause, + wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, + Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, + TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause, }; pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum; @@ -372,17 +373,63 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { } fn generator_datum( &self, - _: chalk_ir::GeneratorId, + id: chalk_ir::GeneratorId, ) -> std::sync::Arc> { - // FIXME - unimplemented!() + let (parent, expr) = self.db.lookup_intern_generator(id.into()); + + // We fill substitution with unknown type, because we only need to know whether the generic + // params are types or consts to build `Binders` and those being filled up are for + // `resume_type`, `yield_type`, and `return_type` of the generator in question. + let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build(); + + let len = subst.len(Interner); + let input_output = rust_ir::GeneratorInputOutputDatum { + resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 3)) + .intern(Interner), + yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 2)) + .intern(Interner), + return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 1)) + .intern(Interner), + // FIXME: calculate upvars + upvars: vec![], + }; + + let it = subst + .iter(Interner) + .map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone())); + let input_output = crate::make_type_and_const_binders(it, input_output); + + let movability = match self.db.body(parent)[expr] { + hir_def::expr::Expr::Closure { + closure_kind: hir_def::expr::ClosureKind::Generator(movability), + .. + } => movability, + _ => unreachable!("non generator expression interned as generator"), + }; + let movability = match movability { + Movability::Static => rust_ir::Movability::Static, + Movability::Movable => rust_ir::Movability::Movable, + }; + + Arc::new(rust_ir::GeneratorDatum { movability, input_output }) } fn generator_witness_datum( &self, - _: chalk_ir::GeneratorId, + id: chalk_ir::GeneratorId, ) -> std::sync::Arc> { - // FIXME - unimplemented!() + // FIXME: calculate inner types + let inner_types = + rust_ir::GeneratorWitnessExistential { types: wrap_empty_binders(vec![]) }; + + let (parent, _) = self.db.lookup_intern_generator(id.into()); + // See the comment in `generator_datum()` for unknown types. + let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build(); + let it = subst + .iter(Interner) + .map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone())); + let inner_types = crate::make_type_and_const_binders(it, inner_types); + + Arc::new(rust_ir::GeneratorWitnessDatum { inner_types }) } fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase { From 4b5a66e0bc621aa6d152f286ce064bcaff3217be Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 9 Sep 2022 15:27:25 +0900 Subject: [PATCH 005/175] Add tests for type inference for generators --- crates/hir-ty/src/tests/coercion.rs | 18 +++++++ crates/hir-ty/src/tests/simple.rs | 82 +++++++++++++++++++++++++++++ crates/test-utils/src/minicore.rs | 48 +++++++++++++++++ 3 files changed, 148 insertions(+) diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs index bf59fadc2c33..d301595bcd98 100644 --- a/crates/hir-ty/src/tests/coercion.rs +++ b/crates/hir-ty/src/tests/coercion.rs @@ -294,6 +294,24 @@ fn foo() { ); } +#[test] +fn generator_yield_return_coerce() { + check_no_mismatches( + r#" +fn test() { + let g = || { + yield &1u32; + yield &&1u32; + if true { + return &1u32; + } + &&1u32 + }; +} + "#, + ); +} + #[test] fn assign_coerce() { check_no_mismatches( diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index 4ea103e5d9ec..e6ff0762caa5 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -1917,6 +1917,88 @@ fn closure_return_inferred() { ); } +#[test] +fn generator_types_inferred() { + check_infer( + r#" +//- minicore: generator, deref +use core::ops::{Generator, GeneratorState}; +use core::pin::Pin; + +fn f(v: i64) {} +fn test() { + let mut g = |r| { + let a = yield 0; + let a = yield 1; + let a = yield 2; + "return value" + }; + + match Pin::new(&mut g).resume(0usize) { + GeneratorState::Yielded(y) => { f(y); } + GeneratorState::Complete(r) => {} + } +} + "#, + expect![[r#" + 70..71 'v': i64 + 78..80 '{}': () + 91..362 '{ ... } }': () + 101..106 'mut g': {generator} + 109..218 '|r| { ... }': {generator} + 110..111 'r': usize + 113..218 '{ ... }': &str + 127..128 'a': usize + 131..138 'yield 0': usize + 137..138 '0': i64 + 152..153 'a': usize + 156..163 'yield 1': usize + 162..163 '1': i64 + 177..178 'a': usize + 181..188 'yield 2': usize + 187..188 '2': i64 + 198..212 '"return value"': &str + 225..360 'match ... }': () + 231..239 'Pin::new': fn new<&mut {generator}>(&mut {generator}) -> Pin<&mut {generator}> + 231..247 'Pin::n...mut g)': Pin<&mut {generator}> + 231..262 'Pin::n...usize)': GeneratorState + 240..246 '&mut g': &mut {generator} + 245..246 'g': {generator} + 255..261 '0usize': usize + 273..299 'Genera...ded(y)': GeneratorState + 297..298 'y': i64 + 303..312 '{ f(y); }': () + 305..306 'f': fn f(i64) + 305..309 'f(y)': () + 307..308 'y': i64 + 321..348 'Genera...ete(r)': GeneratorState + 346..347 'r': &str + 352..354 '{}': () + "#]], + ); +} + +#[test] +fn generator_resume_yield_return_unit() { + check_no_mismatches( + r#" +//- minicore: generator, deref +use core::ops::{Generator, GeneratorState}; +use core::pin::Pin; +fn test() { + let mut g = || { + let () = yield; + }; + + match Pin::new(&mut g).resume(()) { + GeneratorState::Yielded(()) => {} + GeneratorState::Complete(()) => {} + } +} + "#, + ); +} + #[test] fn fn_pointer_return() { check_infer( diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 6df29db4745d..10386b5b7bcd 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -37,6 +37,7 @@ //! add: //! as_ref: sized //! drop: +//! generator: pin pub mod marker { // region:sized @@ -182,6 +183,19 @@ pub mod ops { type Target: ?Sized; fn deref(&self) -> &Self::Target; } + + impl Deref for &T { + type Target = T; + fn deref(&self) -> &T { + loop {} + } + } + impl Deref for &mut T { + type Target = T; + fn deref(&self) -> &T { + loop {} + } + } // region:deref_mut #[lang = "deref_mut"] pub trait DerefMut: Deref { @@ -347,6 +361,27 @@ pub mod ops { fn add(self, rhs: Rhs) -> Self::Output; } // endregion:add + + // region:generator + mod generator { + use crate::pin::Pin; + + #[lang = "generator"] + pub trait Generator { + type Yield; + #[lang = "generator_return"] + type Return; + fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState; + } + + #[lang = "generator_state"] + pub enum GeneratorState { + Yielded(Y), + Complete(R), + } + } + pub use self::generator::{Generator, GeneratorState}; + // endregion:generator } // region:eq @@ -455,6 +490,19 @@ pub mod pin { pub struct Pin

{ pointer: P, } + impl

Pin

{ + pub fn new(pointer: P) -> Pin

{ + loop {} + } + } + // region:deref + impl crate::ops::Deref for Pin

{ + type Target = P::Target; + fn deref(&self) -> &P::Target { + loop {} + } + } + // endregion:deref } // endregion:pin From 997fc46efad4dac0c325df55e17a55d7cc4cdc05 Mon Sep 17 00:00:00 2001 From: OleStrohm Date: Sat, 6 Aug 2022 18:50:21 +0200 Subject: [PATCH 006/175] Implemented basic enum const eval --- crates/hir-def/src/body.rs | 9 +- crates/hir-def/src/lib.rs | 11 ++ crates/hir-def/src/resolver.rs | 1 + crates/hir-ty/src/consteval.rs | 31 ++++- crates/hir-ty/src/db.rs | 16 ++- crates/hir-ty/src/diagnostics/unsafe_check.rs | 4 +- crates/hir-ty/src/infer.rs | 8 ++ crates/hir-ty/src/tests.rs | 10 +- crates/hir/src/from_id.rs | 10 +- crates/hir/src/lib.rs | 16 ++- crates/hir/src/symbols.rs | 5 + crates/ide-db/src/search.rs | 1 + crates/ide/src/hover/render.rs | 13 ++- crates/ide/src/hover/tests.rs | 109 ++++++++++++++++++ 14 files changed, 227 insertions(+), 17 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 22f5fb992663..484e2d7d7ddb 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -27,7 +27,7 @@ use crate::{ macro_id_to_def_id, nameres::DefMap, path::{ModPath, Path}, - src::HasSource, + src::{HasChildSource, HasSource}, AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId, UnresolvedMacro, }; @@ -324,6 +324,13 @@ impl Body { let src = s.source(db); (src.file_id, s.module(db), src.value.body()) } + DefWithBodyId::VariantId(v) => { + let e = v.parent.lookup(db); + let src = v.parent.child_source(db); + let variant = &src.value[v.local_id]; + // TODO(ole): Handle missing exprs (+1 to the prev) + (src.file_id, e.container, variant.expr()) + } }; let expander = Expander::new(db, file_id, module); let (mut body, source_map) = Body::new(db, expander, params, body); diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 32ebfda4fd92..4c44840e861d 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -474,16 +474,25 @@ pub enum DefWithBodyId { FunctionId(FunctionId), StaticId(StaticId), ConstId(ConstId), + VariantId(EnumVariantId), } impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId); +// FIXME: Rename EnumVariantId to VariantId so that the macro above can be used +impl From for DefWithBodyId { + fn from(id: EnumVariantId) -> Self { + DefWithBodyId::VariantId(id) + } +} + impl DefWithBodyId { pub fn as_generic_def_id(self) -> Option { match self { DefWithBodyId::FunctionId(f) => Some(f.into()), DefWithBodyId::StaticId(_) => None, DefWithBodyId::ConstId(c) => Some(c.into()), + DefWithBodyId::VariantId(c) => Some(c.into()), } } } @@ -681,6 +690,7 @@ impl HasModule for DefWithBodyId { DefWithBodyId::FunctionId(it) => it.lookup(db).module(db), DefWithBodyId::StaticId(it) => it.lookup(db).module(db), DefWithBodyId::ConstId(it) => it.lookup(db).module(db), + DefWithBodyId::VariantId(it) => it.parent.lookup(db).container, } } } @@ -691,6 +701,7 @@ impl DefWithBodyId { DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(), DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(), DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(), + DefWithBodyId::VariantId(it) => it.parent.lookup(db).id.value.into(), } } } diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 8aa5973cac57..070f6837133a 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -839,6 +839,7 @@ impl HasResolver for DefWithBodyId { DefWithBodyId::ConstId(c) => c.resolver(db), DefWithBodyId::FunctionId(f) => f.resolver(db), DefWithBodyId::StaticId(s) => s.resolver(db), + DefWithBodyId::VariantId(v) => v.parent.resolver(db), } } } diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 6ecb6e6fd173..e934fe1c3234 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -11,7 +11,7 @@ use hir_def::{ path::ModPath, resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs}, type_ref::ConstScalar, - ConstId, DefWithBodyId, + ConstId, DefWithBodyId, EnumVariantId, }; use la_arena::{Arena, Idx}; use stdx::never; @@ -339,6 +339,7 @@ pub fn eval_const( ValueNs::GenericParam(_) => { Err(ConstEvalError::NotSupported("const generic without substitution")) } + ValueNs::EnumVariantId(id) => ctx.db.const_eval_variant(id), // TODO(ole): Assuming this is all that has to happen? _ => Err(ConstEvalError::NotSupported("path that are not const or local")), } } @@ -412,6 +413,14 @@ pub(crate) fn const_eval_recover( Err(ConstEvalError::Loop) } +pub(crate) fn const_eval_recover_variant( + _: &dyn HirDatabase, + _: &[String], + _: &EnumVariantId, +) -> Result { + Err(ConstEvalError::Loop) +} + pub(crate) fn const_eval_query( db: &dyn HirDatabase, const_id: ConstId, @@ -433,6 +442,26 @@ pub(crate) fn const_eval_query( result } +pub(crate) fn const_eval_query_variant( + db: &dyn HirDatabase, + variant_id: EnumVariantId, +) -> Result { + let def = variant_id.into(); + let body = db.body(def); + let infer = &db.infer(def); + eval_const( + body.body_expr, + &mut ConstEvalCtx { + db, + owner: def, + exprs: &body.exprs, + pats: &body.pats, + local_data: HashMap::default(), + infer, + }, + ) +} + pub(crate) fn eval_to_const<'a>( expr: Idx, mode: ParamLoweringMode, diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index dd5639f00d21..79c5c01ec65f 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -6,8 +6,9 @@ use std::sync::Arc; use arrayvec::ArrayVec; use base_db::{impl_intern_key, salsa, CrateId, Upcast}; use hir_def::{ - db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, FunctionId, - GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId, + db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, + FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, Lookup, TypeOrConstParamId, + VariantId, }; use la_arena::ArenaMap; @@ -47,6 +48,10 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::cycle(crate::consteval::const_eval_recover)] fn const_eval(&self, def: ConstId) -> Result; + #[salsa::invoke(crate::consteval::const_eval_query_variant)] + #[salsa::cycle(crate::consteval::const_eval_recover_variant)] + fn const_eval_variant(&self, def: EnumVariantId) -> Result; + #[salsa::invoke(crate::lower::impl_trait_query)] fn impl_trait(&self, def: ImplId) -> Option>; @@ -188,6 +193,13 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc DefWithBodyId::ConstId(it) => { db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string() } + DefWithBodyId::VariantId(it) => { + let up_db: &dyn DefDatabase = db.upcast(); + let loc = it.parent.lookup(up_db); + let item_tree = loc.id.item_tree(up_db); + let konst = &item_tree[loc.id.value]; + konst.name.to_string() + } }); db.infer_query(def) } diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index 161b19a739ce..431ab949b462 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -18,7 +18,9 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec { let is_unsafe = match def { DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(), - DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, + DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) | DefWithBodyId::VariantId(_) => { + false + } }; if is_unsafe { return res; diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index e37763e8ea7f..63d0f1b01cf0 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -67,6 +67,14 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc ctx.collect_const(&db.const_data(c)), DefWithBodyId::FunctionId(f) => ctx.collect_fn(f), DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)), + DefWithBodyId::VariantId(v) => { + //let def = AttrDefId::EnumVariantId(v); + //let attrs = db.attrs(def); + //let repr = attrs.by_key("repr").attrs().next().unwrap(); + //let ident = repr.single_ident_value().unwrap().text; + // TODO(ole): Get the real type + ctx.return_ty = TyBuilder::def_ty(db, v.parent.into()).fill_with_unknown().build() + } } ctx.infer_body(); diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index d2f13e4351c7..be5ece9c5c50 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -16,7 +16,7 @@ use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt}; use expect_test::Expect; use hir_def::{ body::{Body, BodySourceMap, SyntheticSyntax}, - db::DefDatabase, + db::{DefDatabase, InternDatabase}, expr::{ExprId, PatId}, item_scope::ItemScope, nameres::DefMap, @@ -135,6 +135,10 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour let loc = it.lookup(&db); loc.source(&db).value.syntax().text_range().start() } + DefWithBodyId::VariantId(it) => { + let loc = db.lookup_intern_enum(it.parent); + loc.source(&db).value.syntax().text_range().start() + } }); let mut unexpected_type_mismatches = String::new(); for def in defs { @@ -388,6 +392,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let loc = it.lookup(&db); loc.source(&db).value.syntax().text_range().start() } + DefWithBodyId::VariantId(it) => { + let loc = db.lookup_intern_enum(it.parent); + loc.source(&db).value.syntax().text_range().start() + } }); for def in defs { let (_body, source_map) = db.body_with_source_map(def); diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index 9c7558d19187..f825a72c0f58 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs @@ -140,6 +140,7 @@ impl From for DefWithBodyId { DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id), DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id), DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id), + DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()), } } } @@ -150,6 +151,7 @@ impl From for DefWithBody { DefWithBodyId::FunctionId(it) => DefWithBody::Function(it.into()), DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()), DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()), + DefWithBodyId::VariantId(it) => DefWithBody::Variant(it.into()), } } } @@ -172,9 +174,7 @@ impl From for GenericDefId { GenericDef::Trait(it) => GenericDefId::TraitId(it.id), GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id), GenericDef::Impl(it) => GenericDefId::ImplId(it.id), - GenericDef::Variant(it) => { - GenericDefId::EnumVariantId(EnumVariantId { parent: it.parent.id, local_id: it.id }) - } + GenericDef::Variant(it) => GenericDefId::EnumVariantId(it.into()), GenericDef::Const(it) => GenericDefId::ConstId(it.id), } } @@ -188,9 +188,7 @@ impl From for GenericDef { GenericDefId::TraitId(it) => GenericDef::Trait(it.into()), GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()), GenericDefId::ImplId(it) => GenericDef::Impl(it.into()), - GenericDefId::EnumVariantId(it) => { - GenericDef::Variant(Variant { parent: it.parent.into(), id: it.local_id }) - } + GenericDefId::EnumVariantId(it) => GenericDef::Variant(it.into()), GenericDefId::ConstId(it) => GenericDef::Const(it.into()), } } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 7dd891c86e8d..258224a7584a 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -73,7 +73,7 @@ use once_cell::unsync::Lazy; use rustc_hash::FxHashSet; use stdx::{impl_from, never}; use syntax::{ - ast::{self, HasAttrs as _, HasDocComments, HasName}, + ast::{self, Expr, HasAttrs as _, HasDocComments, HasName}, AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T, }; @@ -962,11 +962,16 @@ impl HasVisibility for Enum { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Variant { - pub(crate) parent: Enum, - pub(crate) id: LocalEnumVariantId, + pub parent: Enum, + pub id: LocalEnumVariantId, } impl Variant { + pub fn value(self, db: &dyn HirDatabase) -> Option { + // TODO(ole): Handle missing exprs (+1 to the prev) + self.source(db)?.value.expr() + } + pub fn module(self, db: &dyn HirDatabase) -> Module { self.parent.module(db) } @@ -1129,6 +1134,7 @@ pub enum DefWithBody { Function(Function), Static(Static), Const(Const), + Variant(Variant), } impl_from!(Function, Const, Static for DefWithBody); @@ -1138,6 +1144,7 @@ impl DefWithBody { DefWithBody::Const(c) => c.module(db), DefWithBody::Function(f) => f.module(db), DefWithBody::Static(s) => s.module(db), + DefWithBody::Variant(v) => v.module(db), } } @@ -1146,6 +1153,7 @@ impl DefWithBody { DefWithBody::Function(f) => Some(f.name(db)), DefWithBody::Static(s) => Some(s.name(db)), DefWithBody::Const(c) => c.name(db), + DefWithBody::Variant(v) => Some(v.name(db)), } } @@ -1155,6 +1163,7 @@ impl DefWithBody { DefWithBody::Function(it) => it.ret_type(db), DefWithBody::Static(it) => it.ty(db), DefWithBody::Const(it) => it.ty(db), + DefWithBody::Variant(it) => it.parent.ty(db), } } @@ -1379,6 +1388,7 @@ impl DefWithBody { DefWithBody::Function(it) => it.into(), DefWithBody::Static(it) => it.into(), DefWithBody::Const(it) => it.into(), + DefWithBody::Variant(it) => it.into(), }; for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) { acc.push(diag.into()) diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index 616a406c7275..8432f0e7e013 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -1,6 +1,7 @@ //! File symbol extraction. use base_db::FileRange; +use hir_def::db::DefDatabase; use hir_def::{ item_tree::ItemTreeNode, src::HasSource, AdtId, AssocItemId, AssocItemLoc, DefWithBodyId, HasModule, ImplId, ItemContainerId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, @@ -244,6 +245,10 @@ impl<'a> SymbolCollector<'a> { DefWithBodyId::ConstId(id) => Some( id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(), ), + DefWithBodyId::VariantId(id) => Some({ + let up_db: &dyn DefDatabase = self.db.upcast(); + up_db.lookup_intern_enum(id.parent).source(up_db).value.name()?.text().into() + }), } } diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 7deffe8e0f63..20ab474e8027 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -236,6 +236,7 @@ impl Definition { DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), }; return match def { Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)), diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index c5c50d88dd28..cd63131e7a73 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -2,7 +2,9 @@ use std::fmt::Display; use either::Either; -use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo}; +use hir::{ + db::HirDatabase, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo, +}; use ide_db::{ base_db::SourceDatabase, defs::Definition, @@ -346,7 +348,14 @@ pub(super) fn definition( Definition::Module(it) => label_and_docs(db, it), Definition::Function(it) => label_and_docs(db, it), Definition::Adt(it) => label_and_docs(db, it), - Definition::Variant(it) => label_and_docs(db, it), + Definition::Variant(it) => label_value_and_docs(db, it, |&it| { + let hir_db: &dyn HirDatabase = db; + let body = hir_db.const_eval_variant(it.into()); + match body { + Ok(x) => Some(format!("{}", x)), + Err(_) => it.value(db).map(|s| format!("{}", s)), + } + }), Definition::Const(it) => label_value_and_docs(db, it, |it| { let body = it.eval(db); match body { diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 4b8b47783d12..f24dec25b6b9 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -3527,6 +3527,86 @@ impl Foo {} ); } +#[test] +fn hover_const_eval_variant() { + // show hex for <10 + check( + r#" +#[repr(u8)] +enum E { + /// This is a doc + A$0 = 1 << 3, +} +"#, + expect![[r#" + *A* + + ```rust + test::E + ``` + + ```rust + A = 8 + ``` + + --- + + This is a doc + "#]], + ); + // show hex for >10 + check( + r#" +#[repr(u8)] +enum E { + /// This is a doc + A$0 = (1 << 3) + (1 << 2), +} +"#, + expect![[r#" + *A* + + ```rust + test::E + ``` + + ```rust + A = 12 (0xC) + ``` + + --- + + This is a doc + "#]], + ); + // enums in const eval + check( + r#" +#[repr(u8)] +enum E { + A = 1, + /// This is a doc + B$0 = E::A + 1, +} +"#, + expect![[r#" + *B* + + ```rust + test::E + ``` + + ```rust + B = 2 + ``` + + --- + + This is a doc + "#]], + ); +} + #[test] fn hover_const_eval() { // show hex for <10 @@ -3820,6 +3900,35 @@ fn foo() { --- + This is a doc + "#]], + ); + check( + r#" +enum E { + /// This is a doc + A = 3, +} +fn foo(e: E) { + match e { + E::A$0 => (), + _ => () + } +} +"#, + expect![[r#" + *A* + + ```rust + test::E + ``` + + ```rust + A = 3 + ``` + + --- + This is a doc "#]], ); From e28046c673178361d39b7f6dafd6915767f2d71f Mon Sep 17 00:00:00 2001 From: OleStrohm Date: Sat, 6 Aug 2022 18:52:35 +0200 Subject: [PATCH 007/175] Removed unnecessary TODO --- crates/hir-ty/src/consteval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index e934fe1c3234..b47d7308941f 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -339,7 +339,7 @@ pub fn eval_const( ValueNs::GenericParam(_) => { Err(ConstEvalError::NotSupported("const generic without substitution")) } - ValueNs::EnumVariantId(id) => ctx.db.const_eval_variant(id), // TODO(ole): Assuming this is all that has to happen? + ValueNs::EnumVariantId(id) => ctx.db.const_eval_variant(id), _ => Err(ConstEvalError::NotSupported("path that are not const or local")), } } From b63234e20be04ae0e7eca20e0bf49dca8d7d3718 Mon Sep 17 00:00:00 2001 From: OleStrohm Date: Sat, 6 Aug 2022 19:12:57 +0200 Subject: [PATCH 008/175] Cleaned up code --- crates/hir-ty/src/infer.rs | 6 +----- crates/hir/src/lib.rs | 14 +++++++++----- crates/hir/src/symbols.rs | 5 ++--- crates/ide/src/hover/render.rs | 5 ++--- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 63d0f1b01cf0..c821a3786b9f 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -26,7 +26,7 @@ use hir_def::{ resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, type_ref::TypeRef, AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup, - TraitId, TypeAliasId, VariantId, + TraitId, TypeAliasId, VariantId }; use hir_expand::name::{name, Name}; use itertools::Either; @@ -68,10 +68,6 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc ctx.collect_fn(f), DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)), DefWithBodyId::VariantId(v) => { - //let def = AttrDefId::EnumVariantId(v); - //let attrs = db.attrs(def); - //let repr = attrs.by_key("repr").attrs().next().unwrap(); - //let ident = repr.single_ident_value().unwrap().text; // TODO(ole): Get the real type ctx.return_ty = TyBuilder::def_ty(db, v.parent.into()).fill_with_unknown().build() } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 258224a7584a..1b06dbd90850 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -967,11 +967,6 @@ pub struct Variant { } impl Variant { - pub fn value(self, db: &dyn HirDatabase) -> Option { - // TODO(ole): Handle missing exprs (+1 to the prev) - self.source(db)?.value.expr() - } - pub fn module(self, db: &dyn HirDatabase) -> Module { self.parent.module(db) } @@ -999,6 +994,15 @@ impl Variant { pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc { db.enum_data(self.parent.id).variants[self.id].variant_data.clone() } + + pub fn value(self, db: &dyn HirDatabase) -> Option { + // TODO(ole): Handle missing exprs (+1 to the prev) + self.source(db)?.value.expr() + } + + pub fn eval(self, db: &dyn HirDatabase) -> Result { + db.const_eval_variant(self.into()) + } } /// Variants inherit visibility from the parent enum. diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index 8432f0e7e013..fd78decda4e6 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -1,7 +1,6 @@ //! File symbol extraction. use base_db::FileRange; -use hir_def::db::DefDatabase; use hir_def::{ item_tree::ItemTreeNode, src::HasSource, AdtId, AssocItemId, AssocItemLoc, DefWithBodyId, HasModule, ImplId, ItemContainerId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, @@ -246,8 +245,8 @@ impl<'a> SymbolCollector<'a> { id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(), ), DefWithBodyId::VariantId(id) => Some({ - let up_db: &dyn DefDatabase = self.db.upcast(); - up_db.lookup_intern_enum(id.parent).source(up_db).value.name()?.text().into() + let db = self.db.upcast(); + id.parent.lookup(db).source(db).value.name()?.text().into() }), } } diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index cd63131e7a73..8ac268f24382 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -349,11 +349,10 @@ pub(super) fn definition( Definition::Function(it) => label_and_docs(db, it), Definition::Adt(it) => label_and_docs(db, it), Definition::Variant(it) => label_value_and_docs(db, it, |&it| { - let hir_db: &dyn HirDatabase = db; - let body = hir_db.const_eval_variant(it.into()); + let body = it.eval(db); match body { Ok(x) => Some(format!("{}", x)), - Err(_) => it.value(db).map(|s| format!("{}", s)), + Err(_) => it.value(db).map(|x| format!("{}", x)), } }), Definition::Const(it) => label_value_and_docs(db, it, |it| { From 2f84b6e2e51442755dfd9c8ae5cc5eb9020e52cb Mon Sep 17 00:00:00 2001 From: OleStrohm Date: Sat, 6 Aug 2022 22:12:33 +0200 Subject: [PATCH 009/175] Almost there --- crates/hir-def/src/body.rs | 4 +- crates/hir-ty/src/consteval.rs | 89 ++++++++++++++++++++++++++++++---- crates/hir-ty/src/infer.rs | 3 +- crates/ide/src/hover/render.rs | 14 +++--- crates/ide/src/hover/tests.rs | 53 +++++++++++++++++++- 5 files changed, 141 insertions(+), 22 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 484e2d7d7ddb..be1a9d11773d 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -28,8 +28,8 @@ use crate::{ nameres::DefMap, path::{ModPath, Path}, src::{HasChildSource, HasSource}, - AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId, - UnresolvedMacro, + AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, + ModuleId, UnresolvedMacro, }; pub use lower::LowerCtx; diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index b47d7308941f..efb17c4780ae 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -7,14 +7,17 @@ use std::{ use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData, IntTy, Scalar}; use hir_def::{ + builtin_type::BuiltinInt, expr::{ArithOp, BinaryOp, Expr, ExprId, Literal, Pat, PatId}, path::ModPath, resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs}, + src::HasChildSource, type_ref::ConstScalar, - ConstId, DefWithBodyId, EnumVariantId, + ConstId, DefWithBodyId, EnumVariantId, Lookup, }; -use la_arena::{Arena, Idx}; +use la_arena::{Arena, Idx, RawIdx}; use stdx::never; +use syntax::ast::HasName; use crate::{ db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx, @@ -77,6 +80,7 @@ pub enum ConstEvalError { #[derive(Debug, Clone, PartialEq, Eq)] pub enum ComputedExpr { Literal(Literal), + Enum(String, EnumVariantId, Literal), Tuple(Box<[ComputedExpr]>), } @@ -104,6 +108,7 @@ impl Display for ComputedExpr { Literal::String(x) => std::fmt::Debug::fmt(x, f), Literal::ByteString(x) => std::fmt::Debug::fmt(x, f), }, + ComputedExpr::Enum(name, _, _) => name.fmt(f), ComputedExpr::Tuple(t) => { f.write_char('(')?; for x in &**t { @@ -116,6 +121,15 @@ impl Display for ComputedExpr { } } +impl ComputedExpr { + pub fn enum_value(&self) -> Option { + match self { + ComputedExpr::Enum(_, _, lit) => Some(ComputedExpr::Literal(lit.clone())), + _ => None, + } + } +} + fn scalar_max(scalar: &Scalar) -> i128 { match scalar { Scalar::Bool => 1, @@ -148,17 +162,56 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool { } } +fn get_name(variant: EnumVariantId, ctx: &mut ConstEvalCtx<'_>) -> String { + let loc = variant.parent.lookup(ctx.db.upcast()); + let children = variant.parent.child_source(ctx.db.upcast()); + let item_tree = loc.id.item_tree(ctx.db.upcast()); + + let variant_name = children.value[variant.local_id].name(); + let enum_name = item_tree[loc.id.value].name.to_string(); + enum_name + "::" + &variant_name.unwrap().to_string() +} + pub fn eval_const( expr_id: ExprId, ctx: &mut ConstEvalCtx<'_>, + variant: Option, ) -> Result { let expr = &ctx.exprs[expr_id]; match expr { - Expr::Missing => Err(ConstEvalError::IncompleteExpr), + Expr::Missing => match variant { + Some(variant) => { + let prev_idx: u32 = variant.local_id.into_raw().into(); + let prev_idx = prev_idx.checked_sub(1).map(|idx| Idx::from_raw(RawIdx::from(idx))); + let value = match prev_idx { + Some(prev) => { + let prev_variant = EnumVariantId { local_id: prev, ..variant }; + 1 + match ctx.db.const_eval_variant(prev_variant)? { + ComputedExpr::Literal(Literal::Int(v, _)) => v, + ComputedExpr::Literal(Literal::Uint(v, _)) => v + .try_into() + .map_err(|_| ConstEvalError::NotSupported("too big u128"))?, + _ => { + return Err(ConstEvalError::NotSupported( + "Enum can't contain this kind of value", + )) + } + } + } + _ => 0, + }; + Ok(ComputedExpr::Enum( + get_name(variant, ctx), + variant, + Literal::Int(value + 1, Some(BuiltinInt::I128)), + )) + } + _ => Err(ConstEvalError::IncompleteExpr), + }, Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())), &Expr::UnaryOp { expr, op } => { let ty = &ctx.expr_ty(expr); - let ev = eval_const(expr, ctx)?; + let ev = eval_const(expr, ctx, None)?; match op { hir_def::expr::UnaryOp::Deref => Err(ConstEvalError::NotSupported("deref")), hir_def::expr::UnaryOp::Not => { @@ -214,8 +267,8 @@ pub fn eval_const( } &Expr::BinaryOp { lhs, rhs, op } => { let ty = &ctx.expr_ty(lhs); - let lhs = eval_const(lhs, ctx)?; - let rhs = eval_const(rhs, ctx)?; + let lhs = eval_const(lhs, ctx, None)?; + let rhs = eval_const(rhs, ctx, None)?; let op = op.ok_or(ConstEvalError::IncompleteExpr)?; let v1 = match lhs { ComputedExpr::Literal(Literal::Int(v, _)) => v, @@ -276,7 +329,7 @@ pub fn eval_const( } }; let value = match initializer { - Some(x) => eval_const(x, ctx)?, + Some(x) => eval_const(x, ctx, None)?, None => continue, }; if !prev_values.contains_key(&pat_id) { @@ -292,7 +345,7 @@ pub fn eval_const( } } let r = match tail { - &Some(x) => eval_const(x, ctx), + &Some(x) => eval_const(x, ctx, None), None => Ok(ComputedExpr::Tuple(Box::new([]))), }; // clean up local data, so caller will receive the exact map that passed to us @@ -339,10 +392,24 @@ pub fn eval_const( ValueNs::GenericParam(_) => { Err(ConstEvalError::NotSupported("const generic without substitution")) } - ValueNs::EnumVariantId(id) => ctx.db.const_eval_variant(id), + ValueNs::EnumVariantId(id) => match ctx.db.const_eval_variant(id)? { + ComputedExpr::Literal(lit) => { + Ok(ComputedExpr::Enum(get_name(id, ctx), id, lit)) + } + _ => Err(ConstEvalError::NotSupported( + "Enums can't evalute to anything but numbers", + )), + }, _ => Err(ConstEvalError::NotSupported("path that are not const or local")), } } + Expr::Cast { expr, .. } => match eval_const(*expr, ctx, None)? { + ComputedExpr::Enum(_, _, lit) => Ok(ComputedExpr::Literal(lit)), + expr => Err(ConstEvalError::NotSupported(Box::leak(Box::new(format!( + "Can't cast type: {:?}", + expr + ))))), + }, _ => Err(ConstEvalError::NotSupported("This kind of expression")), } } @@ -438,6 +505,7 @@ pub(crate) fn const_eval_query( local_data: HashMap::default(), infer, }, + None, ); result } @@ -459,6 +527,7 @@ pub(crate) fn const_eval_query_variant( local_data: HashMap::default(), infer, }, + Some(variant_id), ) } @@ -485,7 +554,7 @@ pub(crate) fn eval_to_const<'a>( local_data: HashMap::default(), infer: &ctx.result, }; - let computed_expr = eval_const(expr, &mut ctx); + let computed_expr = eval_const(expr, &mut ctx, None); let const_scalar = match computed_expr { Ok(ComputedExpr::Literal(literal)) => literal.into(), _ => ConstScalar::Unknown, diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index c821a3786b9f..285ec7520f40 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -26,7 +26,7 @@ use hir_def::{ resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, type_ref::TypeRef, AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup, - TraitId, TypeAliasId, VariantId + TraitId, TypeAliasId, VariantId, }; use hir_expand::name::{name, Name}; use itertools::Either; @@ -68,7 +68,6 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc ctx.collect_fn(f), DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)), DefWithBodyId::VariantId(v) => { - // TODO(ole): Get the real type ctx.return_ty = TyBuilder::def_ty(db, v.parent.into()).fill_with_unknown().build() } } diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 8ac268f24382..44291a1a88b9 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use either::Either; use hir::{ - db::HirDatabase, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo, + db::HirDatabase, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, StructKind, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, @@ -348,12 +348,12 @@ pub(super) fn definition( Definition::Module(it) => label_and_docs(db, it), Definition::Function(it) => label_and_docs(db, it), Definition::Adt(it) => label_and_docs(db, it), - Definition::Variant(it) => label_value_and_docs(db, it, |&it| { - let body = it.eval(db); - match body { - Ok(x) => Some(format!("{}", x)), - Err(_) => it.value(db).map(|x| format!("{}", x)), - } + Definition::Variant(it) => label_value_and_docs(db, it, |&it| match it.kind(db) { + StructKind::Unit => match it.eval(db) { + Ok(x) => Some(format!("{}", x.enum_value().unwrap_or(x))), + Err(_) => it.value(db).map(|x| format!("{:?}", x)), + }, + _ => None, }), Definition::Const(it) => label_value_and_docs(db, it, |it| { let body = it.eval(db); diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index f24dec25b6b9..b877e6e5c9fd 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -3529,6 +3529,31 @@ impl Foo {} #[test] fn hover_const_eval_variant() { + check( + r#" +#[repr(u8)] +enum E { + A = 4, + /// This is a doc + B$0 = E::A as u8 + 1, +} +"#, + expect![[r#" + *B* + + ```rust + test::E + ``` + + ```rust + B = 5 + ``` + + --- + + This is a doc + "#]], + ); // show hex for <10 check( r#" @@ -3586,7 +3611,7 @@ enum E { enum E { A = 1, /// This is a doc - B$0 = E::A + 1, + B$0 = E::A as u8 + 1, } "#, expect![[r#" @@ -3602,6 +3627,32 @@ enum E { --- + This is a doc + "#]], + ); + // unspecified variant should increment by one + check( + r#" +#[repr(u8)] +enum E { + A = 4, + /// This is a doc + B$0, +} +"#, + expect![[r#" + *B* + + ```rust + test::E + ``` + + ```rust + B = 5 + ``` + + --- + This is a doc "#]], ); From ad0a6bf1a3eda25698e9ce5cea0743c2cdf9f051 Mon Sep 17 00:00:00 2001 From: OleStrohm Date: Sun, 7 Aug 2022 18:22:18 +0200 Subject: [PATCH 010/175] Added consteval tests --- crates/hir-def/src/body.rs | 5 ++--- crates/hir-ty/src/consteval.rs | 2 +- crates/hir-ty/src/consteval/tests.rs | 29 ++++++++++++++++++++++++++++ crates/hir/src/lib.rs | 5 ++++- crates/ide/src/hover/render.rs | 15 ++++++++------ crates/ide/src/hover/tests.rs | 1 + 6 files changed, 46 insertions(+), 11 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index be1a9d11773d..2dc7714bbb54 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -28,8 +28,8 @@ use crate::{ nameres::DefMap, path::{ModPath, Path}, src::{HasChildSource, HasSource}, - AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, - ModuleId, UnresolvedMacro, + AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId, + UnresolvedMacro, }; pub use lower::LowerCtx; @@ -328,7 +328,6 @@ impl Body { let e = v.parent.lookup(db); let src = v.parent.child_source(db); let variant = &src.value[v.local_id]; - // TODO(ole): Handle missing exprs (+1 to the prev) (src.file_id, e.container, variant.expr()) } }; diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index efb17c4780ae..141652db73a7 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -203,7 +203,7 @@ pub fn eval_const( Ok(ComputedExpr::Enum( get_name(variant, ctx), variant, - Literal::Int(value + 1, Some(BuiltinInt::I128)), + Literal::Int(value, Some(BuiltinInt::I128)), )) } _ => Err(ConstEvalError::IncompleteExpr), diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 4a052851afd1..357d43d22531 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -87,6 +87,35 @@ fn consts() { ); } +#[test] +fn enums() { + check_number( + r#" + enum E { + F1 = 1, + F2 = 2 * E::F1 as u8, + F3 = 3 * E::F2 as u8, + } + const GOAL: i32 = E::F3 as u8; + "#, + 6, + ); + let r = eval_goal( + r#" + enum E { A = 1, } + const GOAL: E = E::A; + "#, + ) + .unwrap(); + match r { + ComputedExpr::Enum(name, _, Literal::Uint(val, _)) => { + assert_eq!(name, "E::A"); + assert_eq!(val, 1); + } + x => panic!("Expected enum but found {:?}", x), + } +} + #[test] fn const_loop() { check_fail( diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 1b06dbd90850..b656eaa74cad 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -952,6 +952,10 @@ impl Enum { pub fn ty(self, db: &dyn HirDatabase) -> Type { Type::from_def(db, self.id) } + + pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool { + self.variants(db).iter().all(|v| matches!(v.kind(db), StructKind::Unit)) + } } impl HasVisibility for Enum { @@ -996,7 +1000,6 @@ impl Variant { } pub fn value(self, db: &dyn HirDatabase) -> Option { - // TODO(ole): Handle missing exprs (+1 to the prev) self.source(db)?.value.expr() } diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 44291a1a88b9..486739628f2a 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -348,12 +348,15 @@ pub(super) fn definition( Definition::Module(it) => label_and_docs(db, it), Definition::Function(it) => label_and_docs(db, it), Definition::Adt(it) => label_and_docs(db, it), - Definition::Variant(it) => label_value_and_docs(db, it, |&it| match it.kind(db) { - StructKind::Unit => match it.eval(db) { - Ok(x) => Some(format!("{}", x.enum_value().unwrap_or(x))), - Err(_) => it.value(db).map(|x| format!("{:?}", x)), - }, - _ => None, + Definition::Variant(it) => label_value_and_docs(db, it, |&it| { + if it.parent.is_data_carrying(db) { + match it.eval(db) { + Ok(x) => Some(format!("{}", x.enum_value().unwrap_or(x))), + Err(_) => it.value(db).map(|x| format!("{:?}", x)), + } + } else { + None + } }), Definition::Const(it) => label_value_and_docs(db, it, |it| { let body = it.eval(db); diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index b877e6e5c9fd..362b9fa815d3 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -698,6 +698,7 @@ fn hover_enum_variant() { check( r#" enum Option { + Some(T) /// The None variant Non$0e } From 301b8894ead191cb33e8aa72ce74f51332fee274 Mon Sep 17 00:00:00 2001 From: OleStrohm Date: Sun, 7 Aug 2022 18:42:59 +0200 Subject: [PATCH 011/175] Added more consteval tests and fixed consteval result --- crates/hir-ty/src/consteval.rs | 22 +++------------------- crates/hir-ty/src/consteval/tests.rs | 14 ++++++++++++++ crates/ide/src/hover/render.rs | 2 +- crates/ide/src/hover/tests.rs | 25 ------------------------- 4 files changed, 18 insertions(+), 45 deletions(-) diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 141652db73a7..11d93d19c3cf 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -121,15 +121,6 @@ impl Display for ComputedExpr { } } -impl ComputedExpr { - pub fn enum_value(&self) -> Option { - match self { - ComputedExpr::Enum(_, _, lit) => Some(ComputedExpr::Literal(lit.clone())), - _ => None, - } - } -} - fn scalar_max(scalar: &Scalar) -> i128 { match scalar { Scalar::Bool => 1, @@ -200,11 +191,7 @@ pub fn eval_const( } _ => 0, }; - Ok(ComputedExpr::Enum( - get_name(variant, ctx), - variant, - Literal::Int(value, Some(BuiltinInt::I128)), - )) + Ok(ComputedExpr::Literal(Literal::Int(value, Some(BuiltinInt::I128)))) } _ => Err(ConstEvalError::IncompleteExpr), }, @@ -403,12 +390,9 @@ pub fn eval_const( _ => Err(ConstEvalError::NotSupported("path that are not const or local")), } } - Expr::Cast { expr, .. } => match eval_const(*expr, ctx, None)? { + &Expr::Cast { expr, .. } => match eval_const(expr, ctx, None)? { ComputedExpr::Enum(_, _, lit) => Ok(ComputedExpr::Literal(lit)), - expr => Err(ConstEvalError::NotSupported(Box::leak(Box::new(format!( - "Can't cast type: {:?}", - expr - ))))), + _ => Err(ConstEvalError::NotSupported("Can't cast these types")), }, _ => Err(ConstEvalError::NotSupported("This kind of expression")), } diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 357d43d22531..b76506f6ebc2 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -100,6 +100,20 @@ fn enums() { "#, 6, ); + check_number( + r#" + enum E { F1 = 1, F2, } + const GOAL: i32 = E::F2 as u8; + "#, + 2, + ); + check_number( + r#" + enum E { F1, } + const GOAL: i32 = E::F1 as u8; + "#, + 0, + ); let r = eval_goal( r#" enum E { A = 1, } diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 486739628f2a..f7cdc9e5b2fd 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -351,7 +351,7 @@ pub(super) fn definition( Definition::Variant(it) => label_value_and_docs(db, it, |&it| { if it.parent.is_data_carrying(db) { match it.eval(db) { - Ok(x) => Some(format!("{}", x.enum_value().unwrap_or(x))), + Ok(x) => Some(format!("{}", x)), Err(_) => it.value(db).map(|x| format!("{:?}", x)), } } else { diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 362b9fa815d3..eb997e6fef83 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -3530,31 +3530,6 @@ impl Foo {} #[test] fn hover_const_eval_variant() { - check( - r#" -#[repr(u8)] -enum E { - A = 4, - /// This is a doc - B$0 = E::A as u8 + 1, -} -"#, - expect![[r#" - *B* - - ```rust - test::E - ``` - - ```rust - B = 5 - ``` - - --- - - This is a doc - "#]], - ); // show hex for <10 check( r#" From 5313bd19844d6e485c16b06b60a12dc36449688c Mon Sep 17 00:00:00 2001 From: OleStrohm Date: Mon, 12 Sep 2022 18:45:51 +0100 Subject: [PATCH 012/175] Cleaned up code based on feedback --- crates/hir-ty/src/consteval.rs | 21 +++++++++------------ crates/hir/src/lib.rs | 6 +++--- crates/ide/src/hover/render.rs | 2 +- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 11d93d19c3cf..965bf3f2c5b8 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -166,12 +166,11 @@ fn get_name(variant: EnumVariantId, ctx: &mut ConstEvalCtx<'_>) -> String { pub fn eval_const( expr_id: ExprId, ctx: &mut ConstEvalCtx<'_>, - variant: Option, ) -> Result { let expr = &ctx.exprs[expr_id]; match expr { - Expr::Missing => match variant { - Some(variant) => { + Expr::Missing => match ctx.owner { + DefWithBodyId::VariantId(variant) => { let prev_idx: u32 = variant.local_id.into_raw().into(); let prev_idx = prev_idx.checked_sub(1).map(|idx| Idx::from_raw(RawIdx::from(idx))); let value = match prev_idx { @@ -198,7 +197,7 @@ pub fn eval_const( Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())), &Expr::UnaryOp { expr, op } => { let ty = &ctx.expr_ty(expr); - let ev = eval_const(expr, ctx, None)?; + let ev = eval_const(expr, ctx)?; match op { hir_def::expr::UnaryOp::Deref => Err(ConstEvalError::NotSupported("deref")), hir_def::expr::UnaryOp::Not => { @@ -254,8 +253,8 @@ pub fn eval_const( } &Expr::BinaryOp { lhs, rhs, op } => { let ty = &ctx.expr_ty(lhs); - let lhs = eval_const(lhs, ctx, None)?; - let rhs = eval_const(rhs, ctx, None)?; + let lhs = eval_const(lhs, ctx)?; + let rhs = eval_const(rhs, ctx)?; let op = op.ok_or(ConstEvalError::IncompleteExpr)?; let v1 = match lhs { ComputedExpr::Literal(Literal::Int(v, _)) => v, @@ -316,7 +315,7 @@ pub fn eval_const( } }; let value = match initializer { - Some(x) => eval_const(x, ctx, None)?, + Some(x) => eval_const(x, ctx)?, None => continue, }; if !prev_values.contains_key(&pat_id) { @@ -332,7 +331,7 @@ pub fn eval_const( } } let r = match tail { - &Some(x) => eval_const(x, ctx, None), + &Some(x) => eval_const(x, ctx), None => Ok(ComputedExpr::Tuple(Box::new([]))), }; // clean up local data, so caller will receive the exact map that passed to us @@ -390,7 +389,7 @@ pub fn eval_const( _ => Err(ConstEvalError::NotSupported("path that are not const or local")), } } - &Expr::Cast { expr, .. } => match eval_const(expr, ctx, None)? { + &Expr::Cast { expr, .. } => match eval_const(expr, ctx)? { ComputedExpr::Enum(_, _, lit) => Ok(ComputedExpr::Literal(lit)), _ => Err(ConstEvalError::NotSupported("Can't cast these types")), }, @@ -489,7 +488,6 @@ pub(crate) fn const_eval_query( local_data: HashMap::default(), infer, }, - None, ); result } @@ -511,7 +509,6 @@ pub(crate) fn const_eval_query_variant( local_data: HashMap::default(), infer, }, - Some(variant_id), ) } @@ -538,7 +535,7 @@ pub(crate) fn eval_to_const<'a>( local_data: HashMap::default(), infer: &ctx.result, }; - let computed_expr = eval_const(expr, &mut ctx, None); + let computed_expr = eval_const(expr, &mut ctx); let const_scalar = match computed_expr { Ok(ComputedExpr::Literal(literal)) => literal.into(), _ => ConstScalar::Unknown, diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index b656eaa74cad..6bcbe62efa88 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -954,7 +954,7 @@ impl Enum { } pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool { - self.variants(db).iter().all(|v| matches!(v.kind(db), StructKind::Unit)) + self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit)) } } @@ -966,8 +966,8 @@ impl HasVisibility for Enum { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Variant { - pub parent: Enum, - pub id: LocalEnumVariantId, + pub(crate) parent: Enum, + pub(crate) id: LocalEnumVariantId, } impl Variant { diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index f7cdc9e5b2fd..4c429202e6f9 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -349,7 +349,7 @@ pub(super) fn definition( Definition::Function(it) => label_and_docs(db, it), Definition::Adt(it) => label_and_docs(db, it), Definition::Variant(it) => label_value_and_docs(db, it, |&it| { - if it.parent.is_data_carrying(db) { + if !it.parent_enum(db).is_data_carrying(db) { match it.eval(db) { Ok(x) => Some(format!("{}", x)), Err(_) => it.value(db).map(|x| format!("{:?}", x)), From 177ec82a41a3e42814201e0b718764798a76109f Mon Sep 17 00:00:00 2001 From: OleStrohm Date: Mon, 12 Sep 2022 21:02:30 +0100 Subject: [PATCH 013/175] Rebased --- crates/hir-def/src/body/pretty.rs | 12 ++++++++++++ crates/hir/src/lib.rs | 7 +++++++ crates/ide/src/hover/render.rs | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index f2fed954444e..9121fb50fd63 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -2,6 +2,8 @@ use std::fmt::{self, Write}; +use syntax::ast::HasName; + use crate::{ expr::{Array, BindingAnnotation, Literal, Statement}, pretty::{print_generic_args, print_path, print_type_ref}, @@ -32,6 +34,16 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo }; format!("const {} = ", name) } + DefWithBodyId::VariantId(it) => { + needs_semi = false; + let src = it.parent.child_source(db); + let variant = &src.value[it.local_id]; + let name = match &variant.name() { + Some(name) => name.to_string(), + None => "_".to_string(), + }; + format!("{}", name) + } }; let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false }; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 6bcbe62efa88..7d32aef8eb99 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -964,6 +964,12 @@ impl HasVisibility for Enum { } } +impl From<&Variant> for DefWithBodyId { + fn from(&v: &Variant) -> Self { + DefWithBodyId::VariantId(v.into()) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Variant { pub(crate) parent: Enum, @@ -1179,6 +1185,7 @@ impl DefWithBody { DefWithBody::Function(it) => it.id.into(), DefWithBody::Static(it) => it.id.into(), DefWithBody::Const(it) => it.id.into(), + DefWithBody::Variant(it) => it.into(), } } diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 4c429202e6f9..8442e101b6f3 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -3,7 +3,8 @@ use std::fmt::Display; use either::Either; use hir::{ - db::HirDatabase, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, StructKind, TypeInfo, + db::HirDatabase, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, + StructKind, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, From 3931e55aee05b883653aee73659a164fbb60578f Mon Sep 17 00:00:00 2001 From: OleStrohm Date: Mon, 12 Sep 2022 21:27:19 +0100 Subject: [PATCH 014/175] Fixed lints --- crates/ide/src/hover/render.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 8442e101b6f3..d109c0769194 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -2,10 +2,7 @@ use std::fmt::Display; use either::Either; -use hir::{ - db::HirDatabase, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, - StructKind, TypeInfo, -}; +use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo}; use ide_db::{ base_db::SourceDatabase, defs::Definition, From 3d28a1ad761f4106e62e90ceebb209af533a1f24 Mon Sep 17 00:00:00 2001 From: Keenan Gugeler Date: Wed, 14 Sep 2022 13:25:14 -0400 Subject: [PATCH 015/175] Warn about safety of `fetch_update` Specifically as it relates to the ABA problem. --- library/core/src/sync/atomic.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 3c96290fc537..6c70517d965b 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -955,6 +955,14 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// /// # Examples /// /// ```rust @@ -1422,6 +1430,14 @@ impl AtomicPtr { /// **Note:** This method is only available on platforms that support atomic /// operations on pointers. /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// /// # Examples /// /// ```rust @@ -2510,6 +2526,16 @@ macro_rules! atomic_int { /// **Note**: This method is only available on platforms that support atomic operations on #[doc = concat!("[`", $s_int_type, "`].")] /// + /// # Considerations + /// + /// This method is not magic; it is not provided by the hardware. + /// It is implemented in terms of + #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] + /// and suffers from the same drawbacks. + /// In particular, this method will not circumvent the [ABA Problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// /// # Examples /// /// ```rust From ed0cf1c5faa5818dfc4dd4d0b61f50209fd5f280 Mon Sep 17 00:00:00 2001 From: harudagondi Date: Sat, 17 Sep 2022 15:57:45 +0800 Subject: [PATCH 016/175] Add functionality to unwrap tuple declarations --- .../ide-assists/src/handlers/unwrap_tuple.rs | 160 ++++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 19 +++ 3 files changed, 181 insertions(+) create mode 100644 crates/ide-assists/src/handlers/unwrap_tuple.rs diff --git a/crates/ide-assists/src/handlers/unwrap_tuple.rs b/crates/ide-assists/src/handlers/unwrap_tuple.rs new file mode 100644 index 000000000000..171e9214a4e6 --- /dev/null +++ b/crates/ide-assists/src/handlers/unwrap_tuple.rs @@ -0,0 +1,160 @@ +use syntax::{ + ast::{self, edit::AstNodeEdit}, + AstNode, T, +}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: unwrap_tuple +// +// Unwrap the tuple to different variables. +// +// ``` +// # //- minicore: result +// fn main() { +// $0let (foo, bar) = ("Foo", "Bar"); +// } +// ``` +// -> +// ``` +// fn main() { +// let foo = "Foo"; +// let bar = "Bar"; +// } +// ``` +pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let let_kw = ctx.find_token_syntax_at_offset(T![let])?; + let let_stmt = let_kw.parent().and_then(ast::LetStmt::cast)?; + let indent_level = let_stmt.indent_level().0 as usize; + let pat = let_stmt.pat()?; + let ty = let_stmt.ty(); + let init = let_stmt.initializer()?; + + // This only applies for tuple patterns, types, and initializers. + let tuple_pat = match pat { + ast::Pat::TuplePat(pat) => pat, + _ => return None, + }; + let tuple_ty = ty.and_then(|it| match it { + ast::Type::TupleType(ty) => Some(ty), + _ => None, + }); + let tuple_init = match init { + ast::Expr::TupleExpr(expr) => expr, + _ => return None, + }; + + stdx::always!( + tuple_pat.fields().count() == tuple_init.fields().count(), + "Length of tuples in pattern and initializer do not match" + ); + + let parent = let_kw.parent()?; + + acc.add( + AssistId("unwrap_tuple", AssistKind::RefactorRewrite), + "Unwrap tuple", + let_kw.text_range(), + |edit| { + let indents = " ".repeat(indent_level); + + // If there is an ascribed type, insert that type for each declaration, + // otherwise, omit that type. + if let Some(tys) = tuple_ty { + stdx::always!( + tuple_pat.fields().count() == tys.fields().count(), + "Length of tuples in patterns and type do not match" + ); + + let mut zipped_decls = String::new(); + for (pat, ty, expr) in + itertools::izip!(tuple_pat.fields(), tys.fields(), tuple_init.fields()) + { + zipped_decls.push_str(&format!("{}let {pat}: {ty} = {expr};\n", indents)) + } + edit.replace(parent.text_range(), zipped_decls.trim()); + } else { + let mut zipped_decls = String::new(); + for (pat, expr) in itertools::izip!(tuple_pat.fields(), tuple_init.fields()) { + zipped_decls.push_str(&format!("{}let {pat} = {expr};\n", indents)); + } + edit.replace(parent.text_range(), zipped_decls.trim()); + } + }, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::check_assist; + + use super::*; + + #[test] + fn unwrap_tuples() { + check_assist( + unwrap_tuple, + r#" +fn main() { + $0let (foo, bar) = ("Foo", "Bar"); +} +"#, + r#" +fn main() { + let foo = "Foo"; + let bar = "Bar"; +} +"#, + ); + + check_assist( + unwrap_tuple, + r#" +fn main() { + $0let (foo, bar, baz) = ("Foo", "Bar", "Baz"); +} +"#, + r#" +fn main() { + let foo = "Foo"; + let bar = "Bar"; + let baz = "Baz"; +} +"#, + ); + } + + #[test] + fn unwrap_tuple_with_types() { + check_assist( + unwrap_tuple, + r#" +fn main() { + $0let (foo, bar): (u8, i32) = (5, 10); +} +"#, + r#" +fn main() { + let foo: u8 = 5; + let bar: i32 = 10; +} +"#, + ); + + check_assist( + unwrap_tuple, + r#" +fn main() { + $0let (foo, bar, baz): (u8, i32, f64) = (5, 10, 17.5); +} +"#, + r#" +fn main() { + let foo: u8 = 5; + let bar: i32 = 10; + let baz: f64 = 17.5; +} +"#, + ); + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 812d22efbd79..82bcc3dfa5d9 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -189,6 +189,7 @@ mod handlers { mod replace_turbofish_with_explicit_type; mod split_import; mod unmerge_match_arm; + mod unwrap_tuple; mod sort_items; mod toggle_ignore; mod unmerge_use; @@ -291,6 +292,7 @@ mod handlers { unnecessary_async::unnecessary_async, unwrap_block::unwrap_block, unwrap_result_return_type::unwrap_result_return_type, + unwrap_tuple::unwrap_tuple, wrap_return_type_in_result::wrap_return_type_in_result, // These are manually sorted for better priorities. By default, // priority is determined by the size of the target range (smaller diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 3a696635afd2..d403f86c6d8c 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -2386,6 +2386,25 @@ fn foo() -> i32 { 42i32 } ) } +#[test] +fn doctest_unwrap_tuple() { + check_doc_test( + "unwrap_tuple", + r#####" +//- minicore: result +fn main() { + $0let (foo, bar) = ("Foo", "Bar"); +} +"#####, + r#####" +fn main() { + let foo = "Foo"; + let bar = "Bar"; +} +"#####, + ) +} + #[test] fn doctest_wrap_return_type_in_result() { check_doc_test( From d9f570960980a98a1cde705ca38bf957231a53e6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 19 Sep 2022 16:40:43 +0200 Subject: [PATCH 017/175] Simplify feature representation in CargoConfig --- crates/project-model/src/build_scripts.rs | 22 ++--- crates/project-model/src/cargo_workspace.rs | 61 ++++++++------ crates/project-model/src/lib.rs | 4 +- crates/rust-analyzer/src/cargo_target_spec.rs | 82 ++++++++++--------- crates/rust-analyzer/src/config.rs | 30 +++---- 5 files changed, 109 insertions(+), 90 deletions(-) diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index 837ea016193c..32db42f1db75 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -15,7 +15,7 @@ use rustc_hash::FxHashMap; use semver::Version; use serde::Deserialize; -use crate::{cfg_flag::CfgFlag, CargoConfig, CargoWorkspace, Package}; +use crate::{cfg_flag::CfgFlag, CargoConfig, CargoFeatures, CargoWorkspace, Package}; #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct WorkspaceBuildScripts { @@ -49,7 +49,6 @@ impl WorkspaceBuildScripts { let mut cmd = Command::new(toolchain::cargo()); cmd.envs(&config.extra_env); - cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]); // --all-targets includes tests, benches and examples in addition to the @@ -61,15 +60,18 @@ impl WorkspaceBuildScripts { cmd.args(&["--target", target]); } - if config.all_features { - cmd.arg("--all-features"); - } else { - if config.no_default_features { - cmd.arg("--no-default-features"); + match &config.features { + CargoFeatures::All => { + cmd.arg("--all-features"); } - if !config.features.is_empty() { - cmd.arg("--features"); - cmd.arg(config.features.join(" ")); + CargoFeatures::Selected { features, no_default_features } => { + if *no_default_features { + cmd.arg("--no-default-features"); + } + if !features.is_empty() { + cmd.arg("--features"); + cmd.arg(features.join(" ")); + } } } diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index 736d80041bd5..8e50fe878ae3 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -71,35 +71,41 @@ impl Default for UnsetTestCrates { } } +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CargoFeatures { + All, + Selected { + /// List of features to activate. + features: Vec, + /// Do not activate the `default` feature. + no_default_features: bool, + }, +} + +impl Default for CargoFeatures { + fn default() -> Self { + CargoFeatures::Selected { features: vec![], no_default_features: false } + } +} + #[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct CargoConfig { - /// Do not activate the `default` feature. - pub no_default_features: bool, - - /// Activate all available features - pub all_features: bool, - /// List of features to activate. - /// This will be ignored if `cargo_all_features` is true. - pub features: Vec, - + pub features: CargoFeatures, /// rustc target pub target: Option, - /// Don't load sysroot crates (`std`, `core` & friends). Might be useful /// when debugging isolated issues. pub no_sysroot: bool, - /// rustc private crate source pub rustc_source: Option, - /// crates to disable `#[cfg(test)]` on pub unset_test_crates: UnsetTestCrates, - + /// Invoke `cargo check` through the RUSTC_WRAPPER. pub wrap_rustc_in_build_scripts: bool, - + /// The command to run instead of `cargo check` for building build scripts. pub run_build_script_command: Option>, - + /// Extra env vars to set when invoking the cargo command pub extra_env: FxHashMap, } @@ -143,7 +149,7 @@ pub struct PackageData { pub targets: Vec, /// Does this package come from the local filesystem (and is editable)? pub is_local: bool, - // Whether this package is a member of the workspace + /// Whether this package is a member of the workspace pub is_member: bool, /// List of packages this package depends on pub dependencies: Vec, @@ -249,8 +255,8 @@ impl TargetKind { } } +// Deserialize helper for the cargo metadata #[derive(Deserialize, Default)] -// Deserialise helper for the cargo metadata struct PackageMetadata { #[serde(rename = "rust-analyzer")] rust_analyzer: Option, @@ -272,16 +278,19 @@ impl CargoWorkspace { let mut meta = MetadataCommand::new(); meta.cargo_path(toolchain::cargo()); meta.manifest_path(cargo_toml.to_path_buf()); - if config.all_features { - meta.features(CargoOpt::AllFeatures); - } else { - if config.no_default_features { - // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` - // https://github.com/oli-obk/cargo_metadata/issues/79 - meta.features(CargoOpt::NoDefaultFeatures); + match &config.features { + CargoFeatures::All => { + meta.features(CargoOpt::AllFeatures); } - if !config.features.is_empty() { - meta.features(CargoOpt::SomeFeatures(config.features.clone())); + CargoFeatures::Selected { features, no_default_features } => { + if *no_default_features { + // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` + // https://github.com/oli-obk/cargo_metadata/issues/79 + meta.features(CargoOpt::NoDefaultFeatures); + } + if !features.is_empty() { + meta.features(CargoOpt::SomeFeatures(features.clone())); + } } } meta.current_dir(current_dir.as_os_str()); diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs index b81b7432f655..ce78ce85697a 100644 --- a/crates/project-model/src/lib.rs +++ b/crates/project-model/src/lib.rs @@ -42,8 +42,8 @@ use rustc_hash::FxHashSet; pub use crate::{ build_scripts::WorkspaceBuildScripts, cargo_workspace::{ - CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, RustcSource, Target, - TargetData, TargetKind, UnsetTestCrates, + CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency, + RustcSource, Target, TargetData, TargetKind, UnsetTestCrates, }, manifest_path::ManifestPath, project_json::{ProjectJson, ProjectJsonData}, diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 1c39e9391af2..e1675a030c0f 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs @@ -4,7 +4,7 @@ use std::mem; use cfg::{CfgAtom, CfgExpr}; use ide::{FileId, RunnableKind, TestId}; -use project_model::{self, ManifestPath, TargetKind}; +use project_model::{self, CargoFeatures, ManifestPath, TargetKind}; use vfs::AbsPathBuf; use crate::{global_state::GlobalStateSnapshot, Result}; @@ -35,41 +35,41 @@ impl CargoTargetSpec { match kind { RunnableKind::Test { test_id, attr } => { - args.push("test".to_string()); + args.push("test".to_owned()); extra_args.push(test_id.to_string()); if let TestId::Path(_) = test_id { - extra_args.push("--exact".to_string()); + extra_args.push("--exact".to_owned()); } - extra_args.push("--nocapture".to_string()); + extra_args.push("--nocapture".to_owned()); if attr.ignore { - extra_args.push("--ignored".to_string()); + extra_args.push("--ignored".to_owned()); } } RunnableKind::TestMod { path } => { - args.push("test".to_string()); - extra_args.push(path.to_string()); - extra_args.push("--nocapture".to_string()); + args.push("test".to_owned()); + extra_args.push(path.clone()); + extra_args.push("--nocapture".to_owned()); } RunnableKind::Bench { test_id } => { - args.push("bench".to_string()); + args.push("bench".to_owned()); extra_args.push(test_id.to_string()); if let TestId::Path(_) = test_id { - extra_args.push("--exact".to_string()); + extra_args.push("--exact".to_owned()); } - extra_args.push("--nocapture".to_string()); + extra_args.push("--nocapture".to_owned()); } RunnableKind::DocTest { test_id } => { - args.push("test".to_string()); - args.push("--doc".to_string()); + args.push("test".to_owned()); + args.push("--doc".to_owned()); extra_args.push(test_id.to_string()); - extra_args.push("--nocapture".to_string()); + extra_args.push("--nocapture".to_owned()); } RunnableKind::Bin => { let subcommand = match spec { Some(CargoTargetSpec { target_kind: TargetKind::Test, .. }) => "test", _ => "run", }; - args.push(subcommand.to_string()); + args.push(subcommand.to_owned()); } } @@ -82,29 +82,35 @@ impl CargoTargetSpec { }; let cargo_config = snap.config.cargo(); - if cargo_config.all_features { - args.push("--all-features".to_string()); - for feature in target_required_features { - args.push("--features".to_string()); - args.push(feature); - } - } else { - let mut features = Vec::new(); - if let Some(cfg) = cfg.as_ref() { - required_features(cfg, &mut features); + match &cargo_config.features { + CargoFeatures::All => { + args.push("--all-features".to_owned()); + for feature in target_required_features { + args.push("--features".to_owned()); + args.push(feature); + } } + CargoFeatures::Selected { features, no_default_features } => { + let mut feats = Vec::new(); + if let Some(cfg) = cfg.as_ref() { + required_features(cfg, &mut feats); + } - features.extend(cargo_config.features); - features.extend(target_required_features); + feats.extend(features.iter().cloned()); + feats.extend(target_required_features); - features.dedup(); - for feature in features { - args.push("--features".to_string()); - args.push(feature); + feats.dedup(); + for feature in feats { + args.push("--features".to_owned()); + args.push(feature); + } + + if *no_default_features { + args.push("--no-default-features".to_owned()); + } } } - Ok((args, extra_args)) } @@ -136,7 +142,7 @@ impl CargoTargetSpec { } pub(crate) fn push_to(self, buf: &mut Vec, kind: &RunnableKind) { - buf.push("--package".to_string()); + buf.push("--package".to_owned()); buf.push(self.package); // Can't mix --doc with other target flags @@ -145,23 +151,23 @@ impl CargoTargetSpec { } match self.target_kind { TargetKind::Bin => { - buf.push("--bin".to_string()); + buf.push("--bin".to_owned()); buf.push(self.target); } TargetKind::Test => { - buf.push("--test".to_string()); + buf.push("--test".to_owned()); buf.push(self.target); } TargetKind::Bench => { - buf.push("--bench".to_string()); + buf.push("--bench".to_owned()); buf.push(self.target); } TargetKind::Example => { - buf.push("--example".to_string()); + buf.push("--example".to_owned()); buf.push(self.target); } TargetKind::Lib => { - buf.push("--lib".to_string()); + buf.push("--lib".to_owned()); } TargetKind::Other | TargetKind::BuildScript => (), } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 9ef79e6f3812..0d0e246029b1 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -22,7 +22,8 @@ use ide_db::{ use itertools::Itertools; use lsp_types::{ClientCapabilities, MarkupKind}; use project_model::{ - CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource, UnsetTestCrates, + CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource, + UnsetTestCrates, }; use rustc_hash::{FxHashMap, FxHashSet}; use serde::{de::DeserializeOwned, Deserialize}; @@ -90,7 +91,7 @@ config_data! { /// List of features to activate. /// /// Set this to `"all"` to pass `--all-features` to cargo. - cargo_features: CargoFeatures = "[]", + cargo_features: CargoFeaturesDef = "[]", /// Whether to pass `--no-default-features` to cargo. cargo_noDefaultFeatures: bool = "false", /// Internal config for debugging, disables loading of sysroot crates. @@ -114,7 +115,7 @@ config_data! { /// `#rust-analyzer.cargo.features#`. /// /// Set to `"all"` to pass `--all-features` to Cargo. - checkOnSave_features: Option = "null", + checkOnSave_features: Option = "null", /// Whether to pass `--no-default-features` to Cargo. Defaults to /// `#rust-analyzer.cargo.noDefaultFeatures#`. checkOnSave_noDefaultFeatures: Option = "null", @@ -1028,11 +1029,12 @@ impl Config { }); CargoConfig { - no_default_features: self.data.cargo_noDefaultFeatures, - all_features: matches!(self.data.cargo_features, CargoFeatures::All), features: match &self.data.cargo_features { - CargoFeatures::All => vec![], - CargoFeatures::Listed(it) => it.clone(), + CargoFeaturesDef::All => CargoFeatures::All, + CargoFeaturesDef::Selected(features) => CargoFeatures::Selected { + features: features.clone(), + no_default_features: self.data.cargo_noDefaultFeatures, + }, }, target: self.data.cargo_target.clone(), no_sysroot: self.data.cargo_noSysroot, @@ -1086,7 +1088,7 @@ impl Config { .unwrap_or(self.data.cargo_noDefaultFeatures), all_features: matches!( self.data.checkOnSave_features.as_ref().unwrap_or(&self.data.cargo_features), - CargoFeatures::All + CargoFeaturesDef::All ), features: match self .data @@ -1094,8 +1096,8 @@ impl Config { .clone() .unwrap_or_else(|| self.data.cargo_features.clone()) { - CargoFeatures::All => vec![], - CargoFeatures::Listed(it) => it, + CargoFeaturesDef::All => vec![], + CargoFeaturesDef::Selected(it) => it, }, extra_args: self.data.checkOnSave_extraArgs.clone(), extra_env: self.check_on_save_extra_env(), @@ -1564,10 +1566,10 @@ enum CallableCompletionDef { #[derive(Deserialize, Debug, Clone)] #[serde(untagged)] -enum CargoFeatures { +enum CargoFeaturesDef { #[serde(deserialize_with = "de_unit_v::all")] All, - Listed(Vec), + Selected(Vec), } #[derive(Deserialize, Debug, Clone)] @@ -1912,7 +1914,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "Only show mutable reborrow hints." ] }, - "CargoFeatures" => set! { + "CargoFeaturesDef" => set! { "anyOf": [ { "type": "string", @@ -1929,7 +1931,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json } ], }, - "Option" => set! { + "Option" => set! { "anyOf": [ { "type": "string", From a6c067c06d9341e9d4c8a7ead2cc5f58a533ecfd Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 19 Sep 2022 17:31:08 +0200 Subject: [PATCH 018/175] Simplify --- crates/project-model/src/cargo_workspace.rs | 68 +++++++------------ crates/project-model/src/project_json.rs | 3 + crates/project-model/src/rustc_cfg.rs | 13 ++-- crates/project-model/src/sysroot.rs | 27 +++++--- crates/project-model/src/tests.rs | 6 +- crates/project-model/src/workspace.rs | 37 ++++++---- .../rust-analyzer/src/cli/analysis_stats.rs | 2 +- crates/rust-analyzer/src/cli/load_cargo.rs | 8 +-- crates/rust-analyzer/src/cli/lsif.rs | 2 +- crates/rust-analyzer/src/cli/scip.rs | 3 +- crates/rust-analyzer/src/config.rs | 1 + crates/rust-analyzer/src/reload.rs | 4 +- docs/user/generated_config.adoc | 1 + editors/code/package.json | 2 +- 14 files changed, 89 insertions(+), 88 deletions(-) diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index 8e50fe878ae3..bd2bbadea239 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -272,8 +272,8 @@ impl CargoWorkspace { let target = config .target .clone() - .or_else(|| cargo_config_build_target(cargo_toml, config)) - .or_else(|| rustc_discover_host_triple(cargo_toml, config)); + .or_else(|| cargo_config_build_target(cargo_toml, &config.extra_env)) + .or_else(|| rustc_discover_host_triple(cargo_toml, &config.extra_env)); let mut meta = MetadataCommand::new(); meta.cargo_path(toolchain::cargo()); @@ -304,12 +304,9 @@ impl CargoWorkspace { // unclear whether cargo itself supports it. progress("metadata".to_string()); - fn exec_with_env( - command: &cargo_metadata::MetadataCommand, - extra_env: &FxHashMap, - ) -> Result { - let mut command = command.cargo_command(); - command.envs(extra_env); + (|| -> Result { + let mut command = meta.cargo_command(); + command.envs(&config.extra_env); let output = command.output()?; if !output.status.success() { return Err(cargo_metadata::Error::CargoMetadata { @@ -321,12 +318,8 @@ impl CargoWorkspace { .find(|line| line.starts_with('{')) .ok_or(cargo_metadata::Error::NoJson)?; cargo_metadata::MetadataCommand::parse(stdout) - } - - let meta = exec_with_env(&meta, &config.extra_env) - .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))?; - - Ok(meta) + })() + .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command())) } pub fn new(mut meta: cargo_metadata::Metadata) -> CargoWorkspace { @@ -395,32 +388,14 @@ impl CargoWorkspace { } let resolve = meta.resolve.expect("metadata executed with deps"); for mut node in resolve.nodes { - let source = match pkg_by_id.get(&node.id) { - Some(&src) => src, - // FIXME: replace this and a similar branch below with `.unwrap`, once - // https://github.com/rust-lang/cargo/issues/7841 - // is fixed and hits stable (around 1.43-is probably?). - None => { - tracing::error!("Node id do not match in cargo metadata, ignoring {}", node.id); - continue; - } - }; + let &source = pkg_by_id.get(&node.id).unwrap(); node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg)); - for (dep_node, kind) in node + let dependencies = node .deps .iter() - .flat_map(|dep| DepKind::iter(&dep.dep_kinds).map(move |kind| (dep, kind))) - { - let pkg = match pkg_by_id.get(&dep_node.pkg) { - Some(&pkg) => pkg, - None => { - tracing::error!( - "Dep node id do not match in cargo metadata, ignoring {}", - dep_node.pkg - ); - continue; - } - }; + .flat_map(|dep| DepKind::iter(&dep.dep_kinds).map(move |kind| (dep, kind))); + for (dep_node, kind) in dependencies { + let &pkg = pkg_by_id.get(&dep_node.pkg).unwrap(); let dep = PackageDependency { name: dep_node.name.clone(), pkg, kind }; packages[source].dependencies.push(dep); } @@ -465,10 +440,7 @@ impl CargoWorkspace { found = true } self[pkg].dependencies.iter().find_map(|dep| { - if &self[dep.pkg].manifest == manifest_path { - return Some(self[pkg].manifest.clone()); - } - None + (&self[dep.pkg].manifest == manifest_path).then(|| self[pkg].manifest.clone()) }) }) .collect::>(); @@ -494,9 +466,12 @@ impl CargoWorkspace { } } -fn rustc_discover_host_triple(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option { +fn rustc_discover_host_triple( + cargo_toml: &ManifestPath, + extra_env: &FxHashMap, +) -> Option { let mut rustc = Command::new(toolchain::rustc()); - rustc.envs(&config.extra_env); + rustc.envs(extra_env); rustc.current_dir(cargo_toml.parent()).arg("-vV"); tracing::debug!("Discovering host platform by {:?}", rustc); match utf8_stdout(rustc) { @@ -518,9 +493,12 @@ fn rustc_discover_host_triple(cargo_toml: &ManifestPath, config: &CargoConfig) - } } -fn cargo_config_build_target(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option { +fn cargo_config_build_target( + cargo_toml: &ManifestPath, + extra_env: &FxHashMap, +) -> Option { let mut cargo_config = Command::new(toolchain::cargo()); - cargo_config.envs(&config.extra_env); + cargo_config.envs(extra_env); cargo_config .current_dir(cargo_toml.parent()) .args(&["-Z", "unstable-options", "config", "get", "build.target"]) diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index 63d1d0ace96b..5133a14d532b 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -110,14 +110,17 @@ impl ProjectJson { .collect::>(), } } + /// Returns the number of crates in the project. pub fn n_crates(&self) -> usize { self.crates.len() } + /// Returns an iterator over the crates in the project. pub fn crates(&self) -> impl Iterator + '_ { self.crates.iter().enumerate().map(|(idx, krate)| (CrateId(idx as u32), krate)) } + /// Returns the path to the project's root folder. pub fn path(&self) -> &AbsPath { &self.project_root diff --git a/crates/project-model/src/rustc_cfg.rs b/crates/project-model/src/rustc_cfg.rs index 486cb143b80b..323136183663 100644 --- a/crates/project-model/src/rustc_cfg.rs +++ b/crates/project-model/src/rustc_cfg.rs @@ -3,13 +3,14 @@ use std::process::Command; use anyhow::Result; +use rustc_hash::FxHashMap; -use crate::{cfg_flag::CfgFlag, utf8_stdout, CargoConfig, ManifestPath}; +use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath}; pub(crate) fn get( cargo_toml: Option<&ManifestPath>, target: Option<&str>, - config: &CargoConfig, + extra_env: &FxHashMap, ) -> Vec { let _p = profile::span("rustc_cfg::get"); let mut res = Vec::with_capacity(6 * 2 + 1); @@ -22,7 +23,7 @@ pub(crate) fn get( } } - match get_rust_cfgs(cargo_toml, target, config) { + match get_rust_cfgs(cargo_toml, target, extra_env) { Ok(rustc_cfgs) => { tracing::debug!( "rustc cfgs found: {:?}", @@ -42,11 +43,11 @@ pub(crate) fn get( fn get_rust_cfgs( cargo_toml: Option<&ManifestPath>, target: Option<&str>, - config: &CargoConfig, + extra_env: &FxHashMap, ) -> Result { if let Some(cargo_toml) = cargo_toml { let mut cargo_config = Command::new(toolchain::cargo()); - cargo_config.envs(&config.extra_env); + cargo_config.envs(extra_env); cargo_config .current_dir(cargo_toml.parent()) .args(&["-Z", "unstable-options", "rustc", "--print", "cfg"]) @@ -61,7 +62,7 @@ fn get_rust_cfgs( } // using unstable cargo features failed, fall back to using plain rustc let mut cmd = Command::new(toolchain::rustc()); - cmd.envs(&config.extra_env); + cmd.envs(extra_env); cmd.args(&["--print", "cfg", "-O"]); if let Some(target) = target { cmd.args(&["--target", target]); diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index 3282719fef3d..f0d76aa922f7 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -9,8 +9,9 @@ use std::{env, fs, iter, ops, path::PathBuf, process::Command}; use anyhow::{format_err, Result}; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf}; +use rustc_hash::FxHashMap; -use crate::{utf8_stdout, CargoConfig, ManifestPath}; +use crate::{utf8_stdout, ManifestPath}; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Sysroot { @@ -67,18 +68,21 @@ impl Sysroot { self.crates.iter().map(|(id, _data)| id) } - pub fn discover(dir: &AbsPath, config: &CargoConfig) -> Result { + pub fn discover(dir: &AbsPath, extra_env: &FxHashMap) -> Result { tracing::debug!("Discovering sysroot for {}", dir.display()); - let sysroot_dir = discover_sysroot_dir(dir, config)?; - let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir, config)?; + let sysroot_dir = discover_sysroot_dir(dir, extra_env)?; + let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir, extra_env)?; let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?; Ok(res) } - pub fn discover_rustc(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option { + pub fn discover_rustc( + cargo_toml: &ManifestPath, + extra_env: &FxHashMap, + ) -> Option { tracing::debug!("Discovering rustc source for {}", cargo_toml.display()); let current_dir = cargo_toml.parent(); - discover_sysroot_dir(current_dir, config) + discover_sysroot_dir(current_dir, extra_env) .ok() .and_then(|sysroot_dir| get_rustc_src(&sysroot_dir)) } @@ -146,9 +150,12 @@ impl Sysroot { } } -fn discover_sysroot_dir(current_dir: &AbsPath, config: &CargoConfig) -> Result { +fn discover_sysroot_dir( + current_dir: &AbsPath, + extra_env: &FxHashMap, +) -> Result { let mut rustc = Command::new(toolchain::rustc()); - rustc.envs(&config.extra_env); + rustc.envs(extra_env); rustc.current_dir(current_dir).args(&["--print", "sysroot"]); tracing::debug!("Discovering sysroot by {:?}", rustc); let stdout = utf8_stdout(rustc)?; @@ -158,7 +165,7 @@ fn discover_sysroot_dir(current_dir: &AbsPath, config: &CargoConfig) -> Result, ) -> Result { if let Ok(path) = env::var("RUST_SRC_PATH") { let path = AbsPathBuf::try_from(path.as_str()) @@ -174,7 +181,7 @@ fn discover_sysroot_src_dir( get_rust_src(sysroot_path) .or_else(|| { let mut rustup = Command::new(toolchain::rustup()); - rustup.envs(&config.extra_env); + rustup.envs(extra_env); rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]); utf8_stdout(rustup).ok()?; get_rust_src(sysroot_path) diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index bea624bd5419..813f0a7ce9f1 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -10,8 +10,8 @@ use paths::{AbsPath, AbsPathBuf}; use serde::de::DeserializeOwned; use crate::{ - CargoConfig, CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, - Sysroot, WorkspaceBuildScripts, + CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot, + WorkspaceBuildScripts, }; fn load_cargo(file: &str) -> CrateGraph { @@ -101,7 +101,7 @@ fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph { Some(FileId(counter)) } }, - &CargoConfig::default(), + &Default::default(), ) } diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index bc4ab45daeff..c749a3b6566f 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -156,7 +156,11 @@ impl ProjectWorkspace { })?; let project_location = project_json.parent().to_path_buf(); let project_json = ProjectJson::new(&project_location, data); - ProjectWorkspace::load_inline(project_json, config.target.as_deref(), config)? + ProjectWorkspace::load_inline( + project_json, + config.target.as_deref(), + &config.extra_env, + )? } ProjectManifest::CargoToml(cargo_toml) => { let cargo_version = utf8_stdout({ @@ -187,17 +191,21 @@ impl ProjectWorkspace { let sysroot = if config.no_sysroot { None } else { - Some(Sysroot::discover(cargo_toml.parent(), config).with_context(|| { - format!( + Some(Sysroot::discover(cargo_toml.parent(), &config.extra_env).with_context( + || { + format!( "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?", cargo_toml.display() ) - })?) + }, + )?) }; let rustc_dir = match &config.rustc_source { Some(RustcSource::Path(path)) => ManifestPath::try_from(path.clone()).ok(), - Some(RustcSource::Discover) => Sysroot::discover_rustc(&cargo_toml, config), + Some(RustcSource::Discover) => { + Sysroot::discover_rustc(&cargo_toml, &config.extra_env) + } None => None, }; @@ -217,7 +225,8 @@ impl ProjectWorkspace { None => None, }; - let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), config); + let rustc_cfg = + rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env); let cfg_overrides = config.cfg_overrides(); ProjectWorkspace::Cargo { @@ -238,7 +247,7 @@ impl ProjectWorkspace { pub fn load_inline( project_json: ProjectJson, target: Option<&str>, - config: &CargoConfig, + extra_env: &FxHashMap, ) -> Result { let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) { (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?), @@ -260,7 +269,7 @@ impl ProjectWorkspace { (None, None) => None, }; - let rustc_cfg = rustc_cfg::get(None, target, config); + let rustc_cfg = rustc_cfg::get(None, target, extra_env); Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) } @@ -270,9 +279,9 @@ impl ProjectWorkspace { .first() .and_then(|it| it.parent()) .ok_or_else(|| format_err!("No detached files to load"))?, - &CargoConfig::default(), + &Default::default(), )?; - let rustc_cfg = rustc_cfg::get(None, None, &CargoConfig::default()); + let rustc_cfg = rustc_cfg::get(None, None, &Default::default()); Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg }) } @@ -419,7 +428,7 @@ impl ProjectWorkspace { &self, load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, - config: &CargoConfig, + extra_env: &FxHashMap, ) -> CrateGraph { let _p = profile::span("ProjectWorkspace::to_crate_graph"); @@ -430,7 +439,7 @@ impl ProjectWorkspace { load, project, sysroot, - config, + extra_env, ), ProjectWorkspace::Cargo { cargo, @@ -469,7 +478,7 @@ fn project_json_to_crate_graph( load: &mut dyn FnMut(&AbsPath) -> Option, project: &ProjectJson, sysroot: &Option, - config: &CargoConfig, + extra_env: &FxHashMap, ) -> CrateGraph { let mut crate_graph = CrateGraph::default(); let sysroot_deps = sysroot @@ -497,7 +506,7 @@ fn project_json_to_crate_graph( let target_cfgs = match krate.target.as_deref() { Some(target) => cfg_cache .entry(target) - .or_insert_with(|| rustc_cfg::get(None, Some(target), config)), + .or_insert_with(|| rustc_cfg::get(None, Some(target), extra_env)), None => &rustc_cfg, }; diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 80128e43fd3c..81c393abdb34 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -81,7 +81,7 @@ impl flags::AnalysisStats { }; let (host, vfs, _proc_macro) = - load_workspace(workspace, &cargo_config, &load_cargo_config)?; + load_workspace(workspace, &cargo_config.extra_env, &load_cargo_config)?; let db = host.raw_database(); eprint!("{:<20} {}", "Database loaded:", db_load_sw.elapsed()); eprint!(" (metadata {}", metadata_time); diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 88953096e2bc..e07d90542373 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -6,7 +6,7 @@ use anyhow::Result; use crossbeam_channel::{unbounded, Receiver}; use hir::db::DefDatabase; use ide::{AnalysisHost, Change}; -use ide_db::base_db::CrateGraph; +use ide_db::{base_db::CrateGraph, FxHashMap}; use proc_macro_api::ProcMacroServer; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace}; use vfs::{loader::Handle, AbsPath, AbsPathBuf}; @@ -38,7 +38,7 @@ pub fn load_workspace_at( workspace.set_build_scripts(build_scripts) } - load_workspace(workspace, cargo_config, load_config) + load_workspace(workspace, &cargo_config.extra_env, load_config) } // Note: Since this function is used by external tools that use rust-analyzer as a library @@ -48,7 +48,7 @@ pub fn load_workspace_at( // these tools need access to `ProjectWorkspace`, too, which `load_workspace_at` hides. pub fn load_workspace( ws: ProjectWorkspace, - cargo_config: &CargoConfig, + extra_env: &FxHashMap, load_config: &LoadCargoConfig, ) -> Result<(AnalysisHost, vfs::Vfs, Option)> { let (sender, receiver) = unbounded(); @@ -76,7 +76,7 @@ pub fn load_workspace( vfs.set_file_contents(path.clone(), contents); vfs.file_id(&path) }, - cargo_config, + extra_env, ); let project_folders = ProjectFolders::new(&[ws], &[]); diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs index 79577bf78c8f..748306ea57d4 100644 --- a/crates/rust-analyzer/src/cli/lsif.rs +++ b/crates/rust-analyzer/src/cli/lsif.rs @@ -300,7 +300,7 @@ impl flags::Lsif { let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?; let (host, vfs, _proc_macro) = - load_workspace(workspace, &cargo_config, &load_cargo_config)?; + load_workspace(workspace, &cargo_config.extra_env, &load_cargo_config)?; let db = host.raw_database(); let analysis = host.analysis(); diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs index 05c16bb39e35..2c29b3ee3a6f 100644 --- a/crates/rust-analyzer/src/cli/scip.rs +++ b/crates/rust-analyzer/src/cli/scip.rs @@ -40,7 +40,8 @@ impl flags::Scip { let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?; - let (host, vfs, _) = load_workspace(workspace, &cargo_config, &load_cargo_config)?; + let (host, vfs, _) = + load_workspace(workspace, &cargo_config.extra_env, &load_cargo_config)?; let db = host.raw_database(); let analysis = host.analysis(); diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 0d0e246029b1..5d99d2fb1193 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -110,6 +110,7 @@ config_data! { /// Extra arguments for `cargo check`. checkOnSave_extraArgs: Vec = "[]", /// Extra environment variables that will be set when running `cargo check`. + /// Extends `#rust-analyzer.cargo.extraEnv#`. checkOnSave_extraEnv: FxHashMap = "{}", /// List of features to activate. Defaults to /// `#rust-analyzer.cargo.features#`. diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 4cf5de46c485..e7f7972e9abb 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -143,7 +143,7 @@ impl GlobalState { project_model::ProjectWorkspace::load_inline( it.clone(), cargo_config.target.as_deref(), - &cargo_config, + &cargo_config.extra_env, ) } }) @@ -402,7 +402,7 @@ impl GlobalState { crate_graph.extend(ws.to_crate_graph( &mut load_proc_macro, &mut load, - &self.config.cargo(), + &self.config.cargo().extra_env, )); } crate_graph diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 996d4c023d7b..a34f4d5093e3 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -103,6 +103,7 @@ Extra arguments for `cargo check`. + -- Extra environment variables that will be set when running `cargo check`. +Extends `#rust-analyzer.cargo.extraEnv#`. -- [[rust-analyzer.checkOnSave.features]]rust-analyzer.checkOnSave.features (default: `null`):: + diff --git a/editors/code/package.json b/editors/code/package.json index 94b41c049bc3..f8eec9f62e52 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -515,7 +515,7 @@ } }, "rust-analyzer.checkOnSave.extraEnv": { - "markdownDescription": "Extra environment variables that will be set when running `cargo check`.", + "markdownDescription": "Extra environment variables that will be set when running `cargo check`.\nExtends `#rust-analyzer.cargo.extraEnv#`.", "default": {}, "type": "object" }, From cdc362e6cc833913cb95d928b6146ae4317e488a Mon Sep 17 00:00:00 2001 From: DidiBear Date: Mon, 19 Sep 2022 12:00:58 -0400 Subject: [PATCH 019/175] docs(inlay-hints): remove reference to Toggle inlay hints --- crates/ide/src/inlay_hints.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 93fcd7cad7a1..08363d21e89b 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -176,12 +176,6 @@ impl fmt::Debug for InlayHintLabelPart { // * elided lifetimes // * compiler inserted reborrows // -// |=== -// | Editor | Action Name -// -// | VS Code | **rust-analyzer: Toggle inlay hints* -// |=== -// // image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[] pub(crate) fn inlay_hints( db: &RootDatabase, From f87ad8df055a53fff4f8b59922ccaf233211e334 Mon Sep 17 00:00:00 2001 From: OleStrohm Date: Mon, 19 Sep 2022 19:26:09 +0100 Subject: [PATCH 020/175] Added FIXME for the repr type of the enum --- crates/hir-ty/src/infer.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 285ec7520f40..7d1c98207586 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -68,6 +68,7 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc ctx.collect_fn(f), DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)), DefWithBodyId::VariantId(v) => { + // FIXME: This should return the `repr(...)` type of the enum ctx.return_ty = TyBuilder::def_ty(db, v.parent.into()).fill_with_unknown().build() } } From 9845e37f58b32750b8eec2fc150d2a36bb9971a3 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Tue, 20 Sep 2022 04:20:43 +0900 Subject: [PATCH 021/175] Ensure at least one trait bound in `TyKind::DynTy` --- crates/hir-ty/src/chalk_ext.rs | 2 ++ crates/hir-ty/src/lower.rs | 18 +++++++++++++----- crates/hir-ty/src/tests/regression.rs | 12 ++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index 4a5533c6487e..ed97bd2da4f3 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -166,6 +166,8 @@ impl TyExt for Ty { let trait_ref = match self.kind(Interner) { // The principal trait bound should be the first element of the bounds. This is an // invariant ensured by `TyLoweringContext::lower_dyn_trait()`. + // FIXME: dyn types may not have principal trait and we don't want to return auto trait + // here. TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| { match b.skip_binders() { WhereClause::Implemented(trait_ref) => Some(trait_ref), diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 532544fee595..e28c87dfa46b 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -981,10 +981,11 @@ impl<'a> TyLoweringContext<'a> { fn lower_dyn_trait(&self, bounds: &[Interned]) -> Ty { let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); - // INVARIANT: The principal trait bound must come first. Others may be in any order but - // should be in the same order for the same set but possibly different order of bounds in - // the input. - // This invariant is used by `TyExt::dyn_trait()` and chalk. + // INVARIANT: The principal trait bound, if present, must come first. Others may be in any + // order but should be in the same order for the same set but possibly different order of + // bounds in the input. + // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound. + // These invariants are utilized by `TyExt::dyn_trait()` and chalk. let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { let mut bounds: Vec<_> = bounds .iter() @@ -1035,6 +1036,12 @@ impl<'a> TyLoweringContext<'a> { return None; } + if bounds.first().and_then(|b| b.trait_id()).is_none() { + // When there's no trait bound, that's an error. This happens when the trait refs + // are unresolved. + return None; + } + // As multiple occurrences of the same auto traits *are* permitted, we dedulicate the // bounds. We shouldn't have repeated elements besides auto traits at this point. bounds.dedup(); @@ -1046,7 +1053,8 @@ impl<'a> TyLoweringContext<'a> { let bounds = crate::make_single_type_binders(bounds); TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner) } else { - // FIXME: report error (additional non-auto traits or associated type rebound) + // FIXME: report error + // (additional non-auto traits, associated type rebound, or no resolved trait) TyKind::Error.intern(Interner) } } diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 23e51a9c16a5..47cc3341e707 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1691,3 +1691,15 @@ fn macrostmts() -> u8 { "#, ); } + +#[test] +fn dyn_with_unresolved_trait() { + check_types( + r#" +fn foo(a: &dyn DoesNotExist) { + a.bar(); + //^&{unknown} +} + "#, + ); +} From 7e8eac3fd7dc04d39200f1aa1956112f678dc858 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 20 Sep 2022 14:33:18 +0200 Subject: [PATCH 022/175] Simplify --- crates/hir/src/semantics/source_to_def.rs | 6 +-- crates/project-model/src/workspace.rs | 61 +++++++++++------------ 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index ba9a1cfb6b51..87e22c2138b7 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -115,7 +115,7 @@ pub(super) struct SourceToDefCtx<'a, 'b> { } impl SourceToDefCtx<'_, '_> { - pub(super) fn file_to_def(&mut self, file: FileId) -> SmallVec<[ModuleId; 1]> { + pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> { let _p = profile::span("SourceBinder::to_module_def"); let mut mods = SmallVec::new(); for &crate_id in self.db.relevant_crates(file).iter() { @@ -130,7 +130,7 @@ impl SourceToDefCtx<'_, '_> { mods } - pub(super) fn module_to_def(&mut self, src: InFile) -> Option { + pub(super) fn module_to_def(&self, src: InFile) -> Option { let _p = profile::span("module_to_def"); let parent_declaration = src .syntax() @@ -151,7 +151,7 @@ impl SourceToDefCtx<'_, '_> { Some(def_map.module_id(child_id)) } - pub(super) fn source_file_to_def(&mut self, src: InFile) -> Option { + pub(super) fn source_file_to_def(&self, src: InFile) -> Option { let _p = profile::span("source_file_to_def"); let file_id = src.file_id.original_file(self.db.upcast()); self.file_to_def(file_id).get(0).copied() diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index c749a3b6566f..2c0af99940f9 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -21,8 +21,8 @@ use crate::{ cfg_flag::CfgFlag, rustc_cfg, sysroot::SysrootCrate, - utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, ProjectJson, ProjectManifest, Sysroot, - TargetKind, WorkspaceBuildScripts, + utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, Package, ProjectJson, ProjectManifest, + Sysroot, TargetKind, WorkspaceBuildScripts, }; /// A set of cfg-overrides per crate. @@ -315,6 +315,13 @@ impl ProjectWorkspace { /// The return type contains the path and whether or not /// the root is a member of the current workspace pub fn to_roots(&self) -> Vec { + let mk_sysroot = |sysroot: Option<&Sysroot>| { + sysroot.map(|sysroot| PackageRoot { + is_local: false, + include: vec![sysroot.src_root().to_path_buf()], + exclude: Vec::new(), + }) + }; match self { ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project .crates() @@ -325,13 +332,7 @@ impl ProjectWorkspace { }) .collect::>() .into_iter() - .chain(sysroot.as_ref().into_iter().flat_map(|sysroot| { - sysroot.crates().map(move |krate| PackageRoot { - is_local: false, - include: vec![sysroot[krate].root.parent().to_path_buf()], - exclude: Vec::new(), - }) - })) + .chain(mk_sysroot(sysroot.as_ref())) .collect::>(), ProjectWorkspace::Cargo { cargo, @@ -380,11 +381,7 @@ impl ProjectWorkspace { } PackageRoot { is_local, include, exclude } }) - .chain(sysroot.iter().map(|sysroot| PackageRoot { - is_local: false, - include: vec![sysroot.src_root().to_path_buf()], - exclude: Vec::new(), - })) + .chain(mk_sysroot(sysroot.as_ref())) .chain(rustc.iter().flat_map(|rustc| { rustc.packages().map(move |krate| PackageRoot { is_local: false, @@ -401,11 +398,7 @@ impl ProjectWorkspace { include: vec![detached_file.clone()], exclude: Vec::new(), }) - .chain(sysroot.crates().map(|krate| PackageRoot { - is_local: false, - include: vec![sysroot[krate].root.parent().to_path_buf()], - exclude: Vec::new(), - })) + .chain(mk_sysroot(Some(sysroot))) .collect(), } } @@ -639,6 +632,8 @@ fn cargo_to_crate_graph( lib_tgt = Some((crate_id, cargo[tgt].name.clone())); pkg_to_lib_crate.insert(pkg, crate_id); } + // Even crates that don't set proc-macro = true are allowed to depend on proc_macro + // (just none of the APIs work when called outside of a proc macro). if let Some(proc_macro) = libproc_macro { add_dep_with_prelude( &mut crate_graph, @@ -654,19 +649,19 @@ fn cargo_to_crate_graph( } // Set deps to the core, std and to the lib target of the current package - for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() { + for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() { // Add sysroot deps first so that a lib target named `core` etc. can overwrite them. - public_deps.add(*from, &mut crate_graph); + public_deps.add(from, &mut crate_graph); if let Some((to, name)) = lib_tgt.clone() { - if to != *from && *kind != TargetKind::BuildScript { + if to != from && kind != TargetKind::BuildScript { // (build script can not depend on its library target) // For root projects with dashes in their name, // cargo metadata does not do any normalization, // so we do it ourselves currently let name = CrateName::normalize_dashes(&name); - add_dep(&mut crate_graph, *from, name, to); + add_dep(&mut crate_graph, from, name, to); } } } @@ -678,17 +673,17 @@ fn cargo_to_crate_graph( for dep in cargo[pkg].dependencies.iter() { let name = CrateName::new(&dep.name).unwrap(); if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { - for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() { - if dep.kind == DepKind::Build && *kind != TargetKind::BuildScript { + for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() { + if dep.kind == DepKind::Build && kind != TargetKind::BuildScript { // Only build scripts may depend on build dependencies. continue; } - if dep.kind != DepKind::Build && *kind == TargetKind::BuildScript { + if dep.kind != DepKind::Build && kind == TargetKind::BuildScript { // Build scripts may only depend on build dependencies. continue; } - add_dep(&mut crate_graph, *from, name.clone(), to) + add_dep(&mut crate_graph, from, name.clone(), to) } } } @@ -699,9 +694,9 @@ fn cargo_to_crate_graph( // and create dependencies on them for the crates which opt-in to that if let Some(rustc_workspace) = rustc { handle_rustc_crates( + &mut crate_graph, rustc_workspace, load, - &mut crate_graph, &cfg_options, override_cfg, load_proc_macro, @@ -761,16 +756,16 @@ fn detached_files_to_crate_graph( } fn handle_rustc_crates( + crate_graph: &mut CrateGraph, rustc_workspace: &CargoWorkspace, load: &mut dyn FnMut(&AbsPath) -> Option, - crate_graph: &mut CrateGraph, cfg_options: &CfgOptions, override_cfg: &CfgOverrides, load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, - pkg_to_lib_crate: &mut FxHashMap, CrateId>, + pkg_to_lib_crate: &mut FxHashMap, public_deps: &SysrootPublicDeps, cargo: &CargoWorkspace, - pkg_crates: &FxHashMap, Vec<(CrateId, TargetKind)>>, + pkg_crates: &FxHashMap>, build_scripts: &WorkspaceBuildScripts, ) { let mut rustc_pkg_crates = FxHashMap::default(); @@ -784,8 +779,8 @@ fn handle_rustc_crates( let mut queue = VecDeque::new(); queue.push_back(root_pkg); while let Some(pkg) = queue.pop_front() { - // Don't duplicate packages if they are dependended on a diamond pattern - // N.B. if this line is omitted, we try to analyse over 4_800_000 crates + // Don't duplicate packages if they are dependent on a diamond pattern + // N.B. if this line is omitted, we try to analyze over 4_800_000 crates // which is not ideal if rustc_pkg_crates.contains_key(&pkg) { continue; From 027bfd68ba6258dcc26a9d43372d869308d512e2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 20 Sep 2022 14:33:44 +0200 Subject: [PATCH 023/175] Fix operator highlighting tags applying too broadly --- crates/ide/src/syntax_highlighting/highlight.rs | 11 ++++++----- .../test_data/highlight_assoc_functions.html | 6 +++--- .../test_data/highlight_doctest.html | 2 +- .../test_data/highlight_general.html | 12 ++++++------ .../test_data/highlight_injection.html | 2 +- .../test_data/highlight_lifetimes.html | 4 ++-- .../test_data/highlight_strings.html | 8 ++++---- .../test_data/highlight_unsafe.html | 8 ++++---- 8 files changed, 27 insertions(+), 26 deletions(-) diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 9395e914c43a..e7d0a8be7f57 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs @@ -87,9 +87,9 @@ fn punctuation( let parent = token.parent(); let parent_kind = parent.as_ref().map_or(EOF, SyntaxNode::kind); match (kind, parent_kind) { - (T![?], _) => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow, + (T![?], TRY_EXPR) => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow, (T![&], BIN_EXPR) => HlOperator::Bitwise.into(), - (T![&], _) => { + (T![&], REF_EXPR) => { let h = HlTag::Operator(HlOperator::Other).into(); let is_unsafe = parent .and_then(ast::RefExpr::cast) @@ -100,7 +100,9 @@ fn punctuation( h } } - (T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.], _) => HlOperator::Other.into(), + (T![::] | T![->] | T![=>] | T![..] | T![..=] | T![=] | T![@] | T![.], _) => { + HlOperator::Other.into() + } (T![!], MACRO_CALL | MACRO_RULES) => HlPunct::MacroBang.into(), (T![!], NEVER_TYPE) => HlTag::BuiltinType.into(), (T![!], PREFIX_EXPR) => HlOperator::Logical.into(), @@ -129,7 +131,7 @@ fn punctuation( (T![+=] | T![-=] | T![*=] | T![/=] | T![%=], BIN_EXPR) => { Highlight::from(HlOperator::Arithmetic) | HlMod::Mutable } - (T![|] | T![&] | T![!] | T![^] | T![>>] | T![<<], BIN_EXPR) => HlOperator::Bitwise.into(), + (T![|] | T![&] | T![^] | T![>>] | T![<<], BIN_EXPR) => HlOperator::Bitwise.into(), (T![|=] | T![&=] | T![^=] | T![>>=] | T![<<=], BIN_EXPR) => { Highlight::from(HlOperator::Bitwise) | HlMod::Mutable } @@ -137,7 +139,6 @@ fn punctuation( (T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=], BIN_EXPR) => { HlOperator::Comparison.into() } - (_, PREFIX_EXPR | BIN_EXPR | RANGE_EXPR | RANGE_PAT | REST_PAT) => HlOperator::Other.into(), (_, ATTR) => HlTag::AttributeBracket.into(), (kind, _) => match kind { T!['['] | T![']'] => HlPunct::Bracket, diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html index e07fd3925c78..9ed65fbc8548 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html @@ -48,15 +48,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd impl foo { pub fn is_static() {} - pub fn is_not_static(&self) {} + pub fn is_not_static(&self) {} } trait t { fn t_is_static() {} - fn t_is_not_static(&self) {} + fn t_is_not_static(&self) {} } impl t for foo { pub fn is_static() {} - pub fn is_not_static(&self) {} + pub fn is_not_static(&self) {} } \ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index eef5baea9839..18045f1f55af 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html @@ -125,7 +125,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd /// ```sh /// echo 1 /// ``` - pub fn foo(&self) -> bool { + pub fn foo(&self) -> bool { true } } diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html index a97802cbbd0f..9f2b1926b511 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html @@ -61,11 +61,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } trait Bar { - fn bar(&self) -> i32; + fn bar(&self) -> i32; } impl Bar for Foo { - fn bar(&self) -> i32 { + fn bar(&self) -> i32 { self.x } } @@ -75,11 +75,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd f.baz(self) } - fn qux(&mut self) { + fn qux(&mut self) { self.x = 0; } - fn quop(&self) -> i32 { + fn quop(&self) -> i32 { self.x } } @@ -96,11 +96,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd f.baz(self) } - fn qux(&mut self) { + fn qux(&mut self) { self.x = 0; } - fn quop(&self) -> u32 { + fn quop(&self) -> u32 { self.x } } diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index ced7d22f03e4..abcd80c280bf 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html @@ -42,7 +42,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } -

fn fixture(ra_fixture: &str) {}
+
fn fixture(ra_fixture: &str) {}
 
 fn main() {
     fixture(r#"
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html b/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
index 2d85fc8c925b..f98e0b1cda6e 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
@@ -45,8 +45,8 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 

 #[derive()]
 struct Foo<'a, 'b, 'c> where 'a: 'a, 'static: 'static {
-    field: &'a (),
-    field2: &'static (),
+    field: &'a (),
+    field2: &'static (),
 }
 impl<'a> Foo<'_, 'a, 'static>
 where
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index c627bc9b09ab..a626cda3fe8b 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -62,16 +62,16 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         () => (
             $crate::panicking::panic("explicit panic")
         ),
-        ($msg:literal $(,)?) => (
+        ($msg:literal $(,)?) => (
             $crate::panicking::panic($msg)
         ),
         // Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint.
-        ($msg:expr $(,)?) => (
+        ($msg:expr $(,)?) => (
             $crate::panicking::panic_str($msg)
         ),
         // Special-case the single-argument case for const_panic.
-        ("{}", $arg:expr $(,)?) => (
-            $crate::panicking::panic_display(&$arg)
+        ("{}", $arg:expr $(,)?) => (
+            $crate::panicking::panic_display(&$arg)
         ),
         ($fmt:expr, $($arg:tt)+) => (
             $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+))
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 0716bae7513b..1992bdc6ae35 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -49,7 +49,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 }
 macro_rules! unsafe_deref {
     () => {
-        *(&() as *const ())
+        *(&() as *const ())
     };
 }
 static mut MUT_GLOBAL: Struct = Struct { field: 0 };
@@ -63,7 +63,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 struct Struct { field: i32 }
 impl Struct {
-    unsafe fn unsafe_method(&self) {}
+    unsafe fn unsafe_method(&self) {}
 }
 
 #[repr(packed)]
@@ -78,11 +78,11 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 fn unsafe_trait_bound<T: UnsafeTrait>(_: T) {}
 
 trait DoTheAutoref {
-    fn calls_autoref(&self);
+    fn calls_autoref(&self);
 }
 
 impl DoTheAutoref for u16 {
-    fn calls_autoref(&self) {}
+    fn calls_autoref(&self) {}
 }
 
 fn main() {

From 6d0d051628503f1147a452ad83c4f24b63c9f395 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Tue, 20 Sep 2022 17:12:10 +0200
Subject: [PATCH 024/175] Simplify

---
 crates/hir-ty/src/consteval.rs | 41 ++++++++++++++++------------------
 1 file changed, 19 insertions(+), 22 deletions(-)

diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 965bf3f2c5b8..2c0c6e0b8394 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -153,7 +153,7 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
     }
 }
 
-fn get_name(variant: EnumVariantId, ctx: &mut ConstEvalCtx<'_>) -> String {
+fn get_name(ctx: &mut ConstEvalCtx<'_>, variant: EnumVariantId) -> String {
     let loc = variant.parent.lookup(ctx.db.upcast());
     let children = variant.parent.child_source(ctx.db.upcast());
     let item_tree = loc.id.item_tree(ctx.db.upcast());
@@ -167,20 +167,24 @@ pub fn eval_const(
     expr_id: ExprId,
     ctx: &mut ConstEvalCtx<'_>,
 ) -> Result {
+    let u128_to_i128 = |it: u128| -> Result {
+        it.try_into().map_err(|_| ConstEvalError::NotSupported("u128 is too big"))
+    };
+
     let expr = &ctx.exprs[expr_id];
     match expr {
         Expr::Missing => match ctx.owner {
+            // evaluate the implicit variant index of an enum variant without expression
+            // FIXME: This should return the type of the enum representation
             DefWithBodyId::VariantId(variant) => {
                 let prev_idx: u32 = variant.local_id.into_raw().into();
-                let prev_idx = prev_idx.checked_sub(1).map(|idx| Idx::from_raw(RawIdx::from(idx)));
+                let prev_idx = prev_idx.checked_sub(1).map(RawIdx::from).map(Idx::from_raw);
                 let value = match prev_idx {
-                    Some(prev) => {
-                        let prev_variant = EnumVariantId { local_id: prev, ..variant };
+                    Some(local_id) => {
+                        let prev_variant = EnumVariantId { local_id, parent: variant.parent };
                         1 + match ctx.db.const_eval_variant(prev_variant)? {
                             ComputedExpr::Literal(Literal::Int(v, _)) => v,
-                            ComputedExpr::Literal(Literal::Uint(v, _)) => v
-                                .try_into()
-                                .map_err(|_| ConstEvalError::NotSupported("too big u128"))?,
+                            ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
                             _ => {
                                 return Err(ConstEvalError::NotSupported(
                                     "Enum can't contain this kind of value",
@@ -206,9 +210,7 @@ pub fn eval_const(
                             return Ok(ComputedExpr::Literal(Literal::Bool(!b)))
                         }
                         ComputedExpr::Literal(Literal::Int(v, _)) => v,
-                        ComputedExpr::Literal(Literal::Uint(v, _)) => v
-                            .try_into()
-                            .map_err(|_| ConstEvalError::NotSupported("too big u128"))?,
+                        ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
                         _ => return Err(ConstEvalError::NotSupported("this kind of operator")),
                     };
                     let r = match ty.kind(Interner) {
@@ -237,9 +239,7 @@ pub fn eval_const(
                 hir_def::expr::UnaryOp::Neg => {
                     let v = match ev {
                         ComputedExpr::Literal(Literal::Int(v, _)) => v,
-                        ComputedExpr::Literal(Literal::Uint(v, _)) => v
-                            .try_into()
-                            .map_err(|_| ConstEvalError::NotSupported("too big u128"))?,
+                        ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
                         _ => return Err(ConstEvalError::NotSupported("this kind of operator")),
                     };
                     Ok(ComputedExpr::Literal(Literal::Int(
@@ -258,16 +258,12 @@ pub fn eval_const(
             let op = op.ok_or(ConstEvalError::IncompleteExpr)?;
             let v1 = match lhs {
                 ComputedExpr::Literal(Literal::Int(v, _)) => v,
-                ComputedExpr::Literal(Literal::Uint(v, _)) => {
-                    v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))?
-                }
+                ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
                 _ => return Err(ConstEvalError::NotSupported("this kind of operator")),
             };
             let v2 = match rhs {
                 ComputedExpr::Literal(Literal::Int(v, _)) => v,
-                ComputedExpr::Literal(Literal::Uint(v, _)) => {
-                    v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))?
-                }
+                ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
                 _ => return Err(ConstEvalError::NotSupported("this kind of operator")),
             };
             match op {
@@ -380,7 +376,7 @@ pub fn eval_const(
                 }
                 ValueNs::EnumVariantId(id) => match ctx.db.const_eval_variant(id)? {
                     ComputedExpr::Literal(lit) => {
-                        Ok(ComputedExpr::Enum(get_name(id, ctx), id, lit))
+                        Ok(ComputedExpr::Enum(get_name(ctx, id), id, lit))
                     }
                     _ => Err(ConstEvalError::NotSupported(
                         "Enums can't evalute to anything but numbers",
@@ -389,6 +385,7 @@ pub fn eval_const(
                 _ => Err(ConstEvalError::NotSupported("path that are not const or local")),
             }
         }
+        // FIXME: Handle the cast target
         &Expr::Cast { expr, .. } => match eval_const(expr, ctx)? {
             ComputedExpr::Enum(_, _, lit) => Ok(ComputedExpr::Literal(lit)),
             _ => Err(ConstEvalError::NotSupported("Can't cast these types")),
@@ -463,7 +460,7 @@ pub(crate) fn const_eval_recover(
     Err(ConstEvalError::Loop)
 }
 
-pub(crate) fn const_eval_recover_variant(
+pub(crate) fn const_eval_variant_recover(
     _: &dyn HirDatabase,
     _: &[String],
     _: &EnumVariantId,
@@ -471,7 +468,7 @@ pub(crate) fn const_eval_recover_variant(
     Err(ConstEvalError::Loop)
 }
 
-pub(crate) fn const_eval_query(
+pub(crate) fn const_eval_variant_query(
     db: &dyn HirDatabase,
     const_id: ConstId,
 ) -> Result {

From 9f233cd5d25a2d57dbf617824ca352b45cddbbdb Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Tue, 20 Sep 2022 17:12:27 +0200
Subject: [PATCH 025/175] Parse more repr options

---
 crates/hir-def/src/adt.rs  | 75 ++++++++++++++++++++++++++++++++------
 crates/hir-def/src/lib.rs  |  1 -
 crates/hir-ty/src/db.rs    |  4 +-
 crates/hir-ty/src/infer.rs |  7 +++-
 crates/hir/src/lib.rs      |  6 +--
 5 files changed, 74 insertions(+), 19 deletions(-)

diff --git a/crates/hir-def/src/adt.rs b/crates/hir-def/src/adt.rs
index 277135d6dc42..785095800604 100644
--- a/crates/hir-def/src/adt.rs
+++ b/crates/hir-def/src/adt.rs
@@ -1,6 +1,6 @@
 //! Defines hir-level representation of structs, enums and unions
 
-use std::sync::Arc;
+use std::{num::NonZeroU32, sync::Arc};
 
 use base_db::CrateId;
 use either::Either;
@@ -14,6 +14,7 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
 
 use crate::{
     body::{CfgExpander, LowerCtx},
+    builtin_type::{BuiltinInt, BuiltinUint},
     db::DefDatabase,
     intern::Interned,
     item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId},
@@ -31,7 +32,7 @@ use cfg::CfgOptions;
 pub struct StructData {
     pub name: Name,
     pub variant_data: Arc,
-    pub repr: Option,
+    pub repr: Option,
     pub visibility: RawVisibility,
 }
 
@@ -39,6 +40,7 @@ pub struct StructData {
 pub struct EnumData {
     pub name: Name,
     pub variants: Arena,
+    pub repr: Option,
     pub visibility: RawVisibility,
 }
 
@@ -63,10 +65,19 @@ pub struct FieldData {
     pub visibility: RawVisibility,
 }
 
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
 pub enum ReprKind {
-    Packed,
-    Other,
+    C,
+    BuiltinInt { builtin: Either, is_c: bool },
+    Transparent,
+    Default,
+}
+
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
+pub struct ReprData {
+    pub kind: ReprKind,
+    pub packed: bool,
+    pub align: Option,
 }
 
 fn repr_from_value(
@@ -74,21 +85,60 @@ fn repr_from_value(
     krate: CrateId,
     item_tree: &ItemTree,
     of: AttrOwner,
-) -> Option {
+) -> Option {
     item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt)
 }
 
-fn parse_repr_tt(tt: &Subtree) -> Option {
+fn parse_repr_tt(tt: &Subtree) -> Option {
     match tt.delimiter {
         Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {}
         _ => return None,
     }
 
-    let mut it = tt.token_trees.iter();
-    match it.next()? {
-        TokenTree::Leaf(Leaf::Ident(ident)) if ident.text == "packed" => Some(ReprKind::Packed),
-        _ => Some(ReprKind::Other),
+    let mut data = ReprData { kind: ReprKind::Default, packed: false, align: None };
+
+    let mut tts = tt.token_trees.iter().peekable();
+    while let Some(tt) = tts.next() {
+        if let TokenTree::Leaf(Leaf::Ident(ident)) = tt {
+            match &*ident.text {
+                "packed" => {
+                    data.packed = true;
+                    if let Some(TokenTree::Subtree(_)) = tts.peek() {
+                        tts.next();
+                    }
+                }
+                "align" => {
+                    if let Some(TokenTree::Subtree(tt)) = tts.peek() {
+                        tts.next();
+                        if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() {
+                            if let Ok(align) = lit.text.parse() {
+                                data.align = Some(align);
+                            }
+                        }
+                    }
+                }
+                "C" => {
+                    if let ReprKind::BuiltinInt { is_c, .. } = &mut data.kind {
+                        *is_c = true;
+                    } else {
+                        data.kind = ReprKind::C;
+                    }
+                }
+                "transparent" => data.kind = ReprKind::Transparent,
+                repr => {
+                    let is_c = matches!(data.kind, ReprKind::C);
+                    if let Some(builtin) = BuiltinInt::from_suffix(repr)
+                        .map(Either::Left)
+                        .or_else(|| BuiltinUint::from_suffix(repr).map(Either::Right))
+                    {
+                        data.kind = ReprKind::BuiltinInt { builtin, is_c };
+                    }
+                }
+            }
+        }
     }
+
+    Some(data)
 }
 
 impl StructData {
@@ -108,6 +158,7 @@ impl StructData {
             visibility: item_tree[strukt.visibility].clone(),
         })
     }
+
     pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc {
         let loc = id.lookup(db);
         let krate = loc.container.krate;
@@ -133,6 +184,7 @@ impl EnumData {
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
         let cfg_options = db.crate_graph()[krate].cfg_options.clone();
+        let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
 
         let enum_ = &item_tree[loc.id.value];
         let mut variants = Arena::new();
@@ -158,6 +210,7 @@ impl EnumData {
         Arc::new(EnumData {
             name: enum_.name.clone(),
             variants,
+            repr,
             visibility: item_tree[enum_.visibility].clone(),
         })
     }
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 4c44840e861d..5c7aa72349f6 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -479,7 +479,6 @@ pub enum DefWithBodyId {
 
 impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
 
-// FIXME: Rename EnumVariantId to VariantId so that the macro above can be used
 impl From for DefWithBodyId {
     fn from(id: EnumVariantId) -> Self {
         DefWithBodyId::VariantId(id)
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index e16530ecc155..9ac5eaa74e94 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -44,12 +44,12 @@ pub trait HirDatabase: DefDatabase + Upcast {
     #[salsa::invoke(crate::lower::const_param_ty_query)]
     fn const_param_ty(&self, def: ConstParamId) -> Ty;
 
-    #[salsa::invoke(crate::consteval::const_eval_query)]
+    #[salsa::invoke(crate::consteval::const_eval_variant_query)]
     #[salsa::cycle(crate::consteval::const_eval_recover)]
     fn const_eval(&self, def: ConstId) -> Result;
 
     #[salsa::invoke(crate::consteval::const_eval_query_variant)]
-    #[salsa::cycle(crate::consteval::const_eval_recover_variant)]
+    #[salsa::cycle(crate::consteval::const_eval_variant_recover)]
     fn const_eval_variant(&self, def: EnumVariantId) -> Result;
 
     #[salsa::invoke(crate::lower::impl_trait_query)]
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 7d1c98207586..85309d32335d 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -67,9 +67,12 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc ctx.collect_const(&db.const_data(c)),
         DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
         DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
-        DefWithBodyId::VariantId(v) => {
+        DefWithBodyId::VariantId(_v) => {
+            // db.enum_data(v.parent)
             // FIXME: This should return the `repr(...)` type of the enum
-            ctx.return_ty = TyBuilder::def_ty(db, v.parent.into()).fill_with_unknown().build()
+            ctx.return_ty = TyBuilder::builtin(hir_def::builtin_type::BuiltinType::Uint(
+                hir_def::builtin_type::BuiltinUint::U32,
+            ));
         }
     }
 
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 389e07db336a..7d25eee0c0b4 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -39,7 +39,7 @@ use arrayvec::ArrayVec;
 use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
 use either::Either;
 use hir_def::{
-    adt::{ReprKind, VariantData},
+    adt::{ReprData, VariantData},
     body::{BodyDiagnostic, SyntheticSyntax},
     expr::{BindingAnnotation, LabelId, Pat, PatId},
     generics::{TypeOrConstParamData, TypeParamProvenance},
@@ -874,7 +874,7 @@ impl Struct {
         Type::from_def(db, self.id)
     }
 
-    pub fn repr(self, db: &dyn HirDatabase) -> Option {
+    pub fn repr(self, db: &dyn HirDatabase) -> Option {
         db.struct_data(self.id).repr.clone()
     }
 
@@ -2964,7 +2964,7 @@ impl Type {
 
         let adt = adt_id.into();
         match adt {
-            Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)),
+            Adt::Struct(s) => matches!(s.repr(db), Some(ReprData { packed: true, .. })),
             _ => false,
         }
     }

From b25f0ba15bc2cf6877f2e04d6d3e89843b069679 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Tue, 20 Sep 2022 17:15:48 +0200
Subject: [PATCH 026/175] Properly set the enum variant body expected type

---
 crates/hir-ty/src/infer.rs | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 85309d32335d..2c6d503def1d 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -18,7 +18,9 @@ use std::sync::Arc;
 
 use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
 use hir_def::{
+    adt::{ReprData, ReprKind},
     body::Body,
+    builtin_type::BuiltinType,
     data::{ConstData, StaticData},
     expr::{BindingAnnotation, ExprId, PatId},
     lang_item::LangItemTarget,
@@ -67,12 +69,16 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc ctx.collect_const(&db.const_data(c)),
         DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
         DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
-        DefWithBodyId::VariantId(_v) => {
-            // db.enum_data(v.parent)
-            // FIXME: This should return the `repr(...)` type of the enum
-            ctx.return_ty = TyBuilder::builtin(hir_def::builtin_type::BuiltinType::Uint(
-                hir_def::builtin_type::BuiltinUint::U32,
-            ));
+        DefWithBodyId::VariantId(v) => {
+            ctx.return_ty = match db.enum_data(v.parent).repr {
+                Some(ReprData { kind: ReprKind::BuiltinInt { builtin, .. }, .. }) => {
+                    TyBuilder::builtin(match builtin {
+                        Either::Left(builtin) => BuiltinType::Int(builtin),
+                        Either::Right(builtin) => BuiltinType::Uint(builtin),
+                    })
+                }
+                _ => TyBuilder::builtin(BuiltinType::Uint(hir_def::builtin_type::BuiltinUint::U32)),
+            };
         }
     }
 

From 2119c1f3519ab1f106de30f668cbd19f7c39b40d Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Tue, 20 Sep 2022 17:29:35 +0200
Subject: [PATCH 027/175] Fix using incorrect type for variants in
 DefWithBody::body_type

---
 crates/hir-def/src/adt.rs  |  7 +++++++
 crates/hir-ty/src/db.rs    |  9 ++-------
 crates/hir-ty/src/infer.rs | 14 ++++----------
 crates/hir/src/lib.rs      | 13 ++++++++++++-
 4 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/crates/hir-def/src/adt.rs b/crates/hir-def/src/adt.rs
index 785095800604..b093669e6a71 100644
--- a/crates/hir-def/src/adt.rs
+++ b/crates/hir-def/src/adt.rs
@@ -219,6 +219,13 @@ impl EnumData {
         let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?;
         Some(id)
     }
+
+    pub fn variant_body_type(&self) -> Either {
+        match self.repr {
+            Some(ReprData { kind: ReprKind::BuiltinInt { builtin, .. }, .. }) => builtin,
+            _ => Either::Right(BuiltinUint::U32),
+        }
+    }
 }
 
 impl HasChildSource for EnumId {
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 9ac5eaa74e94..72abcc2b4b60 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -7,8 +7,7 @@ use arrayvec::ArrayVec;
 use base_db::{impl_intern_key, salsa, CrateId, Upcast};
 use hir_def::{
     db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId,
-    FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, Lookup, TypeOrConstParamId,
-    VariantId,
+    FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
 };
 use la_arena::ArenaMap;
 
@@ -194,11 +193,7 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc
             db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string()
         }
         DefWithBodyId::VariantId(it) => {
-            let up_db: &dyn DefDatabase = db.upcast();
-            let loc = it.parent.lookup(up_db);
-            let item_tree = loc.id.item_tree(up_db);
-            let konst = &item_tree[loc.id.value];
-            konst.name.to_string()
+            db.enum_data(it.parent).variants[it.local_id].name.to_string()
         }
     });
     db.infer_query(def)
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 2c6d503def1d..daf1e2f0c6d3 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -18,7 +18,6 @@ use std::sync::Arc;
 
 use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
 use hir_def::{
-    adt::{ReprData, ReprKind},
     body::Body,
     builtin_type::BuiltinType,
     data::{ConstData, StaticData},
@@ -70,15 +69,10 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc ctx.collect_fn(f),
         DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
         DefWithBodyId::VariantId(v) => {
-            ctx.return_ty = match db.enum_data(v.parent).repr {
-                Some(ReprData { kind: ReprKind::BuiltinInt { builtin, .. }, .. }) => {
-                    TyBuilder::builtin(match builtin {
-                        Either::Left(builtin) => BuiltinType::Int(builtin),
-                        Either::Right(builtin) => BuiltinType::Uint(builtin),
-                    })
-                }
-                _ => TyBuilder::builtin(BuiltinType::Uint(hir_def::builtin_type::BuiltinUint::U32)),
-            };
+            ctx.return_ty = TyBuilder::builtin(match db.enum_data(v.parent).variant_body_type() {
+                Either::Left(builtin) => BuiltinType::Int(builtin),
+                Either::Right(builtin) => BuiltinType::Uint(builtin),
+            });
         }
     }
 
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 7d25eee0c0b4..1c48d2ff0817 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -953,6 +953,17 @@ impl Enum {
         Type::from_def(db, self.id)
     }
 
+    /// The type of the enum variant bodies.
+    pub fn variant_body_ty(self, db: &dyn HirDatabase) -> Type {
+        Type::new_for_crate(
+            self.id.lookup(db.upcast()).container.krate(),
+            TyBuilder::builtin(match db.enum_data(self.id).variant_body_type() {
+                Either::Left(builtin) => hir_def::builtin_type::BuiltinType::Int(builtin),
+                Either::Right(builtin) => hir_def::builtin_type::BuiltinType::Uint(builtin),
+            }),
+        )
+    }
+
     pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool {
         self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
     }
@@ -1176,7 +1187,7 @@ impl DefWithBody {
             DefWithBody::Function(it) => it.ret_type(db),
             DefWithBody::Static(it) => it.ty(db),
             DefWithBody::Const(it) => it.ty(db),
-            DefWithBody::Variant(it) => it.parent.ty(db),
+            DefWithBody::Variant(it) => it.parent.variant_body_ty(db),
         }
     }
 

From 9bf386f4c03571c58e6a38267f1008241ea723ef Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Tue, 20 Sep 2022 17:43:29 +0200
Subject: [PATCH 028/175] Fix default enum representation not being isize

---
 crates/hir-def/src/adt.rs         |  2 +-
 crates/hir-ty/src/tests.rs        | 12 +++++
 crates/hir-ty/src/tests/simple.rs | 77 ++++++++++++++++++++++---------
 3 files changed, 69 insertions(+), 22 deletions(-)

diff --git a/crates/hir-def/src/adt.rs b/crates/hir-def/src/adt.rs
index b093669e6a71..14f8629056fa 100644
--- a/crates/hir-def/src/adt.rs
+++ b/crates/hir-def/src/adt.rs
@@ -223,7 +223,7 @@ impl EnumData {
     pub fn variant_body_type(&self) -> Either {
         match self.repr {
             Some(ReprData { kind: ReprKind::BuiltinInt { builtin, .. }, .. }) => builtin,
-            _ => Either::Right(BuiltinUint::U32),
+            _ => Either::Left(BuiltinInt::Isize),
         }
     }
 }
diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs
index be5ece9c5c50..ebbc5410147c 100644
--- a/crates/hir-ty/src/tests.rs
+++ b/crates/hir-ty/src/tests.rs
@@ -461,6 +461,18 @@ fn visit_module(
                     let body = db.body(def);
                     visit_body(db, &body, cb);
                 }
+                ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
+                    db.enum_data(it)
+                        .variants
+                        .iter()
+                        .map(|(id, _)| hir_def::EnumVariantId { parent: it, local_id: id })
+                        .for_each(|it| {
+                            let def = it.into();
+                            cb(def);
+                            let body = db.body(def);
+                            visit_body(db, &body, cb);
+                        });
+                }
                 ModuleDefId::TraitId(it) => {
                     let trait_data = db.trait_data(it);
                     for &(_, item) in trait_data.items.iter() {
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 4ea103e5d9ec..1757327b929d 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -1693,16 +1693,16 @@ fn infer_type_param() {
 fn infer_const() {
     check_infer(
         r#"
-        struct Foo;
-        impl Foo { const ASSOC_CONST: u32 = 0; }
-        const GLOBAL_CONST: u32 = 101;
-        fn test() {
-            const LOCAL_CONST: u32 = 99;
-            let x = LOCAL_CONST;
-            let z = GLOBAL_CONST;
-            let id = Foo::ASSOC_CONST;
-        }
-        "#,
+struct Foo;
+impl Foo { const ASSOC_CONST: u32 = 0; }
+const GLOBAL_CONST: u32 = 101;
+fn test() {
+    const LOCAL_CONST: u32 = 99;
+    let x = LOCAL_CONST;
+    let z = GLOBAL_CONST;
+    let id = Foo::ASSOC_CONST;
+}
+"#,
         expect![[r#"
             48..49 '0': u32
             79..82 '101': u32
@@ -1722,17 +1722,17 @@ fn infer_const() {
 fn infer_static() {
     check_infer(
         r#"
-        static GLOBAL_STATIC: u32 = 101;
-        static mut GLOBAL_STATIC_MUT: u32 = 101;
-        fn test() {
-            static LOCAL_STATIC: u32 = 99;
-            static mut LOCAL_STATIC_MUT: u32 = 99;
-            let x = LOCAL_STATIC;
-            let y = LOCAL_STATIC_MUT;
-            let z = GLOBAL_STATIC;
-            let w = GLOBAL_STATIC_MUT;
-        }
-        "#,
+static GLOBAL_STATIC: u32 = 101;
+static mut GLOBAL_STATIC_MUT: u32 = 101;
+fn test() {
+    static LOCAL_STATIC: u32 = 99;
+    static mut LOCAL_STATIC_MUT: u32 = 99;
+    let x = LOCAL_STATIC;
+    let y = LOCAL_STATIC_MUT;
+    let z = GLOBAL_STATIC;
+    let w = GLOBAL_STATIC_MUT;
+}
+"#,
         expect![[r#"
             28..31 '101': u32
             69..72 '101': u32
@@ -1751,6 +1751,41 @@ fn infer_static() {
     );
 }
 
+#[test]
+fn infer_enum_variant() {
+    check_infer(
+        r#"
+enum Foo {
+    A = 15,
+    B = Foo::A as isize + 1
+}
+"#,
+        expect![[r#"
+            19..21 '15': isize
+            31..37 'Foo::A': Foo
+            31..46 'Foo::A as isize': isize
+            31..50 'Foo::A...ze + 1': isize
+            49..50 '1': isize
+        "#]],
+    );
+    check_infer(
+        r#"
+#[repr(u32)]
+enum Foo {
+    A = 15,
+    B = Foo::A as u32 + 1
+}
+"#,
+        expect![[r#"
+            32..34 '15': u32
+            44..50 'Foo::A': Foo
+            44..57 'Foo::A as u32': u32
+            44..61 'Foo::A...32 + 1': u32
+            60..61 '1': u32
+        "#]],
+    );
+}
+
 #[test]
 fn shadowing_primitive() {
     check_types(

From c2dc32c48e8a7027390738b63e88fe220e4e56d9 Mon Sep 17 00:00:00 2001
From: harudagondi 
Date: Wed, 21 Sep 2022 09:11:02 +0800
Subject: [PATCH 029/175] return None instead of assert

---
 crates/ide-assists/src/handlers/unwrap_tuple.rs | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/crates/ide-assists/src/handlers/unwrap_tuple.rs b/crates/ide-assists/src/handlers/unwrap_tuple.rs
index 171e9214a4e6..25c58d086e97 100644
--- a/crates/ide-assists/src/handlers/unwrap_tuple.rs
+++ b/crates/ide-assists/src/handlers/unwrap_tuple.rs
@@ -44,10 +44,14 @@ pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
         _ => return None,
     };
 
-    stdx::always!(
-        tuple_pat.fields().count() == tuple_init.fields().count(),
-        "Length of tuples in pattern and initializer do not match"
-    );
+    if tuple_pat.fields().count() != tuple_init.fields().count() {
+        return None;
+    }
+    if let Some(tys) = &tuple_ty {
+        if tuple_pat.fields().count() != tys.fields().count() {
+            return None;
+        }
+    }
 
     let parent = let_kw.parent()?;
 
@@ -61,11 +65,6 @@ pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
             // If there is an ascribed type, insert that type for each declaration,
             // otherwise, omit that type.
             if let Some(tys) = tuple_ty {
-                stdx::always!(
-                    tuple_pat.fields().count() == tys.fields().count(),
-                    "Length of tuples in patterns and type do not match"
-                );
-
                 let mut zipped_decls = String::new();
                 for (pat, ty, expr) in
                     itertools::izip!(tuple_pat.fields(), tys.fields(), tuple_init.fields())

From 9ede5f073564f140194229546fc2bf5eb6267b62 Mon Sep 17 00:00:00 2001
From: Ryo Yoshida 
Date: Wed, 21 Sep 2022 22:04:55 +0900
Subject: [PATCH 030/175] Implement `HirDisplay` for `TyKind::Generator`

---
 crates/hir-ty/src/display.rs      | 31 ++++++++++++++++++++++++++++++-
 crates/hir-ty/src/tests/simple.rs | 12 ++++++------
 2 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index d2f9c2b8b1e1..71763430ea38 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -20,6 +20,7 @@ use hir_def::{
 };
 use hir_expand::{hygiene::Hygiene, name::Name};
 use itertools::Itertools;
+use smallvec::SmallVec;
 use syntax::SmolStr;
 
 use crate::{
@@ -221,6 +222,7 @@ pub enum DisplaySourceCodeError {
     PathNotFound,
     UnknownType,
     Closure,
+    Generator,
 }
 
 pub enum HirDisplayError {
@@ -782,7 +784,34 @@ impl HirDisplay for Ty {
                 write!(f, "{{unknown}}")?;
             }
             TyKind::InferenceVar(..) => write!(f, "_")?,
-            TyKind::Generator(..) => write!(f, "{{generator}}")?,
+            TyKind::Generator(_, subst) => {
+                if f.display_target.is_source_code() {
+                    return Err(HirDisplayError::DisplaySourceCodeError(
+                        DisplaySourceCodeError::Generator,
+                    ));
+                }
+
+                let subst = subst.as_slice(Interner);
+                let a: Option> = subst
+                    .get(subst.len() - 3..)
+                    .map(|args| args.iter().map(|arg| arg.ty(Interner)).collect())
+                    .flatten();
+
+                if let Some([resume_ty, yield_ty, ret_ty]) = a.as_deref() {
+                    write!(f, "|")?;
+                    resume_ty.hir_fmt(f)?;
+                    write!(f, "|")?;
+
+                    write!(f, " yields ")?;
+                    yield_ty.hir_fmt(f)?;
+
+                    write!(f, " -> ")?;
+                    ret_ty.hir_fmt(f)?;
+                } else {
+                    // This *should* be unreachable, but fallback just in case.
+                    write!(f, "{{generator}}")?;
+                }
+            }
             TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
         }
         Ok(())
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index e6ff0762caa5..b42c5fe7fc41 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -1944,8 +1944,8 @@ fn test() {
             70..71 'v': i64
             78..80 '{}': ()
             91..362 '{     ...   } }': ()
-            101..106 'mut g': {generator}
-            109..218 '|r| { ...     }': {generator}
+            101..106 'mut g': |usize| yields i64 -> &str
+            109..218 '|r| { ...     }': |usize| yields i64 -> &str
             110..111 'r': usize
             113..218 '{     ...     }': &str
             127..128 'a': usize
@@ -1959,11 +1959,11 @@ fn test() {
             187..188 '2': i64
             198..212 '"return value"': &str
             225..360 'match ...     }': ()
-            231..239 'Pin::new': fn new<&mut {generator}>(&mut {generator}) -> Pin<&mut {generator}>
-            231..247 'Pin::n...mut g)': Pin<&mut {generator}>
+            231..239 'Pin::new': fn new<&mut |usize| yields i64 -> &str>(&mut |usize| yields i64 -> &str) -> Pin<&mut |usize| yields i64 -> &str>
+            231..247 'Pin::n...mut g)': Pin<&mut |usize| yields i64 -> &str>
             231..262 'Pin::n...usize)': GeneratorState
-            240..246 '&mut g': &mut {generator}
-            245..246 'g': {generator}
+            240..246 '&mut g': &mut |usize| yields i64 -> &str
+            245..246 'g': |usize| yields i64 -> &str
             255..261 '0usize': usize
             273..299 'Genera...ded(y)': GeneratorState
             297..298 'y': i64

From 40e8f03e11350799097352ead44c3dc6a2c7832f Mon Sep 17 00:00:00 2001
From: Paul Delafosse 
Date: Thu, 22 Sep 2022 05:08:54 +0200
Subject: [PATCH 031/175] docs(guide): fix Analysis and AnalysisHost doc links

---
 docs/dev/guide.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/dev/guide.md b/docs/dev/guide.md
index 808eb5d10bf4..c9ff0b6c29e3 100644
--- a/docs/dev/guide.md
+++ b/docs/dev/guide.md
@@ -40,8 +40,8 @@ terms of files and offsets, and **not** in terms of Rust concepts like structs,
 traits, etc. The "typed" API with Rust specific types is slightly lower in the
 stack, we'll talk about it later.
 
-[`AnalysisHost`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L265-L284
-[`Analysis`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L291-L478
+[`AnalysisHost`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L265-L284
+[`Analysis`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L291-L478
 
 The reason for this separation of `Analysis` and `AnalysisHost` is that we want to apply
 changes "uniquely", but we might also want to fork an `Analysis` and send it to

From 729a9eb5d04df51c6ab6be1964037ddc5e94113f Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Thu, 22 Sep 2022 17:56:58 +0200
Subject: [PATCH 032/175] Fix find_path using the wrong module for visibility
 calculations

---
 crates/hir-def/src/find_path.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs
index b94b50004093..c70e6fdccdcd 100644
--- a/crates/hir-def/src/find_path.rs
+++ b/crates/hir-def/src/find_path.rs
@@ -333,8 +333,8 @@ fn calculate_best_path(
                     db,
                     def_map,
                     visited_modules,
-                    from,
                     crate_root,
+                    from,
                     info.container,
                     max_len - 1,
                     prefixed,

From fb0ce25d59c877eb4e3de07a04fae0aedfe6f33a Mon Sep 17 00:00:00 2001
From: Alan Zimmerman 
Date: Fri, 23 Sep 2022 09:45:24 +0100
Subject: [PATCH 033/175] Add RequestFailed error code, as per spec 3.17

See https://github.com/microsoft/language-server-protocol/issues/1341
---
 lib/lsp-server/src/msg.rs | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/lib/lsp-server/src/msg.rs b/lib/lsp-server/src/msg.rs
index 97e5bd35ce0e..ce00d37beb40 100644
--- a/lib/lsp-server/src/msg.rs
+++ b/lib/lsp-server/src/msg.rs
@@ -135,6 +135,14 @@ pub enum ErrorCode {
     ///
     /// @since 3.17.0
     ServerCancelled = -32802,
+
+    /// A request failed but it was syntactically correct, e.g the
+    /// method name was known and the parameters were valid. The error
+    /// message should contain human readable information about why
+    /// the request failed.
+    ///
+    /// @since 3.17.0
+    RequestFailed = -32803,
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone)]

From 72b3347d000473d06d90fc5112e74d160b65a0e8 Mon Sep 17 00:00:00 2001
From: b-naber 
Date: Fri, 23 Sep 2022 13:23:54 +0200
Subject: [PATCH 034/175] use correct location for type tests in promoted
 consts

---
 compiler/rustc_borrowck/src/type_check/mod.rs | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index d03f03696485..3deffffe8a4f 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -587,6 +587,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         // modify their locations.
         let all_facts = &mut None;
         let mut constraints = Default::default();
+        let mut type_tests = Default::default();
         let mut closure_bounds = Default::default();
         let mut liveness_constraints =
             LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body)));
@@ -598,6 +599,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                 &mut this.cx.borrowck_context.constraints.outlives_constraints,
                 &mut constraints,
             );
+            mem::swap(&mut this.cx.borrowck_context.constraints.type_tests, &mut type_tests);
             mem::swap(
                 &mut this.cx.borrowck_context.constraints.closure_bounds_mapping,
                 &mut closure_bounds,
@@ -622,6 +624,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         swap_constraints(self);
 
         let locations = location.to_locations();
+
+        // Use location of promoted const in collected constraints
+        for type_test in type_tests.iter() {
+            let mut type_test = type_test.clone();
+            type_test.locations = locations;
+            self.cx.borrowck_context.constraints.type_tests.push(type_test)
+        }
         for constraint in constraints.outlives().iter() {
             let mut constraint = constraint.clone();
             constraint.locations = locations;

From 29cc36f84cc68b71f6bc8f8fee786c605a8c5027 Mon Sep 17 00:00:00 2001
From: b-naber 
Date: Fri, 23 Sep 2022 14:03:13 +0200
Subject: [PATCH 035/175] add test

---
 src/test/ui/consts/issue-102117.rs     | 30 +++++++++++++++++++++
 src/test/ui/consts/issue-102117.stderr | 37 ++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)
 create mode 100644 src/test/ui/consts/issue-102117.rs
 create mode 100644 src/test/ui/consts/issue-102117.stderr

diff --git a/src/test/ui/consts/issue-102117.rs b/src/test/ui/consts/issue-102117.rs
new file mode 100644
index 000000000000..b77342c4135e
--- /dev/null
+++ b/src/test/ui/consts/issue-102117.rs
@@ -0,0 +1,30 @@
+#![feature(inline_const, const_type_id)]
+
+use std::alloc::Layout;
+use std::any::TypeId;
+use std::mem::transmute;
+use std::ptr::drop_in_place;
+
+pub struct VTable {
+    layout: Layout,
+    type_id: TypeId,
+    drop_in_place: unsafe fn(*mut ()),
+}
+
+impl VTable {
+    pub fn new() -> &'static Self {
+        const {
+          //~^ ERROR the parameter type `T` may not live long enough
+          //~| ERROR the parameter type `T` may not live long enough
+            &VTable {
+                layout: Layout::new::(),
+                type_id: TypeId::of::(),
+                drop_in_place: unsafe {
+                    transmute::(drop_in_place::)
+                },
+            }
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-102117.stderr b/src/test/ui/consts/issue-102117.stderr
new file mode 100644
index 000000000000..eb4b329bd813
--- /dev/null
+++ b/src/test/ui/consts/issue-102117.stderr
@@ -0,0 +1,37 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/issue-102117.rs:16:9
+   |
+LL | /         const {
+LL | |
+LL | |
+LL | |             &VTable {
+...  |
+LL | |             }
+LL | |         }
+   | |_________^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     pub fn new() -> &'static Self {
+   |                 +++++++++
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/issue-102117.rs:16:9
+   |
+LL | /         const {
+LL | |
+LL | |
+LL | |             &VTable {
+...  |
+LL | |             }
+LL | |         }
+   | |_________^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     pub fn new() -> &'static Self {
+   |                 +++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0310`.

From f57cd838d828cc2a73ac7e133df0e9641dcac9b5 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Fri, 23 Sep 2022 23:30:23 +0200
Subject: [PATCH 036/175] Don't run proc-macro-srv tests on the rust-analyzer
 repo

proc-macro ABI breakage still affects the tests when a new stable version
releases. Ideally we'd still be able to run the tests on the rust-analyzer
repo without having to update the proc-macro ABI, but for now just to
unblock CI we will ignore them here, as they are still run in upstream.
---
 crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs |  2 ++
 crates/proc-macro-srv/src/abis/mod.rs             | 11 +++++++++--
 crates/proc-macro-srv/src/lib.rs                  |  9 +++++++--
 crates/proc-macro-srv/src/tests/mod.rs            | 11 ++---------
 crates/proc-macro-srv/src/tests/utils.rs          | 12 +++---------
 crates/rust-analyzer/tests/slow-tests/main.rs     |  4 +++-
 6 files changed, 26 insertions(+), 23 deletions(-)

diff --git a/crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs b/crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs
index 44712f419191..243972b04997 100644
--- a/crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs
+++ b/crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs
@@ -11,6 +11,8 @@ use proc_macro_api::ProcMacroKind;
 
 use super::PanicMessage;
 
+pub use ra_server::TokenStream;
+
 pub(crate) struct Abi {
     exported_macros: Vec,
 }
diff --git a/crates/proc-macro-srv/src/abis/mod.rs b/crates/proc-macro-srv/src/abis/mod.rs
index f7d3a30919e1..2f854bc15954 100644
--- a/crates/proc-macro-srv/src/abis/mod.rs
+++ b/crates/proc-macro-srv/src/abis/mod.rs
@@ -32,8 +32,8 @@ mod abi_sysroot;
 include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
 
 // Used by `test/utils.rs`
-#[cfg(test)]
-pub(crate) use abi_1_63::TokenStream as TestTokenStream;
+#[cfg(all(test, feature = "sysroot-abi"))]
+pub(crate) use abi_sysroot::TokenStream as TestTokenStream;
 
 use super::dylib::LoadProcMacroDylibError;
 pub(crate) use abi_1_58::Abi as Abi_1_58;
@@ -144,3 +144,10 @@ impl Abi {
         }
     }
 }
+
+#[test]
+fn test_version_check() {
+    let path = paths::AbsPathBuf::assert(crate::proc_macro_test_dylib_path());
+    let info = proc_macro_api::read_dylib_info(&path).unwrap();
+    assert!(info.version.1 >= 50);
+}
diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs
index 3679bfc43c98..72a2dfe72d37 100644
--- a/crates/proc-macro-srv/src/lib.rs
+++ b/crates/proc-macro-srv/src/lib.rs
@@ -20,6 +20,8 @@
 mod dylib;
 mod abis;
 
+pub mod cli;
+
 use std::{
     collections::{hash_map::Entry, HashMap},
     env,
@@ -149,7 +151,10 @@ impl EnvSnapshot {
     }
 }
 
-pub mod cli;
+#[cfg(all(feature = "sysroot-abi", test))]
+mod tests;
 
 #[cfg(test)]
-mod tests;
+pub fn proc_macro_test_dylib_path() -> std::path::PathBuf {
+    proc_macro_test::PROC_MACRO_TEST_LOCATION.into()
+}
diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs
index 6339d56d0179..b46cdddcf6b1 100644
--- a/crates/proc-macro-srv/src/tests/mod.rs
+++ b/crates/proc-macro-srv/src/tests/mod.rs
@@ -2,10 +2,10 @@
 
 #[macro_use]
 mod utils;
-use expect_test::expect;
-use paths::AbsPathBuf;
 use utils::*;
 
+use expect_test::expect;
+
 #[test]
 fn test_derive_empty() {
     assert_expand("DeriveEmpty", r#"struct S;"#, expect![[r#"SUBTREE $"#]]);
@@ -157,10 +157,3 @@ fn list_test_macros() {
         DeriveError [CustomDerive]"#]]
     .assert_eq(&res);
 }
-
-#[test]
-fn test_version_check() {
-    let path = AbsPathBuf::assert(fixtures::proc_macro_test_dylib_path());
-    let info = proc_macro_api::read_dylib_info(&path).unwrap();
-    assert!(info.version.1 >= 50);
-}
diff --git a/crates/proc-macro-srv/src/tests/utils.rs b/crates/proc-macro-srv/src/tests/utils.rs
index f881fe86847d..44b1b6588da0 100644
--- a/crates/proc-macro-srv/src/tests/utils.rs
+++ b/crates/proc-macro-srv/src/tests/utils.rs
@@ -1,15 +1,9 @@
 //! utils used in proc-macro tests
 
-use crate::dylib;
-use crate::ProcMacroSrv;
 use expect_test::Expect;
 use std::str::FromStr;
 
-pub mod fixtures {
-    pub fn proc_macro_test_dylib_path() -> std::path::PathBuf {
-        proc_macro_test::PROC_MACRO_TEST_LOCATION.into()
-    }
-}
+use crate::{dylib, proc_macro_test_dylib_path, ProcMacroSrv};
 
 fn parse_string(code: &str) -> Option {
     // This is a bit strange. We need to parse a string into a token stream into
@@ -30,7 +24,7 @@ pub fn assert_expand_attr(macro_name: &str, ra_fixture: &str, attr_args: &str, e
 }
 
 fn assert_expand_impl(macro_name: &str, input: &str, attr: Option<&str>, expect: Expect) {
-    let path = fixtures::proc_macro_test_dylib_path();
+    let path = proc_macro_test_dylib_path();
     let expander = dylib::Expander::new(&path).unwrap();
     let fixture = parse_string(input).unwrap();
     let attr = attr.map(|attr| parse_string(attr).unwrap().into_subtree());
@@ -40,7 +34,7 @@ fn assert_expand_impl(macro_name: &str, input: &str, attr: Option<&str>, expect:
 }
 
 pub(crate) fn list() -> Vec {
-    let dylib_path = fixtures::proc_macro_test_dylib_path();
+    let dylib_path = proc_macro_test_dylib_path();
     let mut srv = ProcMacroSrv::default();
     let res = srv.list_macros(&dylib_path).unwrap();
     res.into_iter().map(|(name, kind)| format!("{} [{:?}]", name, kind)).collect()
diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs
index 4cc46af1b17c..3e3f1c162f52 100644
--- a/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -18,7 +18,6 @@ mod tidy;
 
 use std::{collections::HashMap, path::PathBuf, time::Instant};
 
-use expect_test::expect;
 use lsp_types::{
     notification::DidOpenTextDocument,
     request::{
@@ -821,7 +820,10 @@ fn main() {
 }
 
 #[test]
+// FIXME: Re-enable once we can run proc-macro tests on rust-lang/rust-analyzer again
+#[cfg(FALSE)]
 fn resolve_proc_macro() {
+    use expect_test::expect;
     if skip_slow_tests() {
         return;
     }

From 7ec9ffa3251504da334a29f0e4331378bc26c54a Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Fri, 23 Sep 2022 22:48:38 +0200
Subject: [PATCH 037/175] Properly support IDE functionality in enum variants

---
 crates/hir-def/src/child_by_source.rs     | 4 ++++
 crates/hir/src/lib.rs                     | 4 ++--
 crates/hir/src/semantics/source_to_def.rs | 2 +-
 3 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/crates/hir-def/src/child_by_source.rs b/crates/hir-def/src/child_by_source.rs
index 5b1435e8f442..bb13165257ba 100644
--- a/crates/hir-def/src/child_by_source.rs
+++ b/crates/hir-def/src/child_by_source.rs
@@ -198,6 +198,10 @@ impl ChildBySource for EnumId {
 impl ChildBySource for DefWithBodyId {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
         let body = db.body(*self);
+        if let &DefWithBodyId::VariantId(v) = self {
+            VariantId::EnumVariantId(v).child_by_source_to(db, res, file_id)
+        }
+
         for (_, def_map) in body.blocks(db) {
             // All block expressions are merged into the same map, because they logically all add
             // inner items to the containing `DefWithBodyId`.
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 1c48d2ff0817..9fcaac85bce0 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -377,10 +377,10 @@ impl ModuleDef {
             ModuleDef::Function(it) => Some(it.into()),
             ModuleDef::Const(it) => Some(it.into()),
             ModuleDef::Static(it) => Some(it.into()),
+            ModuleDef::Variant(it) => Some(it.into()),
 
             ModuleDef::Module(_)
             | ModuleDef::Adt(_)
-            | ModuleDef::Variant(_)
             | ModuleDef::Trait(_)
             | ModuleDef::TypeAlias(_)
             | ModuleDef::Macro(_)
@@ -1160,7 +1160,7 @@ pub enum DefWithBody {
     Const(Const),
     Variant(Variant),
 }
-impl_from!(Function, Const, Static for DefWithBody);
+impl_from!(Function, Const, Static, Variant for DefWithBody);
 
 impl DefWithBody {
     pub fn module(self, db: &dyn HirDatabase) -> Module {
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 87e22c2138b7..fa45e3c12eb0 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -384,7 +384,7 @@ impl SourceToDefCtx<'_, '_> {
         } else {
             let it = ast::Variant::cast(container.value)?;
             let def = self.enum_variant_to_def(InFile::new(container.file_id, it))?;
-            VariantId::from(def).into()
+            DefWithBodyId::from(def).into()
         };
         Some(cont)
     }

From 0231d19f3fba410896d52fa345fe1967c2ea8f55 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Sat, 24 Sep 2022 03:07:05 +0200
Subject: [PATCH 038/175] Fix diagnostics not working in enum variant bodies

---
 crates/hir/src/lib.rs | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 9fcaac85bce0..e1f69001e800 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -50,7 +50,7 @@ use hir_def::{
     resolver::{HasResolver, Resolver},
     src::HasSource as _,
     AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
-    FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
+    EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
     LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
     TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
 };
@@ -348,7 +348,10 @@ impl ModuleDef {
             ModuleDef::Module(it) => it.id.into(),
             ModuleDef::Const(it) => it.id.into(),
             ModuleDef::Static(it) => it.id.into(),
-            _ => return Vec::new(),
+            ModuleDef::Variant(it) => {
+                EnumVariantId { parent: it.parent.into(), local_id: it.id }.into()
+            }
+            ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(),
         };
 
         let module = match self.module(db) {
@@ -537,6 +540,12 @@ impl Module {
                     }
                     acc.extend(decl.diagnostics(db))
                 }
+                ModuleDef::Adt(Adt::Enum(e)) => {
+                    for v in e.variants(db) {
+                        acc.extend(ModuleDef::Variant(v).diagnostics(db));
+                    }
+                    acc.extend(decl.diagnostics(db))
+                }
                 _ => acc.extend(decl.diagnostics(db)),
             }
         }

From 39484ac3b0b80c1c98c4d46a9f88336c02f24da6 Mon Sep 17 00:00:00 2001
From: Josh Triplett 
Date: Sat, 24 Sep 2022 17:20:23 +0100
Subject: [PATCH 039/175] Move style guide to rust-lang/rust

Per [RFC 3309](https://rust-lang.github.io/rfcs/3309-style-team.html).
---
 src/bootstrap/builder.rs               |   1 +
 src/bootstrap/doc.rs                   |   1 +
 src/doc/index.md                       |   6 +
 src/doc/style-guide/book.toml          |   8 +
 src/doc/style-guide/src/README.md      | 190 ++++++
 src/doc/style-guide/src/SUMMARY.md     |  11 +
 src/doc/style-guide/src/advice.md      |  34 +
 src/doc/style-guide/src/cargo.md       |  78 +++
 src/doc/style-guide/src/expressions.md | 850 +++++++++++++++++++++++++
 src/doc/style-guide/src/items.md       | 565 ++++++++++++++++
 src/doc/style-guide/src/principles.md  |  51 ++
 src/doc/style-guide/src/statements.md  | 150 +++++
 src/doc/style-guide/src/types.md       |  58 ++
 13 files changed, 2003 insertions(+)
 create mode 100644 src/doc/style-guide/book.toml
 create mode 100644 src/doc/style-guide/src/README.md
 create mode 100644 src/doc/style-guide/src/SUMMARY.md
 create mode 100644 src/doc/style-guide/src/advice.md
 create mode 100644 src/doc/style-guide/src/cargo.md
 create mode 100644 src/doc/style-guide/src/expressions.md
 create mode 100644 src/doc/style-guide/src/items.md
 create mode 100644 src/doc/style-guide/src/principles.md
 create mode 100644 src/doc/style-guide/src/statements.md
 create mode 100644 src/doc/style-guide/src/types.md

diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index bc6283ef467d..4d1a1e084d52 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -704,6 +704,7 @@ impl<'a> Builder<'a> {
                 doc::Miri,
                 doc::EmbeddedBook,
                 doc::EditionGuide,
+                doc::StyleGuide,
             ),
             Kind::Dist => describe!(
                 dist::Docs,
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 819af6587484..7bdd226cb692 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -82,6 +82,7 @@ book!(
     Reference, "src/doc/reference", "reference", submodule;
     RustByExample, "src/doc/rust-by-example", "rust-by-example", submodule;
     RustdocBook, "src/doc/rustdoc", "rustdoc";
+    StyleGuide, "src/doc/style-guide", "style-guide";
 );
 
 fn open(builder: &Builder<'_>, path: impl AsRef) {
diff --git a/src/doc/index.md b/src/doc/index.md
index 744c7f709a6d..bf08960f338a 100644
--- a/src/doc/index.md
+++ b/src/doc/index.md
@@ -113,6 +113,12 @@ resources useful.
 [The Reference](reference/index.html) is not a formal spec, but is more detailed and
 comprehensive than the book.
 
+## The Style Guide
+
+[The Rust Style Guide](style-guide/index.html) describes the standard formatting of Rust
+code. Most developers use rustfmt to format their code, and rustfmt's default
+formatting matches this style guide.
+
 ## The Rustonomicon
 
 [The Rustonomicon](nomicon/index.html) is your guidebook to the dark arts of unsafe
diff --git a/src/doc/style-guide/book.toml b/src/doc/style-guide/book.toml
new file mode 100644
index 000000000000..056aec8cdd4f
--- /dev/null
+++ b/src/doc/style-guide/book.toml
@@ -0,0 +1,8 @@
+[book]
+title = "The Rust Style Guide"
+author = "The Rust Style Team"
+multilingual = false
+src = "src"
+
+[output.html]
+git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/style-guide/"
diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md
new file mode 100644
index 000000000000..adb73a7eef6e
--- /dev/null
+++ b/src/doc/style-guide/src/README.md
@@ -0,0 +1,190 @@
+# Rust Style Guide
+
+## Motivation - why use a formatting tool?
+
+Formatting code is a mostly mechanical task which takes both time and mental
+effort. By using an automatic formatting tool, a programmer is relieved of
+this task and can concentrate on more important things.
+
+Furthermore, by sticking to an established style guide (such as this one),
+programmers don't need to formulate ad hoc style rules, nor do they need to
+debate with other programmers what style rules should be used, saving time,
+communication overhead, and mental energy.
+
+Humans comprehend information through pattern matching. By ensuring that all
+Rust code has similar formatting, less mental effort is required to comprehend a
+new project, lowering the barrier to entry for new developers.
+
+Thus, there are productivity benefits to using a formatting tool (such as
+rustfmt), and even larger benefits by using a community-consistent formatting,
+typically by using a formatting tool's default settings.
+
+
+## Formatting conventions
+
+### Indentation and line width
+
+* Use spaces, not tabs.
+* Each level of indentation must be four spaces (that is, all indentation
+  outside of string literals and comments must be a multiple of four).
+* The maximum width for a line is 100 characters.
+* A tool should be configurable for all three of these variables.
+
+
+### Blank lines
+
+Separate items and statements by either zero or one blank lines (i.e., one or
+two newlines). E.g,
+
+```rust
+fn foo() {
+    let x = ...;
+
+    let y = ...;
+    let z = ...;
+}
+
+fn bar() {}
+fn baz() {}
+```
+
+Formatting tools should make the bounds on blank lines configurable: there
+should be separate minimum and maximum numbers of newlines between both
+statements and (top-level) items (i.e., four options). As described above, the
+defaults for both statements and items should be minimum: 1, maximum: 2.
+
+
+### [Module-level items](items.md)
+### [Statements](statements.md)
+### [Expressions](expressions.md)
+### [Types](types.md)
+
+
+### Comments
+
+The following guidelines for comments are recommendations only, a mechanical
+formatter might skip formatting of comments.
+
+Prefer line comments (`//`) to block comments (`/* ... */`).
+
+When using line comments there should be a single space after the opening sigil.
+
+When using single-line block comments there should be a single space after the
+opening sigil and before the closing sigil. Multi-line block comments should
+have a newline after the opening sigil and before the closing sigil.
+
+Prefer to put a comment on its own line. Where a comment follows code, there
+should be a single space before it. Where a block comment is inline, there
+should be surrounding whitespace as if it were an identifier or keyword. There
+should be no trailing whitespace after a comment or at the end of any line in a
+multi-line comment. Examples:
+
+```rust
+// A comment on an item.
+struct Foo { ... }
+
+fn foo() {} // A comment after an item.
+
+pub fn foo(/* a comment before an argument */ x: T) {...}
+```
+
+Comments should usually be complete sentences. Start with a capital letter, end
+with a period (`.`). An inline block comment may be treated as a note without
+punctuation.
+
+Source lines which are entirely a comment should be limited to 80 characters
+in length (including comment sigils, but excluding indentation) or the maximum
+width of the line (including comment sigils and indentation), whichever is
+smaller:
+
+```rust
+// This comment goes up to the ................................. 80 char margin.
+
+{
+    // This comment is .............................................. 80 chars wide.
+}
+
+{
+    {
+        {
+            {
+                {
+                    {
+                        // This comment is limited by the ......................... 100 char margin.
+                    }
+                }
+            }
+        }
+    }
+}
+```
+
+#### Doc comments
+
+Prefer line comments (`///`) to block comments (`/** ... */`).
+
+Prefer outer doc comments (`///` or `/** ... */`), only use inner doc comments
+(`//!` and `/*! ... */`) to write module-level or crate-level documentation.
+
+Doc comments should come before attributes.
+
+### Attributes
+
+Put each attribute on its own line, indented to the level of the item.
+In the case of inner attributes (`#!`), indent it to the level of the inside of
+the item. Prefer outer attributes, where possible.
+
+For attributes with argument lists, format like functions.
+
+```rust
+#[repr(C)]
+#[foo(foo, bar)]
+struct CRepr {
+    #![repr(C)]
+    x: f32,
+    y: f32,
+}
+```
+
+For attributes with an equal sign, there should be a single space before and
+after the `=`, e.g., `#[foo = 42]`.
+
+There must only be a single `derive` attribute. Note for tool authors: if
+combining multiple `derive` attributes into a single attribute, the ordering of
+the derived names should be preserved. E.g., `#[derive(bar)] #[derive(foo)]
+struct Baz;` should be formatted to `#[derive(bar, foo)] struct Baz;`.
+
+### *small* items
+
+In many places in this guide we specify that a formatter may format an item
+differently if it is *small*, for example struct literals:
+
+```rust
+// Normal formatting
+Foo {
+    f1: an_expression,
+    f2: another_expression(),
+}
+
+// *small* formatting
+Foo { f1, f2 }
+```
+
+We leave it to individual tools to decide on exactly what *small* means. In
+particular, tools are free to use different definitions in different
+circumstances.
+
+Some suitable heuristics are the size of the item (in characters) or the
+complexity of an item (for example, that all components must be simple names,
+not more complex sub-expressions). For more discussion on suitable heuristics,
+see [this issue](https://github.com/rust-lang-nursery/fmt-rfcs/issues/47).
+
+Tools should give the user an option to ignore such heuristics and always use
+the normal formatting.
+
+
+## [Non-formatting conventions](advice.md)
+
+## [Cargo.toml conventions](cargo.md)
+
+## [Principles used for deciding these guidelines](principles.md)
diff --git a/src/doc/style-guide/src/SUMMARY.md b/src/doc/style-guide/src/SUMMARY.md
new file mode 100644
index 000000000000..004692fa6a22
--- /dev/null
+++ b/src/doc/style-guide/src/SUMMARY.md
@@ -0,0 +1,11 @@
+# Summary
+
+[Introduction](README.md)
+
+- [Module-level items](items.md)
+- [Statements](statements.md)
+- [Expressions](expressions.md)
+- [Types](types.md)
+- [Non-formatting conventions](advice.md)
+- [`Cargo.toml` conventions](cargo.md)
+- [Principles used for deciding these guidelines](principles.md)
diff --git a/src/doc/style-guide/src/advice.md b/src/doc/style-guide/src/advice.md
new file mode 100644
index 000000000000..ab4b92b0a247
--- /dev/null
+++ b/src/doc/style-guide/src/advice.md
@@ -0,0 +1,34 @@
+# Other style advice
+
+## Expressions
+
+Prefer to use Rust's expression oriented nature where possible;
+
+```rust
+// use
+let x = if y { 1 } else { 0 };
+// not
+let x;
+if y {
+    x = 1;
+} else {
+    x = 0;
+}
+```
+
+## Names
+
+ * Types shall be `UpperCamelCase`,
+ * Enum variants shall be `UpperCamelCase`,
+ * Struct fields shall be `snake_case`,
+ * Function and method names shall be `snake_case`,
+ * Local variables shall be `snake_case`,
+ * Macro names shall be `snake_case`,
+ * Constants (`const`s and immutable `static`s) shall be `SCREAMING_SNAKE_CASE`.
+ * When a name is forbidden because it is a reserved word (e.g., `crate`), use a
+   trailing underscore to make the name legal (e.g., `crate_`), or use raw
+   identifiers if possible.
+
+### Modules
+
+Avoid `#[path]` annotations where possible.
diff --git a/src/doc/style-guide/src/cargo.md b/src/doc/style-guide/src/cargo.md
new file mode 100644
index 000000000000..f4993ba06a88
--- /dev/null
+++ b/src/doc/style-guide/src/cargo.md
@@ -0,0 +1,78 @@
+# Cargo.toml conventions
+
+## Formatting conventions
+
+Use the same line width and indentation as Rust code.
+
+Put a blank line between the last key-value pair in a section and the header of
+the next section. Do not place a blank line between section headers and the
+key-value pairs in that section, or between key-value pairs in a section.
+
+Sort key names alphabetically within each section, with the exception of the
+`[package]` section. Put the `[package]` section at the top of the file; put
+the `name` and `version` keys in that order at the top of that section,
+followed by the remaining keys other than `description` in alphabetical order,
+followed by the `description` at the end of that section.
+
+Don't use quotes around any standard key names; use bare keys. Only use quoted
+keys for non-standard keys whose names require them, and avoid introducing such
+key names when possible.  See the [TOML
+specification](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md#table)
+for details.
+
+Put a single space both before and after the `=` between a key and value. Do
+not indent any key names; start all key names at the start of a line.
+
+Use multi-line strings (rather than newline escape sequences) for any string
+values that include multiple lines, such as the crate description.
+
+For array values, such as a list of authors, put the entire list on the same
+line as the key, if it fits. Otherwise, use block indentation: put a newline
+after the opening square bracket, indent each item by one indentation level,
+put a comma after each item (including the last), and put the closing square
+bracket at the start of a line by itself after the last item.
+
+```rust
+authors = [
+    "A Uthor ",
+    "Another Author ",
+]
+```
+
+For table values, such as a crate dependency with a path, write the entire
+table using curly braces and commas on the same line as the key if it fits. If
+the entire table does not fit on the same line as the key, separate it out into
+a separate section with key-value pairs:
+
+```toml
+[dependencies]
+crate1 = { path = "crate1", version = "1.2.3" }
+
+[dependencies.extremely_long_crate_name_goes_here]
+path = "extremely_long_path_name_goes_right_here"
+version = "4.5.6"
+```
+
+## Metadata conventions
+
+The authors list should consist of strings that each contain an author name
+followed by an email address in angle brackets: `Full Name `.
+It should not contain bare email addresses, or names without email addresses.
+(The authors list may also include a mailing list address without an associated
+name.)
+
+The license field must contain a valid [SPDX
+expression](https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60),
+using valid [SPDX license names](https://spdx.org/licenses/). (As an exception,
+by widespread convention, the license field may use `/` in place of ` OR `; for
+example, `MIT/Apache-2.0`.)
+
+The homepage field, if present, must consist of a single URL, including the
+scheme (e.g. `https://example.org/`, not just `example.org`.)
+
+Within the description field, wrap text at 80 columns. Don't start the
+description field with the name of the crate (e.g. "cratename is a ..."); just
+describe the crate itself. If providing a multi-sentence description, the first
+sentence should go on a line by itself and summarize the crate, like the
+subject of an email or commit message; subsequent sentences can then describe
+the crate in more detail.
diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
new file mode 100644
index 000000000000..d4352ef1c301
--- /dev/null
+++ b/src/doc/style-guide/src/expressions.md
@@ -0,0 +1,850 @@
+## Expressions
+
+### Blocks
+
+A block expression should have a newline after the initial `{` and before the
+terminal `}`. Any qualifier before the block (e.g., `unsafe`) should always be
+on the same line as the opening brace, and separated with a single space. The
+contents of the block should be block indented:
+
+```rust
+fn block_as_stmt() {
+    a_call();
+
+    {
+        a_call_inside_a_block();
+
+        // a comment in a block
+        the_value
+    }
+}
+
+fn block_as_expr() {
+    let foo = {
+        a_call_inside_a_block();
+
+        // a comment in a block
+        the_value
+    };
+}
+
+fn unsafe_block_as_stmt() {
+    a_call();
+
+    unsafe {
+        a_call_inside_a_block();
+
+        // a comment in a block
+        the_value
+    }
+}
+```
+
+If a block has an attribute, it should be on its own line:
+
+```rust
+fn block_as_stmt() {
+    #[an_attribute]
+    {
+        #![an_inner_attribute]
+
+        // a comment in a block
+        the_value
+    }
+}
+```
+
+Avoid writing comments on the same line as the braces.
+
+An empty block should be written as `{}`.
+
+A block may be written on a single line if:
+
+* it is either used in expression position (not statement position) or is an
+  unsafe block in statement position
+* contains a single-line expression and no statements
+* contains no comments
+
+A single line block should have spaces after the opening brace and before the
+closing brace.
+
+Examples:
+
+```rust
+fn main() {
+    // Single line
+    let _ = { a_call() };
+    let _ = unsafe { a_call() };
+
+    // Not allowed on one line
+    // Statement position.
+    {
+        a_call()
+    }
+
+    // Contains a statement
+    let _ = {
+        a_call();
+    };
+    unsafe {
+        a_call();
+    }
+
+    // Contains a comment
+    let _ = {
+        // A comment
+    };
+    let _ = {
+        // A comment
+        a_call()
+    };
+
+    // Multiple lines
+    let _ = {
+        a_call();
+        another_call()
+    };
+    let _ = {
+        a_call(
+            an_argument,
+            another_arg,
+        )
+    };
+}
+```
+
+
+### Closures
+
+Don't put any extra spaces before the first `|` (unless the closure is prefixed
+by `move`); put a space between the second `|` and the expression of the
+closure. Between the `|`s, you should use function definition syntax, however,
+elide types where possible.
+
+Use closures without the enclosing `{}`, if possible. Add the `{}` when you have
+a return type, when there are statements, there are comments in the body, or the
+body expression spans multiple lines and is a control-flow expression. If using
+braces, follow the rules above for blocks. Examples:
+
+```rust
+|arg1, arg2| expr
+
+move |arg1: i32, arg2: i32| -> i32 {
+    expr1;
+    expr2
+}
+
+|| Foo {
+    field1,
+    field2: 0,
+}
+
+|| {
+    if true {
+        blah
+    } else {
+        boo
+    }
+}
+
+|x| unsafe {
+    expr
+}
+```
+
+
+### Struct literals
+
+If a struct literal is *small* it may be formatted on a single line. If not,
+each field should be on it's own, block-indented line. There should be a
+trailing comma in the multi-line form only. There should be a space after the
+colon only.
+
+There should be a space before the opening brace. In the single-line form there
+should be spaces after the opening brace and before the closing brace.
+
+```rust
+Foo { field1, field2: 0 }
+let f = Foo {
+    field1,
+    field2: an_expr,
+};
+```
+
+Functional record update syntax is treated like a field, but it must never have
+a trailing comma. There should be no space after `..`.
+
+let f = Foo {
+    field1,
+    ..an_expr
+};
+
+
+### Tuple literals
+
+Use a single-line form where possible. There should not be spaces around the
+parentheses. Where a single-line form is not possible, each element of the tuple
+should be on its own block-indented line and there should be a trailing comma.
+
+```rust
+(a, b, c)
+
+let x = (
+    a_long_expr,
+    another_very_long_expr,
+);
+```
+
+
+### Tuple struct literals
+
+There should be no space between the identifier and the opening parenthesis.
+Otherwise, follow the rules for tuple literals, e.g., `Foo(a, b)`.
+
+
+### Enum literals
+
+Follow the formatting rules for the various struct literals. Prefer using the
+name of the enum as a qualifying name, unless the enum is in the prelude. E.g.,
+
+```rust
+Foo::Bar(a, b)
+Foo::Baz {
+    field1,
+    field2: 1001,
+}
+Ok(an_expr)
+```
+
+
+### Array literals
+
+For simple array literals, avoid line breaking, no spaces around square
+brackets, contents of the array should be separated by commas and spaces. If
+using the repeating initialiser, there should be a space after the semicolon
+only. Apply the same rules if using the `vec!` or similar macros (always use
+square brackets here). Examples:
+
+```rust
+fn main() {
+    [1, 2, 3];
+    vec![a, b, c, d];
+    let a = [42; 10];
+}
+```
+
+If a line must be broken, prefer breaking only after the `;`, if possible.
+Otherwise, follow the rules below for function calls. In any case, the contents
+of the initialiser should be block indented and there should be line breaks
+after the opening bracket and before the closing bracket:
+
+```rust
+fn main() {
+    [
+        a_long_expression();
+        1234567890
+    ]
+    let x = [
+        an_expression,
+        another_expression,
+        a_third_expression,
+    ];
+}
+```
+
+
+### Array accesses, indexing, and slicing.
+
+No spaces around the square brackets, avoid breaking lines if possible, never
+break a line between the target expression and the opening bracket. If the
+indexing expression covers multiple lines, then it should be block indented and
+there should be newlines after the opening brackets and before the closing
+bracket. However, this should be avoided where possible.
+
+Examples:
+
+```rust
+fn main() {
+    foo[42];
+    &foo[..10];
+    bar[0..100];
+    foo[4 + 5 / bar];
+    a_long_target[
+        a_long_indexing_expression
+    ];
+}
+```
+
+### Unary operations
+
+Do not include a space between a unary op and its operand (i.e., `!x`, not
+`! x`). However, there must be a space after `&mut`. Avoid line-breaking
+between a unary operator and its operand.
+
+### Binary operations
+
+Do include spaces around binary ops (i.e., `x + 1`, not `x+1`) (including `=`
+and other assignment operators such as `+=` or `*=`).
+
+For comparison operators, because for `T op U`, `&T op &U` is also implemented:
+if you have `t: &T`, and `u: U`, prefer `*t op u` to `t op &u`. In general,
+within expressions, prefer dereferencing to taking references.
+
+Use parentheses liberally, do not necessarily elide them due to precedence.
+Tools should not automatically insert or remove parentheses. Do not use spaces
+to indicate precedence.
+
+If line-breaking, put the operator on a new line and block indent. Put each 
+sub-expression on its own line. E.g.,
+
+```rust
+foo_bar
+    + bar
+    + baz
+    + qux
+    + whatever
+```
+
+Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather
+than at other binary operators.
+
+### Control flow
+
+Do not include extraneous parentheses for `if` and `while` expressions.
+
+```rust
+if true {
+}
+```
+
+is better than
+
+```rust
+if (true) {
+}
+```
+
+Do include extraneous parentheses if it makes an arithmetic or logic expression
+easier to understand (`(x * 15) + (y * 20)` is fine)
+
+### Function calls
+
+Do not put a space between the function name, and the opening parenthesis.
+
+Do not put a space between an argument, and the comma which follows.
+
+Do put a space between an argument, and the comma which precedes it.
+
+Prefer not to break a line in the callee expression.
+
+#### Single-line calls
+
+Do not put a space between the function name and open paren, between the open
+paren and the first argument, or between the last argument and the close paren.
+
+Do not put a comma after the last argument.
+
+```rust
+foo(x, y, z)
+```
+
+#### Multi-line calls
+
+If the function call is not *small*, it would otherwise over-run the max width,
+or any argument or the callee is multi-line, then the call should be formatted
+across multiple lines. In this case, each argument should be on it's own block-
+indented line, there should be a newline after the opening parenthesis and
+before the closing parenthesis, and there should be a trailing comma. E.g.,
+
+```rust
+a_function_call(
+    arg1,
+    a_nested_call(a, b),
+)
+```
+
+
+### Method calls
+
+Follow the function rules for calling.
+
+Do not put any spaces around the `.`.
+
+```rust
+x.foo().bar().baz(x, y, z);
+```
+
+
+### Macro uses
+
+Macros which can be parsed like other constructs should be formatted like those
+constructs. For example, a macro use `foo!(a, b, c)` can be parsed like a
+function call (ignoring the `!`), therefore it should be formatted following the
+rules for function calls.
+
+#### Special case macros
+
+Macros which take a format string and where all other arguments are *small* may
+be formatted with arguments before and after the format string on a single line
+and the format string on its own line, rather than putting each argument on its
+own line. For example,
+
+```rust
+println!(
+    "Hello {} and {}",
+    name1, name2,
+);
+
+assert_eq!(
+    x, y,
+    "x and y were not equal, see {}",
+    reason,
+);
+```
+
+
+### Casts (`as`)
+
+Put spaces before and after `as`:
+
+```rust
+let cstr = "Hi\0" as *const str as *const [u8] as *const std::os::raw::c_char;
+```
+
+
+### Chains of fields and method calls
+
+A chain is a sequence of field accesses and/or method calls. A chain may also
+include the try operator ('?'). E.g., `a.b.c().d` or `foo?.bar().baz?`.
+
+Prefer formatting on one line if possible, and the chain is *small*. If
+formatting on multiple lines, each field access or method call in the chain
+should be on its own line with the line-break before the `.` and after any `?`.
+Each line should be block-indented. E.g.,
+
+```rust
+let foo = bar
+    .baz?
+    .qux();
+```
+
+If the length of the last line of the first element plus its indentation is
+less than or equal to the indentation of the second line (and there is space),
+then combine the first and second lines, e.g.,
+
+```rust
+x.baz?
+    .qux()
+
+let foo = x
+    .baz?
+    .qux();
+
+foo(
+    expr1,
+    expr2,
+).baz?
+    .qux();
+```
+
+#### Multi-line elements
+
+If any element in a chain is formatted across multiple lines, then that element
+and any later elements must be on their own line. Earlier elements may be kept
+on a single line. E.g.,
+
+```rust
+a.b.c()?.d
+    .foo(
+        an_expr,
+        another_expr,
+    )
+    .bar
+    .baz
+```
+
+Note there is block indent due to the chain and the function call in the above
+example.
+
+Prefer formatting the whole chain in multi-line style and each element on one
+line, rather than putting some elements on multiple lines and some on a single
+line, e.g.,
+
+```rust
+// Better
+self.pre_comment
+    .as_ref()
+    .map_or(false, |comment| comment.starts_with("//"))
+
+// Worse
+self.pre_comment.as_ref().map_or(
+    false,
+    |comment| comment.starts_with("//"),
+)
+```
+
+### Control flow expressions
+
+This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for`
+expressions.
+
+The keyword, any initial clauses, and the opening brace of the block should be
+on a single line. The usual rules for [block formatting](#Blocks) should be
+applied to the block.
+
+If there is an `else` component, then the closing brace, `else`, any following
+clause, and the opening brace should all be on the same line. There should be a
+single space before and after the `else` keyword. For example:
+
+```rust
+if ... {
+    ...
+} else {
+    ...
+}
+
+if let ... {
+    ...
+} else if ... {
+    ...
+} else {
+    ...
+}
+```
+
+If the control line needs to be broken, then prefer to break before the `=` in
+`* let` expressions and before `in` in a `for` expression; the following line
+should be block indented. If the control line is broken for any reason, then the
+opening brace should be on its own line and not indented. Examples:
+
+```rust
+while let Some(foo)
+    = a_long_expression
+{
+    ...
+}
+
+for foo
+    in a_long_expression
+{
+    ...
+}
+
+if a_long_expression
+    && another_long_expression
+    || a_third_long_expression
+{
+    ...
+}
+```
+
+Where the initial clause is multi-lined and ends with one or more closing
+parentheses, square brackets, or braces, and there is nothing else on that line,
+and that line is not indented beyond the indent on the first line of the control
+flow expression, then the opening brace of the block should be put on the same
+line with a preceding space. For example:
+
+```rust
+if !self.config.file_lines().intersects(
+    &self.codemap.lookup_line_range(
+        stmt.span,
+    ),
+) {  // Opening brace on same line as initial clause.
+    ...
+}
+```
+
+
+#### Single line `if else`
+
+Formatters may place an `if else` or `if let else` on a single line if it occurs
+in expression context (i.e., is not a standalone statement), it contains a
+single `else` clause, and is *small*. For example:
+
+```rust
+let y = if x { 0 } else { 1 };
+
+// Examples that must be multi-line.
+let y = if something_very_long {
+    not_small
+} else {
+    also_not_small
+};
+
+if x {
+    0
+} else {
+    1
+}
+```
+
+
+### Match
+
+Prefer not to line-break inside the discriminant expression. There must always
+be a line break after the opening brace and before the closing brace. The match
+arms must be block indented once:
+
+```rust
+match foo {
+    // arms
+}
+
+let x = match foo.bar.baz() {
+    // arms
+};
+```
+
+Use a trailing comma for a match arm if and only if not using a block. 
+
+Never start a match arm pattern with `|`, e.g.,
+
+```rust
+match foo {
+    // Don't do this.
+    | foo => bar,
+    // Or this.
+    | a_very_long_pattern
+    | another_pattern
+    | yet_another_pattern
+    | a_forth_pattern => {
+        ...
+    }
+}
+```
+
+Prefer
+
+
+```rust
+match foo {
+    foo => bar,
+    a_very_long_pattern
+    | another_pattern
+    | yet_another_pattern
+    | a_forth_pattern => {
+        ...
+    }
+}
+```
+
+Avoid splitting the left-hand side (before the `=>`) of a match arm where
+possible. If the right-hand side of the match arm is kept on the same line,
+never use a block (unless the block is empty).
+
+If the right-hand side consists of multiple statements or has line comments or
+the start of the line cannot be fit on the same line as the left-hand side, use
+a block.
+
+The body of a block arm should be block indented once.
+
+Examples:
+
+```rust
+match foo {
+    foo => bar,
+    a_very_long_patten | another_pattern if an_expression() => {
+        no_room_for_this_expression()
+    }
+    foo => {
+        // A comment.
+        an_expression()
+    }
+    foo => {
+        let a = statement();
+        an_expression()
+    }
+    bar => {}
+    // Trailing comma on last item.
+    foo => bar,
+}
+```
+
+If the body is a single expression with no line comments and not a control flow
+expression, then it may be started on the same line as the right-hand side. If
+not, then it must be in a block. Example,
+
+```rust
+match foo {
+    // A combinable expression.
+    foo => a_function_call(another_call(
+        argument1,
+        argument2,
+    )),
+    // A non-combinable expression
+    bar => {
+        a_function_call(
+            another_call(
+                argument1,
+                argument2,
+            ),
+            another_argument,
+        )
+    }
+}
+```
+
+#### Line-breaking
+
+Where it is possible to use a block form on the right-hand side and avoid
+breaking the left-hand side, do that. E.g.
+
+```rust
+    // Assuming the following line does done fit in the max width
+    a_very_long_pattern | another_pattern => ALongStructName {
+        ...
+    },
+    // Prefer this
+    a_very_long_pattern | another_pattern => {
+        ALongStructName {
+            ...
+        }
+    }
+    // To splitting the pattern.
+```
+
+Never break after `=>` without using the block form of the body.
+
+If the left-hand side must be split and there is an `if` clause, break before
+the `if` and block indent. In this case, always use a block body and start the
+body on a new line:
+
+```rust
+    a_very_long_pattern | another_pattern
+        if expr =>
+    {
+        ...
+    }
+```
+
+If required to break the pattern, put each clause of the pattern on its own
+line with no additional indent, breaking before the `|`. If there is an `if`
+clause, then you must use the above form:
+
+```rust
+    a_very_long_pattern
+    | another_pattern
+    | yet_another_pattern
+    | a_forth_pattern => {
+        ...
+    }
+    a_very_long_pattern
+    | another_pattern
+    | yet_another_pattern
+    | a_forth_pattern
+        if expr =>
+    {
+        ...
+    }
+```
+
+If the pattern is multi-line, and the last line is less wide than the indent, do
+not put the `if` clause on a newline. E.g.,
+
+```rust
+    Token::Dimension {
+         value,
+         ref unit,
+         ..
+    } if num_context.is_ok(context.parsing_mode, value) => {
+        ...
+    }
+```
+
+If every clause in a pattern is *small*, but does not fit on one line, then the
+pattern may be formatted across multiple lines with as many clauses per line as
+possible. Again break before a `|`:
+
+```rust
+    foo | bar | baz
+    | qux => {
+        ...
+    }
+```
+
+We define a pattern clause to be *small* if it matches the following grammar:
+
+```
+[small, ntp]:
+    - single token
+    - `&[single-line, ntp]`
+
+[small]:
+    - `[small, ntp]`
+    - unary tuple constructor `([small, ntp])`
+    - `&[small]`
+```
+
+E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not.
+
+
+### Combinable expressions
+
+Where a function call has a single argument, and that argument is formatted
+across multiple-lines, the outer call may be formatted as if it were a single-
+line call. The same combining behaviour may be applied to any similar
+expressions which have multi-line, block-indented lists of sub-expressions
+delimited by parentheses (e.g., macros or tuple struct literals). E.g.,
+
+```rust
+foo(bar(
+    an_expr,
+    another_expr,
+))
+
+let x = foo(Bar {
+    field: whatever,
+});
+
+foo(|param| {
+    action();
+    foo(param)
+})
+```
+
+Such behaviour should extend recursively, however, tools may choose to limit the
+depth of nesting.
+
+Only where the multi-line sub-expression is a closure with an explicit block,
+this combining behaviour may be used where there are other arguments, as long as
+all the arguments and the first line of the closure fit on the first line, the
+closure is the last argument, and there is only one closure argument:
+
+```rust
+foo(first_arg, x, |param| {
+    action();
+    foo(param)
+})
+```
+
+
+### Ranges
+
+Do not put spaces in ranges, e.g., `0..10`, `x..=y`, `..x.len()`, `foo..`.
+
+When writing a range with both upper and lower bounds, if the line must be
+broken, break before the range operator and block indent the second line:
+
+```rust
+a_long_expression
+    ..another_long_expression
+```
+
+For the sake of indicating precedence, we recommend that if either bound is a
+compound expression, then use parentheses around it, e.g., `..(x + 1)`,
+`(x.f)..(x.f.len())`, or `0..(x - 10)`.
+
+
+### Hexadecimal literals
+
+Hexadecimal literals may use upper- or lower-case letters, but they must not be
+mixed within the same literal. Projects should use the same case for all
+literals, but we do not make a recommendation for either lower- or upper-case.
+Tools should have an option to convert mixed case literals to upper-case, and
+may have an option to convert all literals to either lower- or upper-case.
+
+
+## Patterns
+
+Patterns should be formatted like their corresponding expressions. See the
+section on `match` for additional formatting for patterns in match arms.
diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md
new file mode 100644
index 000000000000..324071eb39a5
--- /dev/null
+++ b/src/doc/style-guide/src/items.md
@@ -0,0 +1,565 @@
+## Items
+
+`extern crate` statements must be first in a file. They must be ordered
+alphabetically.
+
+`use` statements, and module *declarations* (`mod foo;`, not `mod { ... }`)
+must come before other items. We recommend that imports come before module
+declarations; if imports and modules are separated, then they should be ordered
+alphabetically. When sorting, `self` and `super` must come before any other
+names. Module declarations should not be moved if they are annotated with
+`#[macro_use]`, since that may be semantics changing.
+
+Tools should make the above ordering optional.
+
+
+### Function definitions
+
+In Rust, one finds functions by searching for `fn [function-name]`; It's
+important that you style your code so that it's very searchable in this way.
+
+The proper ordering and spacing is:
+
+```rust
+[pub] [unsafe] [extern ["ABI"]] fn foo(arg1: i32, arg2: i32) -> i32 {
+    ...
+}
+```
+
+Avoid comments within the signature itself.
+
+If the function signature does not fit on one line, then break after the opening
+parenthesis and before the closing parenthesis and put each argument on its own
+block-indented line. For example,
+
+```rust
+fn foo(
+    arg1: i32,
+    arg2: i32,
+) -> i32 {
+    ...
+}
+```
+
+Note the trailing comma on the last argument.
+
+
+### Tuples and tuple structs
+
+Write the type list as you would a parameter list to a function.
+
+Build a tuple or tuple struct as you would call a function.
+
+#### Single-line
+
+```rust
+struct Bar(Type1, Type2);
+
+let x = Bar(11, 22);
+let y = (11, 22, 33);
+```
+
+### Enums
+
+In the declaration, put each variant on its own line, block indented.
+
+Format each variant accordingly as either a struct, tuple struct, or identifier,
+which doesn't require special formatting (but without the `struct` keyword.
+
+```rust
+enum FooBar {
+    First(u32),
+    Second,
+    Error {
+        err: Box,
+        line: u32,
+    },
+}
+```
+
+If a struct variant is [*small*](#small-items), it may be formatted on
+one line. In this case, do not use a trailing comma for the field list, but do
+put spaces around each brace:
+
+```rust
+enum FooBar {
+    Error { err: Box, line: u32 },
+}
+```
+
+In an enum with multiple struct variants, if any struct variant is written on
+multiple lines, then the multi-line formatting should be used for all struct
+variants. However, such a situation might be an indication that you should
+factor out the fields of the variant into their own struct.
+
+
+### Structs and Unions
+
+Struct names follow on the same line as the `struct` keyword, with the opening
+brace on the same line when it fits within the right margin. All struct fields
+are indented once and end with a trailing comma. The closing brace is not
+indented and appears on its own line.
+
+```rust
+struct Foo {
+    a: A,
+    b: B,
+}
+```
+
+If and only if the type of a field does not fit within the right margin, it is
+pulled down to its own line and indented again.
+
+```rust
+struct Foo {
+    a: A,
+    long_name: 
+        LongType,
+}
+```
+
+Prefer using a unit struct (e.g., `struct Foo;`) to an empty struct (e.g.,
+`struct Foo();` or `struct Foo {}`, these only exist to simplify code
+generation), but if you must use an empty struct, keep it on one line with no
+space between the braces: `struct Foo;` or `struct Foo {}`.
+
+The same guidelines are used for untagged union declarations.
+
+```rust
+union Foo {
+    a: A,
+    b: B,
+    long_name: 
+        LongType,
+}
+```
+
+
+### Tuple structs
+
+Put the whole struct on one line if possible. Types in the parentheses should be
+separated by a comma and space with no trailing comma. No spaces around the
+parentheses or semi-colon:
+
+```rust
+pub struct Foo(String, u8);
+```
+
+Prefer unit structs to empty tuple structs (these only exist to simplify code
+generation), e.g., `struct Foo;` rather than `struct Foo();`.
+
+For more than a few fields, prefer a proper struct with named fields. Given
+this, a tuple struct should always fit on one line. If it does not, block format
+the fields with a field on each line and a trailing comma:
+
+```rust
+pub struct Foo(
+    String,
+    u8,
+);
+```
+
+
+### Traits
+
+Trait items should be block-indented. If there are no items, the trait may be
+formatted on a single line. Otherwise there should be line-breaks after the
+opening brace and before the closing brace:
+
+```rust
+trait Foo {}
+
+pub trait Bar {
+    ...
+}
+```
+
+If the trait has bounds, there should be a space after the colon but not before
+and before and after each `+`, e.g.,
+
+```rust
+trait Foo: Debug + Bar {}
+```
+
+Prefer not to line-break in the bounds if possible (consider using a `where`
+clause). Prefer to break between bounds than to break any individual bound. If
+you must break the bounds, put each bound (including the first) on its own
+block-indented line, break before the `+` and put the opening brace on its own
+line:
+
+```rust
+pub trait IndexRanges:
+    Index, Output=Self>
+    + Index, Output=Self>
+    + Index, Output=Self>
+    + Index
+{
+    ...
+}
+```
+
+
+### Impls
+
+Impl items should be block indented. If there are no items, the impl may be
+formatted on a single line. Otherwise there should be line-breaks after the
+opening brace and before the closing brace:
+
+```rust
+impl Foo {}
+
+impl Bar for Foo {
+    ...
+}
+```
+
+Avoid line-breaking in the signature if possible. If a line break is required in
+a non-inherent impl, break immediately before `for`, block indent the concrete type
+and put the opening brace on its own line:
+
+```rust
+impl Bar
+    for Foo
+{
+    ...
+}
+```
+
+
+### Extern crate
+
+`extern crate foo;`
+
+Use spaces around keywords, no spaces around the semi-colon.
+
+
+### Modules
+
+```rust
+mod foo {
+}
+```
+
+```rust
+mod foo;
+```
+
+Use spaces around keywords and before the opening brace, no spaces around the
+semi-colon.
+
+### macro\_rules!
+
+Use `{}` for the full definition of the macro.
+
+```rust
+macro_rules! foo {
+}
+```
+
+
+### Generics
+
+Prefer to put a generics clause on one line. Break other parts of an item
+declaration rather than line-breaking a generics clause. If a generics clause is
+large enough to require line-breaking, you should prefer to use a `where` clause
+instead.
+
+Do not put spaces before or after `<` nor before `>`. Only put a space after `>`
+if it is followed by a word or opening brace, not an opening parenthesis. There
+should be a space after each comma and no trailing comma.
+
+```rust
+fn foo(x: Vec, y: Vec) ...
+
+impl SomeType { ...
+```
+
+If the generics clause must be formatted across multiple lines, each parameter
+should have its own block-indented line, there should be newlines after the
+opening bracket and before the closing bracket, and the should be a trailing
+comma.
+
+```rust
+fn foo<
+    T: Display,
+    U: Debug,
+>(x: Vec, y: Vec) ...
+```
+
+If an associated type is bound in a generic type, then there should be spaces on
+either side of the `=`:
+
+```rust
+>
+```
+
+Prefer to use single-letter names for generic parameters.
+
+
+### `where` clauses
+
+These rules apply for `where` clauses on any item.
+
+A `where` clause may immediately follow a closing bracket of any kind.
+Otherwise, it must start a new line, with no indent. Each component of a `where`
+clause must be on its own line and be block indented. There should be a trailing
+comma, unless the clause is terminated with a semicolon. If the `where` clause
+is followed by a block (or assignment), the block should be started on a new
+line. Examples:
+
+```rust
+fn function(args)
+where
+    T: Bound,
+    U: AnotherBound,
+{
+    body
+}
+
+fn foo(
+    args
+) -> ReturnType
+where
+    T: Bound,
+{
+    body
+}
+
+fn foo(
+    args,
+) where
+    T: Bound,
+    U: AnotherBound,
+{
+    body
+}
+
+fn foo(
+    args
+) -> ReturnType
+where
+    T: Bound,
+    U: AnotherBound;  // Note, no trailing comma.
+
+// Note that where clauses on `type` aliases are not enforced and should not
+// be used.
+type Foo
+where
+    T: Bound
+= Bar;
+```
+
+If a `where` clause is very short, we recommend using an inline bound on the
+type parameter.
+
+
+If a component of a `where` clause is long, it may be broken before `+` and
+further block indented. Each bound should go on its own line. E.g.,
+
+```rust
+impl IndexRanges for T
+where
+    T: Index, Output = Self::Output>
+        + Index, Output = Self::Output>
+        + Index, Output = Self::Output>
+        + Index, Output = Self::Output>
+        + Index, Output = Self::Output> + Index
+```
+
+#### Option - `where_single_line`
+
+`where_single_line` is `false` by default. If `true`, then a where clause with
+exactly one component may be formatted on a single line if the rest of the
+item's signature is also kept on one line. In this case, there is no need for a
+trailing comma and if followed by a block, no need for a newline before the
+block. E.g.,
+
+```rust
+// May be single-lined.
+fn foo(args) -> ReturnType
+where T: Bound {
+    body
+}
+
+// Must be multi-lined.
+fn foo(
+    args
+) -> ReturnType
+where
+    T: Bound,
+{
+    body
+}
+```
+
+
+### Type aliases
+
+Type aliases should generally be kept on one line. If necessary to break the
+line, do so after the `=`; the right-hand-side should be block indented:
+
+```rust
+pub type Foo = Bar;
+
+// If multi-line is required
+type VeryLongType =
+    AnEvenLongerType>;
+```
+
+Where possible avoid `where` clauses and keep type constraints inline. Where
+that is not possible split the line before and after the `where` clause (and
+split the `where` clause as normal), e.g.,
+
+```rust
+type VeryLongType
+where
+    T: U::AnAssociatedType,
+    U: SomeBound,
+= AnEvenLongerType>;
+```
+
+
+### Associated types
+
+Associated types should follow the guidelines above for type aliases. Where an
+associated type has a bound, there should be a space after the colon but not
+before:
+
+```rust
+pub type Foo: Bar;
+```
+
+
+### extern items
+
+When writing extern items (such as `extern "C" fn`), always be explicit about
+the ABI. For example, write `extern "C" fn foo ...`, not `extern fn foo ...`, or
+`extern "C" { ... }`.
+
+
+### Imports (`use` statements)
+
+If an import can be formatted on one line, do so. There should be no spaces
+around braces.
+
+```rust
+use a::b::c;
+use a::b::d::*;
+use a::b::{foo, bar, baz};
+```
+
+
+#### Large list imports
+
+Prefer to use multiple imports rather than a multi-line import. However, tools
+should not split imports by default (they may offer this as an option).
+
+If an import does require multiple lines (either because a list of single names
+does not fit within the max width, or because of the rules for nested imports
+below), then break after the opening brace and before the closing brace, use a
+trailing comma, and block indent the names.
+
+
+```rust
+// Prefer
+foo::{long, list, of, imports};
+foo::{more, imports};
+
+// If necessary
+foo::{
+    long, list, of, imports, more,
+    imports,  // Note trailing comma
+};
+```
+
+
+#### Ordering of imports
+
+A *group* of imports is a set of imports on the same or sequential lines. One or
+more blank lines or other items (e.g., a function) separate groups of imports.
+
+Within a group of imports, imports must be sorted ascii-betically. Groups of
+imports must not be merged or re-ordered.
+
+
+E.g., input:
+
+```rust
+use d;
+use c;
+
+use b;
+use a;
+```
+
+output:
+
+```rust
+use c;
+use d;
+
+use a;
+use b;
+```
+
+Because of `macro_use`, attributes must also start a new group and prevent
+re-ordering.
+
+Note that tools which only have access to syntax (such as Rustfmt) cannot tell
+which imports are from an external crate or the std lib, etc.
+
+
+#### Ordering list import
+
+Names in a list import must be sorted ascii-betically, but with `self` and
+`super` first, and groups and glob imports last. This applies recursively. For
+example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g.,
+`use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`.
+
+
+#### Normalisation
+
+Tools must make the following normalisations:
+
+* `use a::self;` -> `use a;`
+* `use a::{};` -> (nothing)
+* `use a::{b};` -> `use a::b;`
+
+And must apply these recursively.
+
+Tools must not otherwise merge or un-merge import lists or adjust glob imports
+(without an explicit option).
+
+
+#### Nested imports
+
+If there are any nested imports in a list import, then use the multi-line form,
+even if the import fits on one line. Each nested import must be on its own line,
+but non-nested imports must be grouped on as few lines as possible.
+
+For example,
+
+```rust
+use a::b::{
+    x, y, z,
+    u::{...},
+    w::{...},
+};
+```
+
+
+#### Merging/un-merging imports
+
+An example:
+
+```rust
+// Un-merged
+use a::b;
+use a::c::d;
+
+// Merged
+use a::{b, c::d};
+```
+
+Tools must not merge or un-merge imports by default. They may offer merging or
+un-merging as an option.
diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md
new file mode 100644
index 000000000000..b02b3c0471f2
--- /dev/null
+++ b/src/doc/style-guide/src/principles.md
@@ -0,0 +1,51 @@
+# Guiding principles and rationale
+
+When deciding on style guidelines, the style team tried to be guided by the
+following principles (in rough priority order):
+
+* readability
+    - scan-ability
+    - avoiding misleading formatting
+    - accessibility - readable and editable by users using the the widest
+      variety of hardware, including non-visual accessibility interfaces
+    - readability of code when quoted in rustc error messages
+
+* aesthetics
+    - sense of 'beauty'
+    - consistent with other languages/tools
+
+* specifics
+    - compatibility with version control practices - preserving diffs,
+      merge-friendliness, etc.
+    - preventing right-ward drift
+    - minimising vertical space
+
+* application
+    - ease of manual application
+    - ease of implementation (in Rustfmt, and in other tools/editors/code generators)
+    - internal consistency
+    - simplicity of formatting rules
+
+
+## Overarching guidelines
+
+Prefer block indent over visual indent. E.g.,
+
+```rust
+// Block indent
+a_function_call(
+    foo,
+    bar,
+);
+
+// Visual indent
+a_function_call(foo,
+                bar);
+```
+
+This makes for smaller diffs (e.g., if `a_function_call` is renamed in the above
+example) and less rightward drift.
+
+Lists should have a trailing comma when followed by a newline, see the block
+indent example above. This choice makes moving code (e.g., by copy and paste)
+easier and makes smaller diffs.
diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md
new file mode 100644
index 000000000000..9c3eba12d2ec
--- /dev/null
+++ b/src/doc/style-guide/src/statements.md
@@ -0,0 +1,150 @@
+### Let statements
+
+There should be spaces after the `:` and on both sides of the `=` (if they are
+present). No space before the semi-colon.
+
+```rust
+// A comment.
+let pattern: Type = expr;
+
+let pattern;
+let pattern: Type;
+let pattern = expr;
+```
+
+If possible the declaration should be formatted on a single line. If this is not
+possible, then try splitting after the `=`, if the declaration can fit on two
+lines. The expression should be block indented.
+
+```rust
+let pattern: Type =
+    expr;
+```
+
+If the first line does not fit on a single line, then split after the colon,
+using block indentation. If the type covers multiple lines, even after line-
+breaking after the `:`, then the first line may be placed on the same line as
+the `:`, subject to the [combining rules](https://github.com/rust-lang-nursery/fmt-rfcs/issues/61) (WIP).
+
+
+```rust
+let pattern:
+    Type =
+    expr;
+```
+
+e.g,
+
+```rust
+let Foo {
+    f: abcd,
+    g: qwer,
+}: Foo =
+    Foo { f, g };
+
+let (abcd,
+    defg):
+    Baz =
+{ ... }
+```
+
+If the expression covers multiple lines, if the first line of the expression
+fits in the remaining space, it stays on the same line as the `=`, the rest of the
+expression is not indented. If the first line does not fit, then it should start
+on the next lines, and should be block indented. If the expression is a block
+and the type or pattern cover multiple lines, then the opening brace should be
+on a new line and not indented (this provides separation for the interior of the
+block from the type), otherwise the opening brace follows the `=`.
+
+Examples:
+
+```rust
+let foo = Foo {
+    f: abcd,
+    g: qwer,
+};
+
+let foo =
+    ALongName {
+        f: abcd,
+        g: qwer,
+    };
+
+let foo: Type = {
+    an_expression();
+    ...
+};
+
+let foo:
+    ALongType =
+{
+    an_expression();
+    ...    
+};
+
+let Foo {
+    f: abcd,
+    g: qwer,
+}: Foo = Foo {
+    f: blimblimblim, 
+    g: blamblamblam,
+};
+
+let Foo {
+    f: abcd,
+    g: qwer,
+}: Foo = foo(
+    blimblimblim,
+    blamblamblam,
+);
+```
+
+
+### Macros in statement position
+
+A macro use in statement position should use parentheses or square brackets as
+delimiters and should be terminated with a semi-colon. There should be no spaces
+between the name, `!`, the delimiters, or the `;`.
+
+```rust
+// A comment.
+a_macro!(...);
+```
+
+
+### Expressions in statement position
+
+There should be no space between the expression and the semi-colon.
+
+```
+;
+```
+
+All expressions in statement position should be terminated with a semi-colon,
+unless they end with a block or are used as the value for a block.
+
+E.g.,
+
+```rust
+{
+    an_expression();
+    expr_as_value()
+}
+
+return foo();
+
+loop {
+    break;
+}
+```
+
+Use a semi-colon where an expression has void type, even if it could be
+propagated. E.g.,
+
+```rust
+fn foo() { ... }
+
+fn bar() {
+    foo();
+}
+```
diff --git a/src/doc/style-guide/src/types.md b/src/doc/style-guide/src/types.md
new file mode 100644
index 000000000000..25861ddabb8d
--- /dev/null
+++ b/src/doc/style-guide/src/types.md
@@ -0,0 +1,58 @@
+## Types and Bounds
+
+### Single line formatting
+
+* `[T]` no spaces
+* `[T; expr]`, e.g., `[u32; 42]`, `[Vec; 10 * 2 + foo()]` (space after colon, no spaces around square brackets)
+* `*const T`, `*mut T` (no space after `*`, space before type)
+* `&'a T`, `&T`, `&'a mut T`, `&mut T` (no space after `&`, single spaces separating other words)
+* `unsafe extern "C" fn<'a, 'b, 'c>(T, U, V) -> W` or `fn()` (single spaces around keyowrds and sigils, and after commas, no trailing commas, no spaces around brackets)
+* `!` should be treated like any other type name, `Name`
+* `(A, B, C, D)` (spaces after commas, no spaces around parens, no trailing comma unless it is a one-tuple)
+* ` as SomeTrait>::Foo::Bar` or `Foo::Bar` or `::Foo::Bar` (no spaces around `::` or angle brackets, single spaces around `as`)
+* `Foo::Bar` (spaces after commas, no trailing comma, no spaces around angle brackets)
+* `T + T + T` (single spaces between types, and `+`).
+* `impl T + T + T` (single spaces between keyword, types, and `+`).
+
+Parentheses used in types should not be surrounded by whitespace, e.g., `(Foo)`
+
+
+### Line breaks
+
+Avoid breaking lines in types where possible. Prefer breaking at outermost scope, e.g., prefer
+
+```rust
+Foo<
+    Bar,
+    Baz,
+>
+```
+
+to
+
+```rust
+Foo>
+```
+
+`[T; expr]` may be broken after the `;` if necessary.
+
+Function types may be broken following the rules for function declarations.
+
+Generic types may be broken following the rules for generics.
+
+Types with `+` may be broken after any `+` using block indent and breaking before the `+`. When breaking such a type, all `+`s should be line broken, e.g.,
+
+```rust
+impl Clone
+    + Copy
+    + Debug
+
+Box<
+    Clone
+    + Copy
+    + Debug
+>
+```

From 9a9e8273e4ba8d308f8ce261a4694dc5b42fac9d Mon Sep 17 00:00:00 2001
From: Josh Triplett 
Date: Sat, 24 Sep 2022 17:25:38 +0100
Subject: [PATCH 040/175] triagebot.toml: Add autolabel for T-style

---
 triagebot.toml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/triagebot.toml b/triagebot.toml
index d358e59c2452..181fb1de9305 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -189,6 +189,11 @@ trigger_files = [
     "src/tools/bump-stage0",
 ]
 
+[autolabel."T-style"]
+trigger_files = [
+    "src/doc/style-guide",
+]
+
 [autolabel."A-translation"]
 trigger_files = [
     "compiler/rustc_error_messages",

From 283c0e43caf6d61f4fdaf1320904cd34d7abff9e Mon Sep 17 00:00:00 2001
From: Josh Triplett 
Date: Sat, 24 Sep 2022 17:40:08 +0100
Subject: [PATCH 041/175] style-guide: Remove trailing space

---
 src/doc/style-guide/src/expressions.md | 4 ++--
 src/doc/style-guide/src/items.md       | 4 ++--
 src/doc/style-guide/src/statements.md  | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
index d4352ef1c301..dfa24549b578 100644
--- a/src/doc/style-guide/src/expressions.md
+++ b/src/doc/style-guide/src/expressions.md
@@ -294,7 +294,7 @@ Use parentheses liberally, do not necessarily elide them due to precedence.
 Tools should not automatically insert or remove parentheses. Do not use spaces
 to indicate precedence.
 
-If line-breaking, put the operator on a new line and block indent. Put each 
+If line-breaking, put the operator on a new line and block indent. Put each
 sub-expression on its own line. E.g.,
 
 ```rust
@@ -595,7 +595,7 @@ let x = match foo.bar.baz() {
 };
 ```
 
-Use a trailing comma for a match arm if and only if not using a block. 
+Use a trailing comma for a match arm if and only if not using a block.
 
 Never start a match arm pattern with `|`, e.g.,
 
diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md
index 324071eb39a5..7439c68d92c7 100644
--- a/src/doc/style-guide/src/items.md
+++ b/src/doc/style-guide/src/items.md
@@ -113,7 +113,7 @@ pulled down to its own line and indented again.
 ```rust
 struct Foo {
     a: A,
-    long_name: 
+    long_name:
         LongType,
 }
 ```
@@ -129,7 +129,7 @@ The same guidelines are used for untagged union declarations.
 union Foo {
     a: A,
     b: B,
-    long_name: 
+    long_name:
         LongType,
 }
 ```
diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md
index 9c3eba12d2ec..29b48bb1ee0b 100644
--- a/src/doc/style-guide/src/statements.md
+++ b/src/doc/style-guide/src/statements.md
@@ -79,14 +79,14 @@ let foo:
     ALongType =
 {
     an_expression();
-    ...    
+    ...
 };
 
 let Foo {
     f: abcd,
     g: qwer,
 }: Foo = Foo {
-    f: blimblimblim, 
+    f: blimblimblim,
     g: blamblamblam,
 };
 

From 9a72a668505f403f2ecdb63fdfd4df315b938c6b Mon Sep 17 00:00:00 2001
From: Josh Triplett 
Date: Sat, 24 Sep 2022 19:55:33 +0100
Subject: [PATCH 042/175] style-guide: Fix broken links

---
 src/doc/style-guide/src/expressions.md | 2 +-
 src/doc/style-guide/src/items.md       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
index dfa24549b578..c7d0446dded1 100644
--- a/src/doc/style-guide/src/expressions.md
+++ b/src/doc/style-guide/src/expressions.md
@@ -489,7 +489,7 @@ This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for`
 expressions.
 
 The keyword, any initial clauses, and the opening brace of the block should be
-on a single line. The usual rules for [block formatting](#Blocks) should be
+on a single line. The usual rules for [block formatting](#blocks) should be
 applied to the block.
 
 If there is an `else` component, then the closing brace, `else`, any following
diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md
index 7439c68d92c7..2835975355fc 100644
--- a/src/doc/style-guide/src/items.md
+++ b/src/doc/style-guide/src/items.md
@@ -77,7 +77,7 @@ enum FooBar {
 }
 ```
 
-If a struct variant is [*small*](#small-items), it may be formatted on
+If a struct variant is [*small*](index.html#small-items), it may be formatted on
 one line. In this case, do not use a trailing comma for the field list, but do
 put spaces around each brace:
 

From 73f6af54c105619f00c3e561c73b64c61b457ffc Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Sat, 24 Sep 2022 22:04:17 +0200
Subject: [PATCH 043/175] Use the sysroot proc-macro server for analysis-stats

---
 crates/rust-analyzer/src/cli/load_cargo.rs | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index e07d90542373..5dba545b8718 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -60,10 +60,26 @@ pub fn load_workspace(
     };
 
     let proc_macro_client = if load_config.with_proc_macro {
-        let path = AbsPathBuf::assert(std::env::current_exe()?);
-        Ok(ProcMacroServer::spawn(path, &["proc-macro"]).unwrap())
+        let mut path = AbsPathBuf::assert(std::env::current_exe()?);
+        let mut args = vec!["proc-macro"];
+
+        if let ProjectWorkspace::Cargo { sysroot, .. } | ProjectWorkspace::Json { sysroot, .. } =
+            &ws
+        {
+            if let Some(sysroot) = sysroot.as_ref() {
+                let standalone_server_name =
+                    format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
+                let server_path = sysroot.root().join("libexec").join(&standalone_server_name);
+                if std::fs::metadata(&server_path).is_ok() {
+                    path = server_path;
+                    args = vec![];
+                }
+            }
+        }
+
+        ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|e| e.to_string())
     } else {
-        Err("proc macro server not started".to_owned())
+        Err("proc macro server disabled".to_owned())
     };
 
     let crate_graph = ws.to_crate_graph(

From 75d3a9ebd1a6758d7d613869e1c8f72e31676792 Mon Sep 17 00:00:00 2001
From: Camille GILLOT 
Date: Tue, 6 Sep 2022 21:10:22 +0200
Subject: [PATCH 044/175] Remove unused variable.

---
 library/core/src/num/flt2dec/strategy/grisu.rs | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/library/core/src/num/flt2dec/strategy/grisu.rs b/library/core/src/num/flt2dec/strategy/grisu.rs
index a4cb51c6297a..ed3e0edaff2a 100644
--- a/library/core/src/num/flt2dec/strategy/grisu.rs
+++ b/library/core/src/num/flt2dec/strategy/grisu.rs
@@ -253,7 +253,6 @@ pub fn format_shortest_opt<'a>(
     let delta1frac = delta1 & ((1 << e) - 1);
 
     // render integral parts, while checking for the accuracy at each step.
-    let mut kappa = max_kappa as i16;
     let mut ten_kappa = max_ten_kappa; // 10^kappa
     let mut remainder = plus1int; // digits yet to be rendered
     loop {
@@ -290,12 +289,10 @@ pub fn format_shortest_opt<'a>(
         // the exact number of digits is `max_kappa + 1` as `plus1 < 10^(max_kappa+1)`.
         if i > max_kappa as usize {
             debug_assert_eq!(ten_kappa, 1);
-            debug_assert_eq!(kappa, 0);
             break;
         }
 
         // restore invariants
-        kappa -= 1;
         ten_kappa /= 10;
         remainder = r;
     }
@@ -338,7 +335,6 @@ pub fn format_shortest_opt<'a>(
         }
 
         // restore invariants
-        kappa -= 1;
         remainder = r;
     }
 

From f67184fdcbe9ed85566b3574945df0e107b8016f Mon Sep 17 00:00:00 2001
From: Martin Geisler 
Date: Sun, 25 Sep 2022 20:44:42 +0200
Subject: [PATCH 045/175] Consistently write `RwLock`

Before the documentation sometimes referred to an "rwlock" and sometimes to "`RwLock`".
---
 library/std/src/sync/rwlock.rs | 63 +++++++++++++++++-----------------
 1 file changed, 32 insertions(+), 31 deletions(-)

diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index 9ab781561e9b..a8981233995f 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -166,7 +166,7 @@ impl RwLock {
 }
 
 impl RwLock {
-    /// Locks this rwlock with shared read access, blocking the current thread
+    /// Locks this `RwLock` with shared read access, blocking the current thread
     /// until it can be acquired.
     ///
     /// The calling thread will be blocked until there are no more writers which
@@ -180,9 +180,10 @@ impl RwLock {
     ///
     /// # Errors
     ///
-    /// This function will return an error if the RwLock is poisoned. An RwLock
-    /// is poisoned whenever a writer panics while holding an exclusive lock.
-    /// The failure will occur immediately after the lock has been acquired.
+    /// This function will return an error if the `RwLock` is poisoned. An
+    /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
+    /// lock. The failure will occur immediately after the lock has been
+    /// acquired.
     ///
     /// # Panics
     ///
@@ -214,7 +215,7 @@ impl RwLock {
         }
     }
 
-    /// Attempts to acquire this rwlock with shared read access.
+    /// Attempts to acquire this `RwLock` with shared read access.
     ///
     /// If the access could not be granted at this time, then `Err` is returned.
     /// Otherwise, an RAII guard is returned which will release the shared access
@@ -227,13 +228,13 @@ impl RwLock {
     ///
     /// # Errors
     ///
-    /// This function will return the [`Poisoned`] error if the RwLock is poisoned.
-    /// An RwLock is poisoned whenever a writer panics while holding an exclusive
-    /// lock. `Poisoned` will only be returned if the lock would have otherwise been
-    /// acquired.
+    /// This function will return the [`Poisoned`] error if the `RwLock` is
+    /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding
+    /// an exclusive lock. `Poisoned` will only be returned if the lock would
+    /// have otherwise been acquired.
     ///
-    /// This function will return the [`WouldBlock`] error if the RwLock could not
-    /// be acquired because it was already locked exclusively.
+    /// This function will return the [`WouldBlock`] error if the `RwLock` could
+    /// not be acquired because it was already locked exclusively.
     ///
     /// [`Poisoned`]: TryLockError::Poisoned
     /// [`WouldBlock`]: TryLockError::WouldBlock
@@ -262,20 +263,20 @@ impl RwLock {
         }
     }
 
-    /// Locks this rwlock with exclusive write access, blocking the current
+    /// Locks this `RwLock` with exclusive write access, blocking the current
     /// thread until it can be acquired.
     ///
     /// This function will not return while other writers or other readers
     /// currently have access to the lock.
     ///
-    /// Returns an RAII guard which will drop the write access of this rwlock
+    /// Returns an RAII guard which will drop the write access of this `RwLock`
     /// when dropped.
     ///
     /// # Errors
     ///
-    /// This function will return an error if the RwLock is poisoned. An RwLock
-    /// is poisoned whenever a writer panics while holding an exclusive lock.
-    /// An error will be returned when the lock is acquired.
+    /// This function will return an error if the `RwLock` is poisoned. An
+    /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
+    /// lock. An error will be returned when the lock is acquired.
     ///
     /// # Panics
     ///
@@ -302,7 +303,7 @@ impl RwLock {
         }
     }
 
-    /// Attempts to lock this rwlock with exclusive write access.
+    /// Attempts to lock this `RwLock` with exclusive write access.
     ///
     /// If the lock could not be acquired at this time, then `Err` is returned.
     /// Otherwise, an RAII guard is returned which will release the lock when
@@ -315,13 +316,13 @@ impl RwLock {
     ///
     /// # Errors
     ///
-    /// This function will return the [`Poisoned`] error if the RwLock is
-    /// poisoned. An RwLock is poisoned whenever a writer panics while holding
-    /// an exclusive lock. `Poisoned` will only be returned if the lock would have
-    /// otherwise been acquired.
+    /// This function will return the [`Poisoned`] error if the `RwLock` is
+    /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding
+    /// an exclusive lock. `Poisoned` will only be returned if the lock would
+    /// have otherwise been acquired.
     ///
-    /// This function will return the [`WouldBlock`] error if the RwLock could not
-    /// be acquired because it was already locked exclusively.
+    /// This function will return the [`WouldBlock`] error if the `RwLock` could
+    /// not be acquired because it was already locked exclusively.
     ///
     /// [`Poisoned`]: TryLockError::Poisoned
     /// [`WouldBlock`]: TryLockError::WouldBlock
@@ -421,10 +422,10 @@ impl RwLock {
     ///
     /// # Errors
     ///
-    /// This function will return an error if the RwLock is poisoned. An RwLock
-    /// is poisoned whenever a writer panics while holding an exclusive lock. An
-    /// error will only be returned if the lock would have otherwise been
-    /// acquired.
+    /// This function will return an error if the `RwLock` is poisoned. An
+    /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
+    /// lock. An error will only be returned if the lock would have otherwise
+    /// been acquired.
     ///
     /// # Examples
     ///
@@ -454,10 +455,10 @@ impl RwLock {
     ///
     /// # Errors
     ///
-    /// This function will return an error if the RwLock is poisoned. An RwLock
-    /// is poisoned whenever a writer panics while holding an exclusive lock. An
-    /// error will only be returned if the lock would have otherwise been
-    /// acquired.
+    /// This function will return an error if the `RwLock` is poisoned. An
+    /// `RwLock` is poisoned whenever a writer panics while holding an exclusive
+    /// lock. An error will only be returned if the lock would have otherwise
+    /// been acquired.
     ///
     /// # Examples
     ///

From 2ea770d067b186dac4be6fe22757efc8f8176eb2 Mon Sep 17 00:00:00 2001
From: David Carlier 
Date: Sat, 24 Sep 2022 09:08:56 +0100
Subject: [PATCH 046/175] fs::get_path solarish version.

---
 library/std/src/sys/unix/fs.rs | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index cc347e3586ae..60545be71de1 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1198,7 +1198,12 @@ impl FromRawFd for File {
 
 impl fmt::Debug for File {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        #[cfg(any(target_os = "linux", target_os = "netbsd"))]
+        #[cfg(any(
+            target_os = "linux",
+            target_os = "netbsd",
+            target_os = "illumos",
+            target_os = "solaris"
+        ))]
         fn get_path(fd: c_int) -> Option {
             let mut p = PathBuf::from("/proc/self/fd");
             p.push(&fd.to_string());
@@ -1253,7 +1258,9 @@ impl fmt::Debug for File {
             target_os = "macos",
             target_os = "vxworks",
             all(target_os = "freebsd", target_arch = "x86_64"),
-            target_os = "netbsd"
+            target_os = "netbsd",
+            target_os = "illumos",
+            target_os = "solaris"
         )))]
         fn get_path(_fd: c_int) -> Option {
             // FIXME(#24570): implement this for other Unix platforms

From 7929e9c56b4e99931e3f6d4538f94e5850b87789 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 26 Sep 2022 11:34:30 +0200
Subject: [PATCH 047/175] Remove obsolete in-rust-tree feature from sourcegen

---
 crates/rust-analyzer/Cargo.toml | 1 -
 crates/sourcegen/Cargo.toml     | 3 ---
 2 files changed, 4 deletions(-)

diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 5392589186d1..861753d6fb41 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -87,7 +87,6 @@ jemalloc = ["jemallocator", "profile/jemalloc"]
 force-always-assert = ["always-assert/force"]
 in-rust-tree = [
     "proc-macro-srv/sysroot-abi",
-    "sourcegen/in-rust-tree",
     "ide/in-rust-tree",
     "syntax/in-rust-tree",
 ]
diff --git a/crates/sourcegen/Cargo.toml b/crates/sourcegen/Cargo.toml
index a84110d940bc..e75867e2d81c 100644
--- a/crates/sourcegen/Cargo.toml
+++ b/crates/sourcegen/Cargo.toml
@@ -11,6 +11,3 @@ doctest = false
 
 [dependencies]
 xshell = "0.2.2"
-
-[features]
-in-rust-tree = []

From aa093f5a58175e06249baeeae60818918274e123 Mon Sep 17 00:00:00 2001
From: Noah Santschi-Cooney 
Date: Mon, 26 Sep 2022 14:09:54 +0100
Subject: [PATCH 048/175] Fix PackageInformation having the crate name instead
 of package name

---
 crates/base-db/src/fixture.rs         |  8 ++++----
 crates/base-db/src/input.rs           | 25 ++++++++++++++-----------
 crates/ide/src/lib.rs                 |  2 +-
 crates/ide/src/moniker.rs             | 10 +++++++---
 crates/project-model/src/workspace.rs | 19 ++++++++++++++-----
 5 files changed, 40 insertions(+), 24 deletions(-)

diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs
index 8e6e6a11abda..5b7828a26996 100644
--- a/crates/base-db/src/fixture.rs
+++ b/crates/base-db/src/fixture.rs
@@ -196,7 +196,7 @@ impl ChangeFixture {
                 Env::default(),
                 Ok(Vec::new()),
                 false,
-                CrateOrigin::CratesIo { repo: None },
+                CrateOrigin::CratesIo { repo: None, name: None },
             );
         } else {
             for (from, to, prelude) in crate_deps {
@@ -270,7 +270,7 @@ impl ChangeFixture {
                 Env::default(),
                 Ok(proc_macro),
                 true,
-                CrateOrigin::CratesIo { repo: None },
+                CrateOrigin::CratesIo { repo: None, name: None },
             );
 
             for krate in all_crates {
@@ -398,7 +398,7 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option) {
         let (version, origin) = match b.split_once(':') {
             Some(("CratesIo", data)) => match data.split_once(',') {
                 Some((version, url)) => {
-                    (version, CrateOrigin::CratesIo { repo: Some(url.to_owned()) })
+                    (version, CrateOrigin::CratesIo { repo: Some(url.to_owned()), name: None })
                 }
                 _ => panic!("Bad crates.io parameter: {}", data),
             },
@@ -409,7 +409,7 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option) {
         let crate_origin = match &*crate_str {
             "std" => CrateOrigin::Lang(LangCrateOrigin::Std),
             "core" => CrateOrigin::Lang(LangCrateOrigin::Core),
-            _ => CrateOrigin::CratesIo { repo: None },
+            _ => CrateOrigin::CratesIo { repo: None, name: None },
         };
         (crate_str, crate_origin, None)
     }
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index b388e47dee6e..9ceaebb91e16 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -136,7 +136,10 @@ impl ops::Deref for CrateName {
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum CrateOrigin {
     /// Crates that are from crates.io official registry,
-    CratesIo { repo: Option },
+    CratesIo {
+        repo: Option,
+        name: Option,
+    },
     /// Crates that are provided by the language, like std, core, proc-macro, ...
     Lang(LangCrateOrigin),
 }
@@ -648,7 +651,7 @@ mod tests {
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo { repo: None, name: None },
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -660,7 +663,7 @@ mod tests {
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo { repo: None, name: None },
         );
         let crate3 = graph.add_crate_root(
             FileId(3u32),
@@ -672,7 +675,7 @@ mod tests {
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo { repo: None, name: None },
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -698,7 +701,7 @@ mod tests {
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo { repo: None, name: None },
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -710,7 +713,7 @@ mod tests {
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo { repo: None, name: None },
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -733,7 +736,7 @@ mod tests {
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo { repo: None, name: None },
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -745,7 +748,7 @@ mod tests {
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo { repo: None, name: None },
         );
         let crate3 = graph.add_crate_root(
             FileId(3u32),
@@ -757,7 +760,7 @@ mod tests {
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo { repo: None, name: None },
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -780,7 +783,7 @@ mod tests {
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo { repo: None, name: None },
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -792,7 +795,7 @@ mod tests {
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo { repo: None, name: None },
         );
         assert!(graph
             .add_dep(
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index c1ef25b592b1..7820b67142fe 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -236,7 +236,7 @@ impl Analysis {
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo { repo: None, name: None },
         );
         change.change_file(file_id, Some(Arc::new(text)));
         change.set_crate_graph(crate_graph);
diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs
index 600a526300c7..852a8fd83761 100644
--- a/crates/ide/src/moniker.rs
+++ b/crates/ide/src/moniker.rs
@@ -253,10 +253,14 @@ pub(crate) fn def_to_moniker(
         },
         kind: if krate == from_crate { MonikerKind::Export } else { MonikerKind::Import },
         package_information: {
-            let name = krate.display_name(db)?.to_string();
-            let (repo, version) = match krate.origin(db) {
-                CrateOrigin::CratesIo { repo } => (repo?, krate.version(db)?),
+            let (name, repo, version) = match krate.origin(db) {
+                CrateOrigin::CratesIo { repo, name } => (
+                    name.unwrap_or(krate.display_name(db)?.canonical_name().to_string()),
+                    repo?,
+                    krate.version(db)?,
+                ),
                 CrateOrigin::Lang(lang) => (
+                    krate.display_name(db)?.canonical_name().to_string(),
                     "https://github.com/rust-lang/rust/".to_string(),
                     match lang {
                         LangCrateOrigin::Other => {
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 2c0af99940f9..d9d3cab45614 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -518,9 +518,15 @@ fn project_json_to_crate_graph(
                     proc_macro,
                     krate.is_proc_macro,
                     if krate.display_name.is_some() {
-                        CrateOrigin::CratesIo { repo: krate.repository.clone() }
+                        CrateOrigin::CratesIo {
+                            repo: krate.repository.clone(),
+                            name: krate
+                                .display_name
+                                .clone()
+                                .map(|n| n.canonical_name().to_string()),
+                        }
                     } else {
-                        CrateOrigin::CratesIo { repo: None }
+                        CrateOrigin::CratesIo { repo: None, name: None }
                     },
                 ),
             )
@@ -740,14 +746,17 @@ fn detached_files_to_crate_graph(
         let detached_file_crate = crate_graph.add_crate_root(
             file_id,
             Edition::CURRENT,
-            display_name,
+            display_name.clone(),
             None,
             cfg_options.clone(),
             cfg_options.clone(),
             Env::default(),
             Ok(Vec::new()),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::CratesIo {
+                repo: None,
+                name: display_name.map(|n| n.canonical_name().to_string()),
+            },
         );
 
         public_deps.add(detached_file_crate, &mut crate_graph);
@@ -923,7 +932,7 @@ fn add_target_crate_root(
         env,
         proc_macro,
         is_proc_macro,
-        CrateOrigin::CratesIo { repo: pkg.repository.clone() },
+        CrateOrigin::CratesIo { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) },
     )
 }
 

From 60b432b7e9ad71e97680da2497fdb3576094d854 Mon Sep 17 00:00:00 2001
From: Noah Santschi-Cooney 
Date: Mon, 26 Sep 2022 18:09:46 +0100
Subject: [PATCH 049/175] fix model tests

---
 crates/project-model/src/tests.rs | 48 +++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index 813f0a7ce9f1..e2444e24974a 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -185,6 +185,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -260,6 +263,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -335,6 +341,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -410,6 +419,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -477,6 +489,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                             repo: Some(
                                 "https://github.com/rust-lang/libc",
                             ),
+                            name: Some(
+                                "libc",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -567,6 +582,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -644,6 +662,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -721,6 +742,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -798,6 +822,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -865,6 +892,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                             repo: Some(
                                 "https://github.com/rust-lang/libc",
                             ),
+                            name: Some(
+                                "libc",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -946,6 +976,9 @@ fn cargo_hello_world_project_model() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -1023,6 +1056,9 @@ fn cargo_hello_world_project_model() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -1100,6 +1136,9 @@ fn cargo_hello_world_project_model() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -1177,6 +1216,9 @@ fn cargo_hello_world_project_model() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello-world",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -1244,6 +1286,9 @@ fn cargo_hello_world_project_model() {
                             repo: Some(
                                 "https://github.com/rust-lang/libc",
                             ),
+                            name: Some(
+                                "libc",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -1804,6 +1849,9 @@ fn rust_project_hello_world_project_model() {
                         ),
                         origin: CratesIo {
                             repo: None,
+                            name: Some(
+                                "hello_world",
+                            ),
                         },
                         is_proc_macro: false,
                     },

From 651c586035dfb4cf244aa9e9dacabfee9f579564 Mon Sep 17 00:00:00 2001
From: Noah Santschi-Cooney 
Date: Mon, 26 Sep 2022 18:35:06 +0100
Subject: [PATCH 050/175] formatting

---
 crates/base-db/src/input.rs | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index 9ceaebb91e16..e7f0c4ec29bf 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -136,10 +136,7 @@ impl ops::Deref for CrateName {
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum CrateOrigin {
     /// Crates that are from crates.io official registry,
-    CratesIo {
-        repo: Option,
-        name: Option,
-    },
+    CratesIo { repo: Option, name: Option },
     /// Crates that are provided by the language, like std, core, proc-macro, ...
     Lang(LangCrateOrigin),
 }

From 89107d5469dfe978efafe57d70b6f1525b060d46 Mon Sep 17 00:00:00 2001
From: unexge 
Date: Sun, 4 Sep 2022 18:28:04 +0100
Subject: [PATCH 051/175] Emit unconfigured code diagnostics for fields

---
 crates/hir-def/src/item_tree.rs               |   8 +
 crates/hir-def/src/item_tree/lower.rs         |   9 +-
 crates/hir-def/src/item_tree/pretty.rs        |   6 +-
 crates/hir-def/src/nameres/collector.rs       |  99 ++-
 crates/hir-def/src/nameres/diagnostics.rs     |   6 +-
 crates/hir-expand/src/ast_id_map.rs           |   7 +-
 crates/hir/src/diagnostics.rs                 |   2 +-
 .../src/handlers/inactive_code.rs             |  25 +
 crates/syntax/src/ast/generated/nodes.rs      | 567 ++++++++++++++++++
 crates/syntax/src/tests/sourcegen_ast.rs      |  34 ++
 10 files changed, 730 insertions(+), 33 deletions(-)

diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index 3342d4db4aa6..570344596def 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -943,6 +943,7 @@ impl AssocItem {
 pub struct Variant {
     pub name: Name,
     pub fields: Fields,
+    pub ast_id: FileAstId,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -952,10 +953,17 @@ pub enum Fields {
     Unit,
 }
 
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum FieldAstId {
+    Record(FileAstId),
+    Tuple(FileAstId),
+}
+
 /// A single field of an enum variant or struct
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Field {
     pub name: Name,
     pub type_ref: Interned,
     pub visibility: RawVisibilityId,
+    pub ast_id: FieldAstId,
 }
diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs
index 7f2551e94187..077a1b619dd5 100644
--- a/crates/hir-def/src/item_tree/lower.rs
+++ b/crates/hir-def/src/item_tree/lower.rs
@@ -184,7 +184,8 @@ impl<'a> Ctx<'a> {
         let name = field.name()?.as_name();
         let visibility = self.lower_visibility(field);
         let type_ref = self.lower_type_ref_opt(field.ty());
-        let res = Field { name, type_ref, visibility };
+        let ast_id = FieldAstId::Record(self.source_ast_id_map.ast_id(field));
+        let res = Field { name, type_ref, visibility, ast_id };
         Some(res)
     }
 
@@ -203,7 +204,8 @@ impl<'a> Ctx<'a> {
         let name = Name::new_tuple_field(idx);
         let visibility = self.lower_visibility(field);
         let type_ref = self.lower_type_ref_opt(field.ty());
-        Field { name, type_ref, visibility }
+        let ast_id = FieldAstId::Tuple(self.source_ast_id_map.ast_id(field));
+        Field { name, type_ref, visibility, ast_id }
     }
 
     fn lower_union(&mut self, union: &ast::Union) -> Option> {
@@ -247,7 +249,8 @@ impl<'a> Ctx<'a> {
     fn lower_variant(&mut self, variant: &ast::Variant) -> Option {
         let name = variant.name()?.as_name();
         let fields = self.lower_fields(&variant.kind());
-        let res = Variant { name, fields };
+        let ast_id = self.source_ast_id_map.ast_id(variant);
+        let res = Variant { name, fields, ast_id };
         Some(res)
     }
 
diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs
index 34dd817fd130..da1643152c2f 100644
--- a/crates/hir-def/src/item_tree/pretty.rs
+++ b/crates/hir-def/src/item_tree/pretty.rs
@@ -115,7 +115,7 @@ impl<'a> Printer<'a> {
                 w!(self, "{{");
                 self.indented(|this| {
                     for field in fields.clone() {
-                        let Field { visibility, name, type_ref } = &this.tree[field];
+                        let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
                         this.print_attrs_of(field);
                         this.print_visibility(*visibility);
                         w!(this, "{}: ", name);
@@ -129,7 +129,7 @@ impl<'a> Printer<'a> {
                 w!(self, "(");
                 self.indented(|this| {
                     for field in fields.clone() {
-                        let Field { visibility, name, type_ref } = &this.tree[field];
+                        let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
                         this.print_attrs_of(field);
                         this.print_visibility(*visibility);
                         w!(this, "{}: ", name);
@@ -323,7 +323,7 @@ impl<'a> Printer<'a> {
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
                     for variant in variants.clone() {
-                        let Variant { name, fields } = &this.tree[variant];
+                        let Variant { name, fields, ast_id: _ } = &this.tree[variant];
                         this.print_attrs_of(variant);
                         w!(this, "{}", name);
                         this.print_fields(fields);
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 9242b48c5931..5f0cf9c4ac89 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -32,8 +32,8 @@ use crate::{
     derive_macro_as_call_id,
     item_scope::{ImportType, PerNsGlobImports},
     item_tree::{
-        self, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, MacroCall,
-        MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
+        self, FieldAstId, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode,
+        MacroCall, MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
     },
     macro_call_as_call_id, macro_id_to_def_id,
     nameres::{
@@ -1511,7 +1511,10 @@ impl ModCollector<'_, '_> {
             let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
             if let Some(cfg) = attrs.cfg() {
                 if !self.is_cfg_enabled(&cfg) {
-                    self.emit_unconfigured_diagnostic(item, &cfg);
+                    self.emit_unconfigured_diagnostic(
+                        InFile::new(self.file_id(), item.ast_id(&self.item_tree).upcast()),
+                        &cfg,
+                    );
                     continue;
                 }
             }
@@ -1523,22 +1526,20 @@ impl ModCollector<'_, '_> {
             }
 
             let db = self.def_collector.db;
-            let module = self.def_collector.def_map.module_id(self.module_id);
-            let def_map = &mut self.def_collector.def_map;
+            let module_id = self.module_id;
+            let module = self.def_collector.def_map.module_id(module_id);
             let update_def =
                 |def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
-                    def_collector.def_map.modules[self.module_id].scope.declare(id);
+                    def_collector.def_map.modules[module_id].scope.declare(id);
                     def_collector.update(
-                        self.module_id,
+                        module_id,
                         &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
                         vis,
                         ImportType::Named,
                     )
                 };
             let resolve_vis = |def_map: &DefMap, visibility| {
-                def_map
-                    .resolve_visibility(db, self.module_id, visibility)
-                    .unwrap_or(Visibility::Public)
+                def_map.resolve_visibility(db, module_id, visibility).unwrap_or(Visibility::Public)
             };
 
             match item {
@@ -1594,6 +1595,7 @@ impl ModCollector<'_, '_> {
                     let fn_id =
                         FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
 
+                    let def_map = &self.def_collector.def_map;
                     let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
                     if self.def_collector.is_proc_macro {
                         if self.module_id == def_map.root {
@@ -1614,7 +1616,10 @@ impl ModCollector<'_, '_> {
                 ModItem::Struct(id) => {
                     let it = &self.item_tree[id];
 
-                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
+                    self.process_fields(&it.fields);
+
+                    let vis =
+                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1628,7 +1633,10 @@ impl ModCollector<'_, '_> {
                 ModItem::Union(id) => {
                     let it = &self.item_tree[id];
 
-                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
+                    self.process_fields(&it.fields);
+
+                    let vis =
+                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1642,7 +1650,21 @@ impl ModCollector<'_, '_> {
                 ModItem::Enum(id) => {
                     let it = &self.item_tree[id];
 
-                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
+                    for id in it.variants.clone() {
+                        let variant = &self.item_tree[id];
+                        let attrs = self.item_tree.attrs(self.def_collector.db, krate, id.into());
+                        if let Some(cfg) = attrs.cfg() {
+                            if !self.is_cfg_enabled(&cfg) {
+                                self.emit_unconfigured_diagnostic(
+                                    InFile::new(self.file_id(), variant.ast_id.upcast()),
+                                    &cfg,
+                                );
+                            }
+                        }
+                    }
+
+                    let vis =
+                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1660,7 +1682,10 @@ impl ModCollector<'_, '_> {
 
                     match &it.name {
                         Some(name) => {
-                            let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
+                            let vis = resolve_vis(
+                                &self.def_collector.def_map,
+                                &self.item_tree[it.visibility],
+                            );
                             update_def(self.def_collector, const_id.into(), name, vis, false);
                         }
                         None => {
@@ -1674,7 +1699,8 @@ impl ModCollector<'_, '_> {
                 ModItem::Static(id) => {
                     let it = &self.item_tree[id];
 
-                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
+                    let vis =
+                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
@@ -1688,7 +1714,8 @@ impl ModCollector<'_, '_> {
                 ModItem::Trait(id) => {
                     let it = &self.item_tree[id];
 
-                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
+                    let vis =
+                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1702,7 +1729,8 @@ impl ModCollector<'_, '_> {
                 ModItem::TypeAlias(id) => {
                     let it = &self.item_tree[id];
 
-                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
+                    let vis =
+                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
@@ -2115,17 +2143,44 @@ impl ModCollector<'_, '_> {
         }
     }
 
+    fn process_fields(&mut self, fields: &Fields) {
+        match fields {
+            Fields::Record(range) | Fields::Tuple(range) => {
+                for id in range.clone() {
+                    let field = &self.item_tree[id];
+                    let attrs = self.item_tree.attrs(
+                        self.def_collector.db,
+                        self.def_collector.def_map.krate,
+                        id.into(),
+                    );
+                    if let Some(cfg) = attrs.cfg() {
+                        if !self.is_cfg_enabled(&cfg) {
+                            self.emit_unconfigured_diagnostic(
+                                InFile::new(
+                                    self.file_id(),
+                                    match field.ast_id {
+                                        FieldAstId::Record(it) => it.upcast(),
+                                        FieldAstId::Tuple(it) => it.upcast(),
+                                    },
+                                ),
+                                &cfg,
+                            );
+                        }
+                    }
+                }
+            }
+            Fields::Unit => {}
+        }
+    }
+
     fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool {
         self.def_collector.cfg_options.check(cfg) != Some(false)
     }
 
-    fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
-        let ast_id = item.ast_id(self.item_tree);
-
-        let ast_id = InFile::new(self.file_id(), ast_id);
+    fn emit_unconfigured_diagnostic(&mut self, ast: AstId, cfg: &CfgExpr) {
         self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
             self.module_id,
-            ast_id,
+            ast,
             cfg.clone(),
             self.def_collector.cfg_options.clone(),
         ));
diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs
index ed7e920fd2b8..066142291981 100644
--- a/crates/hir-def/src/nameres/diagnostics.rs
+++ b/crates/hir-def/src/nameres/diagnostics.rs
@@ -4,7 +4,7 @@ use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
 use hir_expand::MacroCallKind;
 use la_arena::Idx;
-use syntax::ast;
+use syntax::ast::{self, AnyHasAttrs};
 
 use crate::{
     attr::AttrId,
@@ -22,7 +22,7 @@ pub enum DefDiagnosticKind {
 
     UnresolvedImport { id: ItemTreeId, index: Idx },
 
-    UnconfiguredCode { ast: AstId, cfg: CfgExpr, opts: CfgOptions },
+    UnconfiguredCode { ast: AstId, cfg: CfgExpr, opts: CfgOptions },
 
     UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
 
@@ -75,7 +75,7 @@ impl DefDiagnostic {
 
     pub fn unconfigured_code(
         container: LocalModuleId,
-        ast: AstId,
+        ast: AstId,
         cfg: CfgExpr,
         opts: CfgOptions,
     ) -> Self {
diff --git a/crates/hir-expand/src/ast_id_map.rs b/crates/hir-expand/src/ast_id_map.rs
index 11c0a6764e9d..2b27db0e9506 100644
--- a/crates/hir-expand/src/ast_id_map.rs
+++ b/crates/hir-expand/src/ast_id_map.rs
@@ -93,7 +93,12 @@ impl AstIdMap {
         // trait does not change ids of top-level items, which helps caching.
         bdfs(node, |it| {
             let kind = it.kind();
-            if ast::Item::can_cast(kind) || ast::BlockExpr::can_cast(kind) {
+            if ast::Item::can_cast(kind)
+                || ast::BlockExpr::can_cast(kind)
+                || ast::Variant::can_cast(kind)
+                || ast::RecordField::can_cast(kind)
+                || ast::TupleField::can_cast(kind)
+            {
                 res.alloc(&it);
                 true
             } else {
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 5edc16d8bce9..c5dc60f1ec5f 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -1,7 +1,7 @@
 //! Re-export diagnostics such that clients of `hir` don't have to depend on
 //! low-level crates.
 //!
-//! This probably isn't the best way to do this -- ideally, diagnistics should
+//! This probably isn't the best way to do this -- ideally, diagnostics should
 //! be expressed in terms of hir types themselves.
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
diff --git a/crates/ide-diagnostics/src/handlers/inactive_code.rs b/crates/ide-diagnostics/src/handlers/inactive_code.rs
index 04918891b254..c22e25b0637d 100644
--- a/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -137,6 +137,31 @@ trait Bar {
 
     #[cfg_attr(not(never), inline, cfg(no))] fn h() {}
   //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
+"#,
+        );
+    }
+
+    #[test]
+    fn inactive_fields() {
+        check(
+            r#"
+enum Foo {
+  #[cfg(a)] Bar,
+//^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
+}
+
+struct Baz {
+  #[cfg(a)] baz: String,
+//^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
+}
+
+struct Qux(#[cfg(a)] String);
+         //^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
+
+union FooBar {
+  #[cfg(a)] baz: u32,
+//^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
+}
 "#,
         );
     }
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 449402e5f5b3..f4664f3aaeae 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -3894,6 +3894,12 @@ impl AstNode for AnyHasArgList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl From for AnyHasArgList {
+    fn from(node: CallExpr) -> AnyHasArgList { AnyHasArgList::new(node) }
+}
+impl From for AnyHasArgList {
+    fn from(node: MethodCallExpr) -> AnyHasArgList { AnyHasArgList::new(node) }
+}
 impl AnyHasAttrs {
     #[inline]
     pub fn new(node: T) -> AnyHasAttrs {
@@ -3978,6 +3984,207 @@ impl AstNode for AnyHasAttrs {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl From for AnyHasAttrs {
+    fn from(node: MacroCall) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: SourceFile) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Const) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Enum) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ExternBlock) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ExternCrate) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Fn) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Impl) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: MacroRules) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: MacroDef) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Module) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Static) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Struct) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Trait) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: TypeAlias) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Union) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Use) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ItemList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: BlockExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: SelfParam) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Param) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: RecordField) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: TupleField) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Variant) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: AssocItemList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ExternItemList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ConstParam) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: LifetimeParam) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: TypeParam) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: LetStmt) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ArrayExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: AwaitExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: BinExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: BoxExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: BreakExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: CallExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: CastExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ClosureExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ContinueExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: FieldExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ForExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: IfExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: IndexExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Literal) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: LoopExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: MatchExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: MethodCallExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ParenExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: PathExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: PrefixExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: RangeExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: RefExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ReturnExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: TryExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: TupleExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: WhileExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: YieldExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: LetExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: UnderscoreExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: StmtList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: RecordExprFieldList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: RecordExprField) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: MatchArmList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: MatchArm) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: IdentPat) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: RestPat) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: RecordPatField) -> AnyHasAttrs { AnyHasAttrs::new(node) }
+}
 impl AnyHasDocComments {
     #[inline]
     pub fn new(node: T) -> AnyHasDocComments {
@@ -4015,6 +4222,66 @@ impl AstNode for AnyHasDocComments {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl From for AnyHasDocComments {
+    fn from(node: MacroCall) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: SourceFile) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Const) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Enum) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: ExternBlock) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: ExternCrate) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Fn) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Impl) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: MacroRules) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: MacroDef) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Module) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Static) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Struct) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Trait) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: TypeAlias) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Union) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Use) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: RecordField) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: TupleField) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Variant) -> AnyHasDocComments { AnyHasDocComments::new(node) }
+}
 impl AnyHasGenericParams {
     #[inline]
     pub fn new(node: T) -> AnyHasGenericParams {
@@ -4030,6 +4297,27 @@ impl AstNode for AnyHasGenericParams {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl From for AnyHasGenericParams {
+    fn from(node: Enum) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
+}
+impl From for AnyHasGenericParams {
+    fn from(node: Fn) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
+}
+impl From for AnyHasGenericParams {
+    fn from(node: Impl) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
+}
+impl From for AnyHasGenericParams {
+    fn from(node: Struct) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
+}
+impl From for AnyHasGenericParams {
+    fn from(node: Trait) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
+}
+impl From for AnyHasGenericParams {
+    fn from(node: TypeAlias) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
+}
+impl From for AnyHasGenericParams {
+    fn from(node: Union) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
+}
 impl AnyHasLoopBody {
     #[inline]
     pub fn new(node: T) -> AnyHasLoopBody {
@@ -4043,6 +4331,15 @@ impl AstNode for AnyHasLoopBody {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl From for AnyHasLoopBody {
+    fn from(node: ForExpr) -> AnyHasLoopBody { AnyHasLoopBody::new(node) }
+}
+impl From for AnyHasLoopBody {
+    fn from(node: LoopExpr) -> AnyHasLoopBody { AnyHasLoopBody::new(node) }
+}
+impl From for AnyHasLoopBody {
+    fn from(node: WhileExpr) -> AnyHasLoopBody { AnyHasLoopBody::new(node) }
+}
 impl AnyHasModuleItem {
     #[inline]
     pub fn new(node: T) -> AnyHasModuleItem {
@@ -4056,6 +4353,15 @@ impl AstNode for AnyHasModuleItem {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl From for AnyHasModuleItem {
+    fn from(node: MacroItems) -> AnyHasModuleItem { AnyHasModuleItem::new(node) }
+}
+impl From for AnyHasModuleItem {
+    fn from(node: SourceFile) -> AnyHasModuleItem { AnyHasModuleItem::new(node) }
+}
+impl From for AnyHasModuleItem {
+    fn from(node: ItemList) -> AnyHasModuleItem { AnyHasModuleItem::new(node) }
+}
 impl AnyHasName {
     #[inline]
     pub fn new(node: T) -> AnyHasName {
@@ -4091,6 +4397,60 @@ impl AstNode for AnyHasName {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl From for AnyHasName {
+    fn from(node: Const) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: Enum) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: Fn) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: MacroRules) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: MacroDef) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: Module) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: Static) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: Struct) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: Trait) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: TypeAlias) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: Union) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: Rename) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: SelfParam) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: RecordField) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: Variant) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: ConstParam) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: TypeParam) -> AnyHasName { AnyHasName::new(node) }
+}
+impl From for AnyHasName {
+    fn from(node: IdentPat) -> AnyHasName { AnyHasName::new(node) }
+}
 impl AnyHasTypeBounds {
     #[inline]
     pub fn new(node: T) -> AnyHasTypeBounds {
@@ -4109,6 +4469,24 @@ impl AstNode for AnyHasTypeBounds {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl From for AnyHasTypeBounds {
+    fn from(node: AssocTypeArg) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
+}
+impl From for AnyHasTypeBounds {
+    fn from(node: Trait) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
+}
+impl From for AnyHasTypeBounds {
+    fn from(node: TypeAlias) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
+}
+impl From for AnyHasTypeBounds {
+    fn from(node: LifetimeParam) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
+}
+impl From for AnyHasTypeBounds {
+    fn from(node: TypeParam) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
+}
+impl From for AnyHasTypeBounds {
+    fn from(node: WherePred) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
+}
 impl AnyHasVisibility {
     #[inline]
     pub fn new(node: T) -> AnyHasVisibility {
@@ -4143,6 +4521,195 @@ impl AstNode for AnyHasVisibility {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl From for AnyHasVisibility {
+    fn from(node: Const) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: Enum) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: ExternCrate) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: Fn) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: Impl) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: MacroRules) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: MacroDef) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: Module) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: Static) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: Struct) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: Trait) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: TypeAlias) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: Union) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: Use) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: RecordField) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: TupleField) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasVisibility {
+    fn from(node: Variant) -> AnyHasVisibility { AnyHasVisibility::new(node) }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Item) -> AnyHasAttrs {
+        match node {
+            Item::Const(it) => AnyHasAttrs::new(it),
+            Item::Enum(it) => AnyHasAttrs::new(it),
+            Item::ExternBlock(it) => AnyHasAttrs::new(it),
+            Item::ExternCrate(it) => AnyHasAttrs::new(it),
+            Item::Fn(it) => AnyHasAttrs::new(it),
+            Item::Impl(it) => AnyHasAttrs::new(it),
+            Item::MacroCall(it) => AnyHasAttrs::new(it),
+            Item::MacroRules(it) => AnyHasAttrs::new(it),
+            Item::MacroDef(it) => AnyHasAttrs::new(it),
+            Item::Module(it) => AnyHasAttrs::new(it),
+            Item::Static(it) => AnyHasAttrs::new(it),
+            Item::Struct(it) => AnyHasAttrs::new(it),
+            Item::Trait(it) => AnyHasAttrs::new(it),
+            Item::TypeAlias(it) => AnyHasAttrs::new(it),
+            Item::Union(it) => AnyHasAttrs::new(it),
+            Item::Use(it) => AnyHasAttrs::new(it),
+        }
+    }
+}
+impl From for AnyHasAttrs {
+    fn from(node: Adt) -> AnyHasAttrs {
+        match node {
+            Adt::Enum(it) => AnyHasAttrs::new(it),
+            Adt::Struct(it) => AnyHasAttrs::new(it),
+            Adt::Union(it) => AnyHasAttrs::new(it),
+        }
+    }
+}
+impl From for AnyHasAttrs {
+    fn from(node: AssocItem) -> AnyHasAttrs {
+        match node {
+            AssocItem::Const(it) => AnyHasAttrs::new(it),
+            AssocItem::Fn(it) => AnyHasAttrs::new(it),
+            AssocItem::MacroCall(it) => AnyHasAttrs::new(it),
+            AssocItem::TypeAlias(it) => AnyHasAttrs::new(it),
+        }
+    }
+}
+impl From for AnyHasAttrs {
+    fn from(node: ExternItem) -> AnyHasAttrs {
+        match node {
+            ExternItem::Fn(it) => AnyHasAttrs::new(it),
+            ExternItem::MacroCall(it) => AnyHasAttrs::new(it),
+            ExternItem::Static(it) => AnyHasAttrs::new(it),
+            ExternItem::TypeAlias(it) => AnyHasAttrs::new(it),
+        }
+    }
+}
+impl From for AnyHasAttrs {
+    fn from(node: GenericParam) -> AnyHasAttrs {
+        match node {
+            GenericParam::ConstParam(it) => AnyHasAttrs::new(it),
+            GenericParam::LifetimeParam(it) => AnyHasAttrs::new(it),
+            GenericParam::TypeParam(it) => AnyHasAttrs::new(it),
+        }
+    }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Item) -> AnyHasDocComments {
+        match node {
+            Item::Const(it) => AnyHasDocComments::new(it),
+            Item::Enum(it) => AnyHasDocComments::new(it),
+            Item::ExternBlock(it) => AnyHasDocComments::new(it),
+            Item::ExternCrate(it) => AnyHasDocComments::new(it),
+            Item::Fn(it) => AnyHasDocComments::new(it),
+            Item::Impl(it) => AnyHasDocComments::new(it),
+            Item::MacroCall(it) => AnyHasDocComments::new(it),
+            Item::MacroRules(it) => AnyHasDocComments::new(it),
+            Item::MacroDef(it) => AnyHasDocComments::new(it),
+            Item::Module(it) => AnyHasDocComments::new(it),
+            Item::Static(it) => AnyHasDocComments::new(it),
+            Item::Struct(it) => AnyHasDocComments::new(it),
+            Item::Trait(it) => AnyHasDocComments::new(it),
+            Item::TypeAlias(it) => AnyHasDocComments::new(it),
+            Item::Union(it) => AnyHasDocComments::new(it),
+            Item::Use(it) => AnyHasDocComments::new(it),
+        }
+    }
+}
+impl From for AnyHasDocComments {
+    fn from(node: Adt) -> AnyHasDocComments {
+        match node {
+            Adt::Enum(it) => AnyHasDocComments::new(it),
+            Adt::Struct(it) => AnyHasDocComments::new(it),
+            Adt::Union(it) => AnyHasDocComments::new(it),
+        }
+    }
+}
+impl From for AnyHasDocComments {
+    fn from(node: AssocItem) -> AnyHasDocComments {
+        match node {
+            AssocItem::Const(it) => AnyHasDocComments::new(it),
+            AssocItem::Fn(it) => AnyHasDocComments::new(it),
+            AssocItem::MacroCall(it) => AnyHasDocComments::new(it),
+            AssocItem::TypeAlias(it) => AnyHasDocComments::new(it),
+        }
+    }
+}
+impl From for AnyHasDocComments {
+    fn from(node: ExternItem) -> AnyHasDocComments {
+        match node {
+            ExternItem::Fn(it) => AnyHasDocComments::new(it),
+            ExternItem::MacroCall(it) => AnyHasDocComments::new(it),
+            ExternItem::Static(it) => AnyHasDocComments::new(it),
+            ExternItem::TypeAlias(it) => AnyHasDocComments::new(it),
+        }
+    }
+}
+impl From for AnyHasGenericParams {
+    fn from(node: Adt) -> AnyHasGenericParams {
+        match node {
+            Adt::Enum(it) => AnyHasGenericParams::new(it),
+            Adt::Struct(it) => AnyHasGenericParams::new(it),
+            Adt::Union(it) => AnyHasGenericParams::new(it),
+        }
+    }
+}
+impl From for AnyHasName {
+    fn from(node: Adt) -> AnyHasName {
+        match node {
+            Adt::Enum(it) => AnyHasName::new(it),
+            Adt::Struct(it) => AnyHasName::new(it),
+            Adt::Union(it) => AnyHasName::new(it),
+        }
+    }
+}
+impl From for AnyHasVisibility {
+    fn from(node: Adt) -> AnyHasVisibility {
+        match node {
+            Adt::Enum(it) => AnyHasVisibility::new(it),
+            Adt::Struct(it) => AnyHasVisibility::new(it),
+            Adt::Union(it) => AnyHasVisibility::new(it),
+        }
+    }
+}
 impl std::fmt::Display for GenericArg {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs
index 70b54843dbaa..56d7c98d58a3 100644
--- a/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/crates/syntax/src/tests/sourcegen_ast.rs
@@ -229,6 +229,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
                 .iter()
                 .map(|name| format_ident!("{}", to_upper_snake_case(&name.name.to_string())))
                 .collect();
+            let node_names: Vec<_> = nodes.iter().map(|n| format_ident!("{}", n.name)).collect();
 
             (
                 quote! {
@@ -259,11 +260,43 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
                             &self.syntax
                         }
                     }
+
+                    #(
+                        impl From<#node_names> for #name {
+                            fn from(node: #node_names) -> #name {
+                                #name::new(node)
+                            }
+                        }
+                    )*
                 },
             )
         })
         .unzip();
 
+    let any_enum_boilerplate_impls: Vec<_> = grammar
+        .enums
+        .iter()
+        .flat_map(|en| en.traits.iter().map(move |t| (t, en)))
+        .sorted_by_key(|(k, _)| *k)
+        .map(|(target_name, en)| {
+            let target_name = format_ident!("Any{}", target_name);
+            let enum_name = format_ident!("{}", en.name);
+            let variants: Vec<_> = en.variants.iter().map(|var| format_ident!("{}", var)).collect();
+
+            quote! {
+                impl From<#enum_name> for #target_name {
+                    fn from(node: #enum_name) -> #target_name {
+                        match node {
+                            #(
+                                #enum_name::#variants(it) => #target_name::new(it),
+                            )*
+                        }
+                    }
+                }
+            }
+        })
+        .collect();
+
     let enum_names = grammar.enums.iter().map(|it| &it.name);
     let node_names = grammar.nodes.iter().map(|it| &it.name);
 
@@ -305,6 +338,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
         #(#node_boilerplate_impls)*
         #(#enum_boilerplate_impls)*
         #(#any_node_boilerplate_impls)*
+        #(#any_enum_boilerplate_impls)*
         #(#display_impls)*
     };
 

From b21bf25a07ef4cff8e9e38f44f9f407bb2bd207d Mon Sep 17 00:00:00 2001
From: unexge 
Date: Wed, 21 Sep 2022 23:05:30 +0100
Subject: [PATCH 052/175] Collect diagnostics in queries instead of nameres

---
 crates/hir-def/src/adt.rs                     | 164 ++++++++++++++----
 crates/hir-def/src/db.rs                      |  15 ++
 crates/hir-def/src/nameres/collector.rs       |  99 +++--------
 crates/hir/src/lib.rs                         |  24 ++-
 .../src/handlers/inactive_code.rs             |   8 +-
 5 files changed, 194 insertions(+), 116 deletions(-)

diff --git a/crates/hir-def/src/adt.rs b/crates/hir-def/src/adt.rs
index 14f8629056fa..af8ca8571ba2 100644
--- a/crates/hir-def/src/adt.rs
+++ b/crates/hir-def/src/adt.rs
@@ -6,7 +6,7 @@ use base_db::CrateId;
 use either::Either;
 use hir_expand::{
     name::{AsName, Name},
-    InFile,
+    HirFileId, InFile,
 };
 use la_arena::{Arena, ArenaMap};
 use syntax::ast::{self, HasName, HasVisibility};
@@ -17,13 +17,15 @@ use crate::{
     builtin_type::{BuiltinInt, BuiltinUint},
     db::DefDatabase,
     intern::Interned,
-    item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId},
+    item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
+    nameres::diagnostics::DefDiagnostic,
     src::HasChildSource,
     src::HasSource,
     trace::Trace,
     type_ref::TypeRef,
     visibility::RawVisibility,
-    EnumId, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, VariantId,
+    EnumId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId, UnionId,
+    VariantId,
 };
 use cfg::CfgOptions;
 
@@ -143,6 +145,13 @@ fn parse_repr_tt(tt: &Subtree) -> Option {
 
 impl StructData {
     pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc {
+        db.struct_data_with_diagnostics(id).0
+    }
+
+    pub(crate) fn struct_data_with_diagnostics_query(
+        db: &dyn DefDatabase,
+        id: StructId,
+    ) -> (Arc, Arc>) {
         let loc = id.lookup(db);
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
@@ -150,16 +159,35 @@ impl StructData {
         let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
 
         let strukt = &item_tree[loc.id.value];
-        let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &strukt.fields, None);
-        Arc::new(StructData {
-            name: strukt.name.clone(),
-            variant_data: Arc::new(variant_data),
-            repr,
-            visibility: item_tree[strukt.visibility].clone(),
-        })
+        let (variant_data, diagnostics) = lower_fields(
+            db,
+            krate,
+            loc.id.file_id(),
+            loc.container.local_id,
+            &item_tree,
+            &cfg_options,
+            &strukt.fields,
+            None,
+        );
+        (
+            Arc::new(StructData {
+                name: strukt.name.clone(),
+                variant_data: Arc::new(variant_data),
+                repr,
+                visibility: item_tree[strukt.visibility].clone(),
+            }),
+            Arc::new(diagnostics),
+        )
     }
 
     pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc {
+        db.union_data_with_diagnostics(id).0
+    }
+
+    pub(crate) fn union_data_with_diagnostics_query(
+        db: &dyn DefDatabase,
+        id: UnionId,
+    ) -> (Arc, Arc>) {
         let loc = id.lookup(db);
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
@@ -167,19 +195,37 @@ impl StructData {
         let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
 
         let union = &item_tree[loc.id.value];
-        let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &union.fields, None);
-
-        Arc::new(StructData {
-            name: union.name.clone(),
-            variant_data: Arc::new(variant_data),
-            repr,
-            visibility: item_tree[union.visibility].clone(),
-        })
+        let (variant_data, diagnostics) = lower_fields(
+            db,
+            krate,
+            loc.id.file_id(),
+            loc.container.local_id,
+            &item_tree,
+            &cfg_options,
+            &union.fields,
+            None,
+        );
+        (
+            Arc::new(StructData {
+                name: union.name.clone(),
+                variant_data: Arc::new(variant_data),
+                repr,
+                visibility: item_tree[union.visibility].clone(),
+            }),
+            Arc::new(diagnostics),
+        )
     }
 }
 
 impl EnumData {
     pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc {
+        db.enum_data_with_diagnostics(e).0
+    }
+
+    pub(crate) fn enum_data_with_diagnostics_query(
+        db: &dyn DefDatabase,
+        e: EnumId,
+    ) -> (Arc, Arc>) {
         let loc = e.lookup(db);
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
@@ -188,31 +234,46 @@ impl EnumData {
 
         let enum_ = &item_tree[loc.id.value];
         let mut variants = Arena::new();
+        let mut diagnostics = Vec::new();
         for tree_id in enum_.variants.clone() {
-            if item_tree.attrs(db, krate, tree_id.into()).is_cfg_enabled(&cfg_options) {
-                let var = &item_tree[tree_id];
-                let var_data = lower_fields(
+            let attrs = item_tree.attrs(db, krate, tree_id.into());
+            let var = &item_tree[tree_id];
+            if attrs.is_cfg_enabled(&cfg_options) {
+                let (var_data, field_diagnostics) = lower_fields(
                     db,
                     krate,
+                    loc.id.file_id(),
+                    loc.container.local_id,
                     &item_tree,
                     &cfg_options,
                     &var.fields,
                     Some(enum_.visibility),
                 );
+                diagnostics.extend(field_diagnostics);
 
                 variants.alloc(EnumVariantData {
                     name: var.name.clone(),
                     variant_data: Arc::new(var_data),
                 });
+            } else {
+                diagnostics.push(DefDiagnostic::unconfigured_code(
+                    loc.container.local_id,
+                    InFile::new(loc.id.file_id(), var.ast_id.upcast()),
+                    attrs.cfg().unwrap(),
+                    cfg_options.clone(),
+                ))
             }
         }
 
-        Arc::new(EnumData {
-            name: enum_.name.clone(),
-            variants,
-            repr,
-            visibility: item_tree[enum_.visibility].clone(),
-        })
+        (
+            Arc::new(EnumData {
+                name: enum_.name.clone(),
+                variants,
+                repr,
+                visibility: item_tree[enum_.visibility].clone(),
+            }),
+            Arc::new(diagnostics),
+        )
     }
 
     pub fn variant(&self, name: &Name) -> Option {
@@ -384,31 +445,64 @@ fn lower_struct(
 fn lower_fields(
     db: &dyn DefDatabase,
     krate: CrateId,
+    current_file_id: HirFileId,
+    container: LocalModuleId,
     item_tree: &ItemTree,
     cfg_options: &CfgOptions,
     fields: &Fields,
     override_visibility: Option,
-) -> VariantData {
+) -> (VariantData, Vec) {
+    let mut diagnostics = Vec::new();
     match fields {
         Fields::Record(flds) => {
             let mut arena = Arena::new();
             for field_id in flds.clone() {
-                if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
-                    arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
+                let attrs = item_tree.attrs(db, krate, field_id.into());
+                let field = &item_tree[field_id];
+                if attrs.is_cfg_enabled(cfg_options) {
+                    arena.alloc(lower_field(item_tree, field, override_visibility));
+                } else {
+                    diagnostics.push(DefDiagnostic::unconfigured_code(
+                        container,
+                        InFile::new(
+                            current_file_id,
+                            match field.ast_id {
+                                FieldAstId::Record(it) => it.upcast(),
+                                FieldAstId::Tuple(it) => it.upcast(),
+                            },
+                        ),
+                        attrs.cfg().unwrap(),
+                        cfg_options.clone(),
+                    ))
                 }
             }
-            VariantData::Record(arena)
+            (VariantData::Record(arena), diagnostics)
         }
         Fields::Tuple(flds) => {
             let mut arena = Arena::new();
             for field_id in flds.clone() {
-                if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
-                    arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
+                let attrs = item_tree.attrs(db, krate, field_id.into());
+                let field = &item_tree[field_id];
+                if attrs.is_cfg_enabled(cfg_options) {
+                    arena.alloc(lower_field(item_tree, field, override_visibility));
+                } else {
+                    diagnostics.push(DefDiagnostic::unconfigured_code(
+                        container,
+                        InFile::new(
+                            current_file_id,
+                            match field.ast_id {
+                                FieldAstId::Record(it) => it.upcast(),
+                                FieldAstId::Tuple(it) => it.upcast(),
+                            },
+                        ),
+                        attrs.cfg().unwrap(),
+                        cfg_options.clone(),
+                    ))
                 }
             }
-            VariantData::Tuple(arena)
+            (VariantData::Tuple(arena), diagnostics)
         }
-        Fields::Unit => VariantData::Unit,
+        Fields::Unit => (VariantData::Unit, diagnostics),
     }
 }
 
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 40b2f734b711..93ffe29a1fe8 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -97,12 +97,27 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast {
     #[salsa::invoke(StructData::struct_data_query)]
     fn struct_data(&self, id: StructId) -> Arc;
 
+    #[salsa::invoke(StructData::struct_data_with_diagnostics_query)]
+    fn struct_data_with_diagnostics(
+        &self,
+        id: StructId,
+    ) -> (Arc, Arc>);
+
     #[salsa::invoke(StructData::union_data_query)]
     fn union_data(&self, id: UnionId) -> Arc;
 
+    #[salsa::invoke(StructData::union_data_with_diagnostics_query)]
+    fn union_data_with_diagnostics(
+        &self,
+        id: UnionId,
+    ) -> (Arc, Arc>);
+
     #[salsa::invoke(EnumData::enum_data_query)]
     fn enum_data(&self, e: EnumId) -> Arc;
 
+    #[salsa::invoke(EnumData::enum_data_with_diagnostics_query)]
+    fn enum_data_with_diagnostics(&self, e: EnumId) -> (Arc, Arc>);
+
     #[salsa::invoke(ImplData::impl_data_query)]
     fn impl_data(&self, e: ImplId) -> Arc;
 
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 5f0cf9c4ac89..9ffc218818ca 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -32,8 +32,8 @@ use crate::{
     derive_macro_as_call_id,
     item_scope::{ImportType, PerNsGlobImports},
     item_tree::{
-        self, FieldAstId, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode,
-        MacroCall, MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
+        self, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, MacroCall,
+        MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
     },
     macro_call_as_call_id, macro_id_to_def_id,
     nameres::{
@@ -1511,10 +1511,7 @@ impl ModCollector<'_, '_> {
             let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
             if let Some(cfg) = attrs.cfg() {
                 if !self.is_cfg_enabled(&cfg) {
-                    self.emit_unconfigured_diagnostic(
-                        InFile::new(self.file_id(), item.ast_id(&self.item_tree).upcast()),
-                        &cfg,
-                    );
+                    self.emit_unconfigured_diagnostic(item, &cfg);
                     continue;
                 }
             }
@@ -1526,20 +1523,22 @@ impl ModCollector<'_, '_> {
             }
 
             let db = self.def_collector.db;
-            let module_id = self.module_id;
-            let module = self.def_collector.def_map.module_id(module_id);
+            let module = self.def_collector.def_map.module_id(self.module_id);
+            let def_map = &mut self.def_collector.def_map;
             let update_def =
                 |def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
-                    def_collector.def_map.modules[module_id].scope.declare(id);
+                    def_collector.def_map.modules[self.module_id].scope.declare(id);
                     def_collector.update(
-                        module_id,
+                        self.module_id,
                         &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
                         vis,
                         ImportType::Named,
                     )
                 };
             let resolve_vis = |def_map: &DefMap, visibility| {
-                def_map.resolve_visibility(db, module_id, visibility).unwrap_or(Visibility::Public)
+                def_map
+                    .resolve_visibility(db, self.module_id, visibility)
+                    .unwrap_or(Visibility::Public)
             };
 
             match item {
@@ -1595,7 +1594,6 @@ impl ModCollector<'_, '_> {
                     let fn_id =
                         FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
 
-                    let def_map = &self.def_collector.def_map;
                     let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
                     if self.def_collector.is_proc_macro {
                         if self.module_id == def_map.root {
@@ -1616,10 +1614,7 @@ impl ModCollector<'_, '_> {
                 ModItem::Struct(id) => {
                     let it = &self.item_tree[id];
 
-                    self.process_fields(&it.fields);
-
-                    let vis =
-                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
+                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1633,10 +1628,7 @@ impl ModCollector<'_, '_> {
                 ModItem::Union(id) => {
                     let it = &self.item_tree[id];
 
-                    self.process_fields(&it.fields);
-
-                    let vis =
-                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
+                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1650,21 +1642,7 @@ impl ModCollector<'_, '_> {
                 ModItem::Enum(id) => {
                     let it = &self.item_tree[id];
 
-                    for id in it.variants.clone() {
-                        let variant = &self.item_tree[id];
-                        let attrs = self.item_tree.attrs(self.def_collector.db, krate, id.into());
-                        if let Some(cfg) = attrs.cfg() {
-                            if !self.is_cfg_enabled(&cfg) {
-                                self.emit_unconfigured_diagnostic(
-                                    InFile::new(self.file_id(), variant.ast_id.upcast()),
-                                    &cfg,
-                                );
-                            }
-                        }
-                    }
-
-                    let vis =
-                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
+                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1682,10 +1660,7 @@ impl ModCollector<'_, '_> {
 
                     match &it.name {
                         Some(name) => {
-                            let vis = resolve_vis(
-                                &self.def_collector.def_map,
-                                &self.item_tree[it.visibility],
-                            );
+                            let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
                             update_def(self.def_collector, const_id.into(), name, vis, false);
                         }
                         None => {
@@ -1699,8 +1674,7 @@ impl ModCollector<'_, '_> {
                 ModItem::Static(id) => {
                     let it = &self.item_tree[id];
 
-                    let vis =
-                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
+                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
@@ -1714,8 +1688,7 @@ impl ModCollector<'_, '_> {
                 ModItem::Trait(id) => {
                     let it = &self.item_tree[id];
 
-                    let vis =
-                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
+                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1729,8 +1702,7 @@ impl ModCollector<'_, '_> {
                 ModItem::TypeAlias(id) => {
                     let it = &self.item_tree[id];
 
-                    let vis =
-                        resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
+                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
                         TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
@@ -2143,44 +2115,17 @@ impl ModCollector<'_, '_> {
         }
     }
 
-    fn process_fields(&mut self, fields: &Fields) {
-        match fields {
-            Fields::Record(range) | Fields::Tuple(range) => {
-                for id in range.clone() {
-                    let field = &self.item_tree[id];
-                    let attrs = self.item_tree.attrs(
-                        self.def_collector.db,
-                        self.def_collector.def_map.krate,
-                        id.into(),
-                    );
-                    if let Some(cfg) = attrs.cfg() {
-                        if !self.is_cfg_enabled(&cfg) {
-                            self.emit_unconfigured_diagnostic(
-                                InFile::new(
-                                    self.file_id(),
-                                    match field.ast_id {
-                                        FieldAstId::Record(it) => it.upcast(),
-                                        FieldAstId::Tuple(it) => it.upcast(),
-                                    },
-                                ),
-                                &cfg,
-                            );
-                        }
-                    }
-                }
-            }
-            Fields::Unit => {}
-        }
-    }
-
     fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool {
         self.def_collector.cfg_options.check(cfg) != Some(false)
     }
 
-    fn emit_unconfigured_diagnostic(&mut self, ast: AstId, cfg: &CfgExpr) {
+    fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
+        let ast_id = item.ast_id(self.item_tree);
+
+        let ast_id = InFile::new(self.file_id(), ast_id.upcast());
         self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
             self.module_id,
-            ast,
+            ast_id,
             cfg.clone(),
             self.def_collector.cfg_options.clone(),
         ));
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index e1f69001e800..d1c8fa59aef4 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -540,9 +540,27 @@ impl Module {
                     }
                     acc.extend(decl.diagnostics(db))
                 }
-                ModuleDef::Adt(Adt::Enum(e)) => {
-                    for v in e.variants(db) {
-                        acc.extend(ModuleDef::Variant(v).diagnostics(db));
+                ModuleDef::Adt(adt) => {
+                    match adt {
+                        Adt::Struct(s) => {
+                            for diag in db.struct_data_with_diagnostics(s.id).1.iter() {
+                                emit_def_diagnostic(db, acc, diag);
+                            }
+                        }
+                        Adt::Union(u) => {
+                            for diag in db.union_data_with_diagnostics(u.id).1.iter() {
+                                emit_def_diagnostic(db, acc, diag);
+                            }
+                        }
+                        Adt::Enum(e) => {
+                            for v in e.variants(db) {
+                                acc.extend(ModuleDef::Variant(v).diagnostics(db));
+                            }
+
+                            for diag in db.enum_data_with_diagnostics(e.id).1.iter() {
+                                emit_def_diagnostic(db, acc, diag);
+                            }
+                        }
                     }
                     acc.extend(decl.diagnostics(db))
                 }
diff --git a/crates/ide-diagnostics/src/handlers/inactive_code.rs b/crates/ide-diagnostics/src/handlers/inactive_code.rs
index c22e25b0637d..f558b7256a4c 100644
--- a/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -142,12 +142,18 @@ trait Bar {
     }
 
     #[test]
-    fn inactive_fields() {
+    fn inactive_fields_and_variants() {
         check(
             r#"
 enum Foo {
   #[cfg(a)] Bar,
 //^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
+  Baz {
+    #[cfg(a)] baz: String,
+  //^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
+  },
+  Qux(#[cfg(a)] String),
+    //^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
 }
 
 struct Baz {

From 3a8d84b4a39098014dcfeb9925d76fbac15a1bc3 Mon Sep 17 00:00:00 2001
From: unexge 
Date: Mon, 26 Sep 2022 19:16:02 +0100
Subject: [PATCH 053/175] Use `Arc<[DefDiagnostic]>` instead of
 `Arc>`

---
 crates/hir-def/src/adt.rs  | 12 ++++++------
 crates/hir-def/src/data.rs |  8 ++++----
 crates/hir-def/src/db.rs   | 18 ++++++------------
 3 files changed, 16 insertions(+), 22 deletions(-)

diff --git a/crates/hir-def/src/adt.rs b/crates/hir-def/src/adt.rs
index af8ca8571ba2..938db032fbc8 100644
--- a/crates/hir-def/src/adt.rs
+++ b/crates/hir-def/src/adt.rs
@@ -151,7 +151,7 @@ impl StructData {
     pub(crate) fn struct_data_with_diagnostics_query(
         db: &dyn DefDatabase,
         id: StructId,
-    ) -> (Arc, Arc>) {
+    ) -> (Arc, Arc<[DefDiagnostic]>) {
         let loc = id.lookup(db);
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
@@ -176,7 +176,7 @@ impl StructData {
                 repr,
                 visibility: item_tree[strukt.visibility].clone(),
             }),
-            Arc::new(diagnostics),
+            diagnostics.into(),
         )
     }
 
@@ -187,7 +187,7 @@ impl StructData {
     pub(crate) fn union_data_with_diagnostics_query(
         db: &dyn DefDatabase,
         id: UnionId,
-    ) -> (Arc, Arc>) {
+    ) -> (Arc, Arc<[DefDiagnostic]>) {
         let loc = id.lookup(db);
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
@@ -212,7 +212,7 @@ impl StructData {
                 repr,
                 visibility: item_tree[union.visibility].clone(),
             }),
-            Arc::new(diagnostics),
+            diagnostics.into(),
         )
     }
 }
@@ -225,7 +225,7 @@ impl EnumData {
     pub(crate) fn enum_data_with_diagnostics_query(
         db: &dyn DefDatabase,
         e: EnumId,
-    ) -> (Arc, Arc>) {
+    ) -> (Arc, Arc<[DefDiagnostic]>) {
         let loc = e.lookup(db);
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
@@ -272,7 +272,7 @@ impl EnumData {
                 repr,
                 visibility: item_tree[enum_.visibility].clone(),
             }),
-            Arc::new(diagnostics),
+            diagnostics.into(),
         )
     }
 
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index 631ae3cf11fa..2dc69b00ace0 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -219,7 +219,7 @@ impl TraitData {
     pub(crate) fn trait_data_with_diagnostics_query(
         db: &dyn DefDatabase,
         tr: TraitId,
-    ) -> (Arc, Arc>) {
+    ) -> (Arc, Arc<[DefDiagnostic]>) {
         let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
         let item_tree = tree_id.item_tree(db);
         let tr_def = &item_tree[tree_id.value];
@@ -251,7 +251,7 @@ impl TraitData {
                 visibility,
                 skip_array_during_method_dispatch,
             }),
-            Arc::new(diagnostics),
+            diagnostics.into(),
         )
     }
 
@@ -299,7 +299,7 @@ impl ImplData {
     pub(crate) fn impl_data_with_diagnostics_query(
         db: &dyn DefDatabase,
         id: ImplId,
-    ) -> (Arc, Arc>) {
+    ) -> (Arc, Arc<[DefDiagnostic]>) {
         let _p = profile::span("impl_data_with_diagnostics_query");
         let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
 
@@ -318,7 +318,7 @@ impl ImplData {
 
         (
             Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }),
-            Arc::new(diagnostics),
+            diagnostics.into(),
         )
     }
 
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 93ffe29a1fe8..431c8255497b 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -98,38 +98,32 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast {
     fn struct_data(&self, id: StructId) -> Arc;
 
     #[salsa::invoke(StructData::struct_data_with_diagnostics_query)]
-    fn struct_data_with_diagnostics(
-        &self,
-        id: StructId,
-    ) -> (Arc, Arc>);
+    fn struct_data_with_diagnostics(&self, id: StructId)
+        -> (Arc, Arc<[DefDiagnostic]>);
 
     #[salsa::invoke(StructData::union_data_query)]
     fn union_data(&self, id: UnionId) -> Arc;
 
     #[salsa::invoke(StructData::union_data_with_diagnostics_query)]
-    fn union_data_with_diagnostics(
-        &self,
-        id: UnionId,
-    ) -> (Arc, Arc>);
+    fn union_data_with_diagnostics(&self, id: UnionId) -> (Arc, Arc<[DefDiagnostic]>);
 
     #[salsa::invoke(EnumData::enum_data_query)]
     fn enum_data(&self, e: EnumId) -> Arc;
 
     #[salsa::invoke(EnumData::enum_data_with_diagnostics_query)]
-    fn enum_data_with_diagnostics(&self, e: EnumId) -> (Arc, Arc>);
+    fn enum_data_with_diagnostics(&self, e: EnumId) -> (Arc, Arc<[DefDiagnostic]>);
 
     #[salsa::invoke(ImplData::impl_data_query)]
     fn impl_data(&self, e: ImplId) -> Arc;
 
     #[salsa::invoke(ImplData::impl_data_with_diagnostics_query)]
-    fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc, Arc>);
+    fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc, Arc<[DefDiagnostic]>);
 
     #[salsa::invoke(TraitData::trait_data_query)]
     fn trait_data(&self, e: TraitId) -> Arc;
 
     #[salsa::invoke(TraitData::trait_data_with_diagnostics_query)]
-    fn trait_data_with_diagnostics(&self, tr: TraitId)
-        -> (Arc, Arc>);
+    fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc, Arc<[DefDiagnostic]>);
 
     #[salsa::invoke(TypeAliasData::type_alias_data_query)]
     fn type_alias_data(&self, e: TypeAliasId) -> Arc;

From 7e5e5177b60c7986d6d8b776b112219d99d23969 Mon Sep 17 00:00:00 2001
From: unexge 
Date: Mon, 26 Sep 2022 19:29:28 +0100
Subject: [PATCH 054/175] Generate `From` impls manually

---
 crates/syntax/src/ast/generated/nodes.rs | 567 -----------------------
 crates/syntax/src/ast/node_ext.rs        |  30 ++
 crates/syntax/src/tests/sourcegen_ast.rs |  34 --
 3 files changed, 30 insertions(+), 601 deletions(-)

diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index f4664f3aaeae..449402e5f5b3 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -3894,12 +3894,6 @@ impl AstNode for AnyHasArgList {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl From for AnyHasArgList {
-    fn from(node: CallExpr) -> AnyHasArgList { AnyHasArgList::new(node) }
-}
-impl From for AnyHasArgList {
-    fn from(node: MethodCallExpr) -> AnyHasArgList { AnyHasArgList::new(node) }
-}
 impl AnyHasAttrs {
     #[inline]
     pub fn new(node: T) -> AnyHasAttrs {
@@ -3984,207 +3978,6 @@ impl AstNode for AnyHasAttrs {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl From for AnyHasAttrs {
-    fn from(node: MacroCall) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: SourceFile) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Const) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Enum) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ExternBlock) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ExternCrate) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Fn) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Impl) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: MacroRules) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: MacroDef) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Module) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Static) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Struct) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Trait) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: TypeAlias) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Union) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Use) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ItemList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: BlockExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: SelfParam) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Param) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: RecordField) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: TupleField) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Variant) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: AssocItemList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ExternItemList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ConstParam) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: LifetimeParam) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: TypeParam) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: LetStmt) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ArrayExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: AwaitExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: BinExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: BoxExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: BreakExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: CallExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: CastExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ClosureExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ContinueExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: FieldExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ForExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: IfExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: IndexExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Literal) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: LoopExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: MatchExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: MethodCallExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ParenExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: PathExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: PrefixExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: RangeExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: RefExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ReturnExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: TryExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: TupleExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: WhileExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: YieldExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: LetExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: UnderscoreExpr) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: StmtList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: RecordExprFieldList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: RecordExprField) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: MatchArmList) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: MatchArm) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: IdentPat) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: RestPat) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: RecordPatField) -> AnyHasAttrs { AnyHasAttrs::new(node) }
-}
 impl AnyHasDocComments {
     #[inline]
     pub fn new(node: T) -> AnyHasDocComments {
@@ -4222,66 +4015,6 @@ impl AstNode for AnyHasDocComments {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl From for AnyHasDocComments {
-    fn from(node: MacroCall) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: SourceFile) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Const) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Enum) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: ExternBlock) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: ExternCrate) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Fn) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Impl) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: MacroRules) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: MacroDef) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Module) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Static) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Struct) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Trait) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: TypeAlias) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Union) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Use) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: RecordField) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: TupleField) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Variant) -> AnyHasDocComments { AnyHasDocComments::new(node) }
-}
 impl AnyHasGenericParams {
     #[inline]
     pub fn new(node: T) -> AnyHasGenericParams {
@@ -4297,27 +4030,6 @@ impl AstNode for AnyHasGenericParams {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl From for AnyHasGenericParams {
-    fn from(node: Enum) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
-}
-impl From for AnyHasGenericParams {
-    fn from(node: Fn) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
-}
-impl From for AnyHasGenericParams {
-    fn from(node: Impl) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
-}
-impl From for AnyHasGenericParams {
-    fn from(node: Struct) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
-}
-impl From for AnyHasGenericParams {
-    fn from(node: Trait) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
-}
-impl From for AnyHasGenericParams {
-    fn from(node: TypeAlias) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
-}
-impl From for AnyHasGenericParams {
-    fn from(node: Union) -> AnyHasGenericParams { AnyHasGenericParams::new(node) }
-}
 impl AnyHasLoopBody {
     #[inline]
     pub fn new(node: T) -> AnyHasLoopBody {
@@ -4331,15 +4043,6 @@ impl AstNode for AnyHasLoopBody {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl From for AnyHasLoopBody {
-    fn from(node: ForExpr) -> AnyHasLoopBody { AnyHasLoopBody::new(node) }
-}
-impl From for AnyHasLoopBody {
-    fn from(node: LoopExpr) -> AnyHasLoopBody { AnyHasLoopBody::new(node) }
-}
-impl From for AnyHasLoopBody {
-    fn from(node: WhileExpr) -> AnyHasLoopBody { AnyHasLoopBody::new(node) }
-}
 impl AnyHasModuleItem {
     #[inline]
     pub fn new(node: T) -> AnyHasModuleItem {
@@ -4353,15 +4056,6 @@ impl AstNode for AnyHasModuleItem {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl From for AnyHasModuleItem {
-    fn from(node: MacroItems) -> AnyHasModuleItem { AnyHasModuleItem::new(node) }
-}
-impl From for AnyHasModuleItem {
-    fn from(node: SourceFile) -> AnyHasModuleItem { AnyHasModuleItem::new(node) }
-}
-impl From for AnyHasModuleItem {
-    fn from(node: ItemList) -> AnyHasModuleItem { AnyHasModuleItem::new(node) }
-}
 impl AnyHasName {
     #[inline]
     pub fn new(node: T) -> AnyHasName {
@@ -4397,60 +4091,6 @@ impl AstNode for AnyHasName {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl From for AnyHasName {
-    fn from(node: Const) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: Enum) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: Fn) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: MacroRules) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: MacroDef) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: Module) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: Static) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: Struct) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: Trait) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: TypeAlias) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: Union) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: Rename) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: SelfParam) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: RecordField) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: Variant) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: ConstParam) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: TypeParam) -> AnyHasName { AnyHasName::new(node) }
-}
-impl From for AnyHasName {
-    fn from(node: IdentPat) -> AnyHasName { AnyHasName::new(node) }
-}
 impl AnyHasTypeBounds {
     #[inline]
     pub fn new(node: T) -> AnyHasTypeBounds {
@@ -4469,24 +4109,6 @@ impl AstNode for AnyHasTypeBounds {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl From for AnyHasTypeBounds {
-    fn from(node: AssocTypeArg) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
-}
-impl From for AnyHasTypeBounds {
-    fn from(node: Trait) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
-}
-impl From for AnyHasTypeBounds {
-    fn from(node: TypeAlias) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
-}
-impl From for AnyHasTypeBounds {
-    fn from(node: LifetimeParam) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
-}
-impl From for AnyHasTypeBounds {
-    fn from(node: TypeParam) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
-}
-impl From for AnyHasTypeBounds {
-    fn from(node: WherePred) -> AnyHasTypeBounds { AnyHasTypeBounds::new(node) }
-}
 impl AnyHasVisibility {
     #[inline]
     pub fn new(node: T) -> AnyHasVisibility {
@@ -4521,195 +4143,6 @@ impl AstNode for AnyHasVisibility {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl From for AnyHasVisibility {
-    fn from(node: Const) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: Enum) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: ExternCrate) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: Fn) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: Impl) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: MacroRules) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: MacroDef) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: Module) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: Static) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: Struct) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: Trait) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: TypeAlias) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: Union) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: Use) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: RecordField) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: TupleField) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasVisibility {
-    fn from(node: Variant) -> AnyHasVisibility { AnyHasVisibility::new(node) }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Item) -> AnyHasAttrs {
-        match node {
-            Item::Const(it) => AnyHasAttrs::new(it),
-            Item::Enum(it) => AnyHasAttrs::new(it),
-            Item::ExternBlock(it) => AnyHasAttrs::new(it),
-            Item::ExternCrate(it) => AnyHasAttrs::new(it),
-            Item::Fn(it) => AnyHasAttrs::new(it),
-            Item::Impl(it) => AnyHasAttrs::new(it),
-            Item::MacroCall(it) => AnyHasAttrs::new(it),
-            Item::MacroRules(it) => AnyHasAttrs::new(it),
-            Item::MacroDef(it) => AnyHasAttrs::new(it),
-            Item::Module(it) => AnyHasAttrs::new(it),
-            Item::Static(it) => AnyHasAttrs::new(it),
-            Item::Struct(it) => AnyHasAttrs::new(it),
-            Item::Trait(it) => AnyHasAttrs::new(it),
-            Item::TypeAlias(it) => AnyHasAttrs::new(it),
-            Item::Union(it) => AnyHasAttrs::new(it),
-            Item::Use(it) => AnyHasAttrs::new(it),
-        }
-    }
-}
-impl From for AnyHasAttrs {
-    fn from(node: Adt) -> AnyHasAttrs {
-        match node {
-            Adt::Enum(it) => AnyHasAttrs::new(it),
-            Adt::Struct(it) => AnyHasAttrs::new(it),
-            Adt::Union(it) => AnyHasAttrs::new(it),
-        }
-    }
-}
-impl From for AnyHasAttrs {
-    fn from(node: AssocItem) -> AnyHasAttrs {
-        match node {
-            AssocItem::Const(it) => AnyHasAttrs::new(it),
-            AssocItem::Fn(it) => AnyHasAttrs::new(it),
-            AssocItem::MacroCall(it) => AnyHasAttrs::new(it),
-            AssocItem::TypeAlias(it) => AnyHasAttrs::new(it),
-        }
-    }
-}
-impl From for AnyHasAttrs {
-    fn from(node: ExternItem) -> AnyHasAttrs {
-        match node {
-            ExternItem::Fn(it) => AnyHasAttrs::new(it),
-            ExternItem::MacroCall(it) => AnyHasAttrs::new(it),
-            ExternItem::Static(it) => AnyHasAttrs::new(it),
-            ExternItem::TypeAlias(it) => AnyHasAttrs::new(it),
-        }
-    }
-}
-impl From for AnyHasAttrs {
-    fn from(node: GenericParam) -> AnyHasAttrs {
-        match node {
-            GenericParam::ConstParam(it) => AnyHasAttrs::new(it),
-            GenericParam::LifetimeParam(it) => AnyHasAttrs::new(it),
-            GenericParam::TypeParam(it) => AnyHasAttrs::new(it),
-        }
-    }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Item) -> AnyHasDocComments {
-        match node {
-            Item::Const(it) => AnyHasDocComments::new(it),
-            Item::Enum(it) => AnyHasDocComments::new(it),
-            Item::ExternBlock(it) => AnyHasDocComments::new(it),
-            Item::ExternCrate(it) => AnyHasDocComments::new(it),
-            Item::Fn(it) => AnyHasDocComments::new(it),
-            Item::Impl(it) => AnyHasDocComments::new(it),
-            Item::MacroCall(it) => AnyHasDocComments::new(it),
-            Item::MacroRules(it) => AnyHasDocComments::new(it),
-            Item::MacroDef(it) => AnyHasDocComments::new(it),
-            Item::Module(it) => AnyHasDocComments::new(it),
-            Item::Static(it) => AnyHasDocComments::new(it),
-            Item::Struct(it) => AnyHasDocComments::new(it),
-            Item::Trait(it) => AnyHasDocComments::new(it),
-            Item::TypeAlias(it) => AnyHasDocComments::new(it),
-            Item::Union(it) => AnyHasDocComments::new(it),
-            Item::Use(it) => AnyHasDocComments::new(it),
-        }
-    }
-}
-impl From for AnyHasDocComments {
-    fn from(node: Adt) -> AnyHasDocComments {
-        match node {
-            Adt::Enum(it) => AnyHasDocComments::new(it),
-            Adt::Struct(it) => AnyHasDocComments::new(it),
-            Adt::Union(it) => AnyHasDocComments::new(it),
-        }
-    }
-}
-impl From for AnyHasDocComments {
-    fn from(node: AssocItem) -> AnyHasDocComments {
-        match node {
-            AssocItem::Const(it) => AnyHasDocComments::new(it),
-            AssocItem::Fn(it) => AnyHasDocComments::new(it),
-            AssocItem::MacroCall(it) => AnyHasDocComments::new(it),
-            AssocItem::TypeAlias(it) => AnyHasDocComments::new(it),
-        }
-    }
-}
-impl From for AnyHasDocComments {
-    fn from(node: ExternItem) -> AnyHasDocComments {
-        match node {
-            ExternItem::Fn(it) => AnyHasDocComments::new(it),
-            ExternItem::MacroCall(it) => AnyHasDocComments::new(it),
-            ExternItem::Static(it) => AnyHasDocComments::new(it),
-            ExternItem::TypeAlias(it) => AnyHasDocComments::new(it),
-        }
-    }
-}
-impl From for AnyHasGenericParams {
-    fn from(node: Adt) -> AnyHasGenericParams {
-        match node {
-            Adt::Enum(it) => AnyHasGenericParams::new(it),
-            Adt::Struct(it) => AnyHasGenericParams::new(it),
-            Adt::Union(it) => AnyHasGenericParams::new(it),
-        }
-    }
-}
-impl From for AnyHasName {
-    fn from(node: Adt) -> AnyHasName {
-        match node {
-            Adt::Enum(it) => AnyHasName::new(it),
-            Adt::Struct(it) => AnyHasName::new(it),
-            Adt::Union(it) => AnyHasName::new(it),
-        }
-    }
-}
-impl From for AnyHasVisibility {
-    fn from(node: Adt) -> AnyHasVisibility {
-        match node {
-            Adt::Enum(it) => AnyHasVisibility::new(it),
-            Adt::Struct(it) => AnyHasVisibility::new(it),
-            Adt::Union(it) => AnyHasVisibility::new(it),
-        }
-    }
-}
 impl std::fmt::Display for GenericArg {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index bb92c51e9a90..fe82aa907222 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -873,3 +873,33 @@ impl ast::MatchGuard {
         support::child(&self.syntax)
     }
 }
+
+impl From for ast::AnyHasAttrs {
+    fn from(node: ast::Item) -> Self {
+        Self::new(node)
+    }
+}
+
+impl From for ast::AnyHasAttrs {
+    fn from(node: ast::AssocItem) -> Self {
+        Self::new(node)
+    }
+}
+
+impl From for ast::AnyHasAttrs {
+    fn from(node: ast::Variant) -> Self {
+        Self::new(node)
+    }
+}
+
+impl From for ast::AnyHasAttrs {
+    fn from(node: ast::RecordField) -> Self {
+        Self::new(node)
+    }
+}
+
+impl From for ast::AnyHasAttrs {
+    fn from(node: ast::TupleField) -> Self {
+        Self::new(node)
+    }
+}
diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs
index 56d7c98d58a3..70b54843dbaa 100644
--- a/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/crates/syntax/src/tests/sourcegen_ast.rs
@@ -229,7 +229,6 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
                 .iter()
                 .map(|name| format_ident!("{}", to_upper_snake_case(&name.name.to_string())))
                 .collect();
-            let node_names: Vec<_> = nodes.iter().map(|n| format_ident!("{}", n.name)).collect();
 
             (
                 quote! {
@@ -260,43 +259,11 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
                             &self.syntax
                         }
                     }
-
-                    #(
-                        impl From<#node_names> for #name {
-                            fn from(node: #node_names) -> #name {
-                                #name::new(node)
-                            }
-                        }
-                    )*
                 },
             )
         })
         .unzip();
 
-    let any_enum_boilerplate_impls: Vec<_> = grammar
-        .enums
-        .iter()
-        .flat_map(|en| en.traits.iter().map(move |t| (t, en)))
-        .sorted_by_key(|(k, _)| *k)
-        .map(|(target_name, en)| {
-            let target_name = format_ident!("Any{}", target_name);
-            let enum_name = format_ident!("{}", en.name);
-            let variants: Vec<_> = en.variants.iter().map(|var| format_ident!("{}", var)).collect();
-
-            quote! {
-                impl From<#enum_name> for #target_name {
-                    fn from(node: #enum_name) -> #target_name {
-                        match node {
-                            #(
-                                #enum_name::#variants(it) => #target_name::new(it),
-                            )*
-                        }
-                    }
-                }
-            }
-        })
-        .collect();
-
     let enum_names = grammar.enums.iter().map(|it| &it.name);
     let node_names = grammar.nodes.iter().map(|it| &it.name);
 
@@ -338,7 +305,6 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
         #(#node_boilerplate_impls)*
         #(#enum_boilerplate_impls)*
         #(#any_node_boilerplate_impls)*
-        #(#any_enum_boilerplate_impls)*
         #(#display_impls)*
     };
 

From fb736449fd939e2727a204ed1c52f1df805a1437 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Tue, 27 Sep 2022 13:52:04 +0200
Subject: [PATCH 055/175] Use cfg(any()) instead of cfg(FALSE) for disabling
 proc-macro test

---
 crates/rust-analyzer/tests/slow-tests/main.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs
index 3e3f1c162f52..9032c21d096b 100644
--- a/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -821,7 +821,7 @@ fn main() {
 
 #[test]
 // FIXME: Re-enable once we can run proc-macro tests on rust-lang/rust-analyzer again
-#[cfg(FALSE)]
+#[cfg(any())]
 fn resolve_proc_macro() {
     use expect_test::expect;
     if skip_slow_tests() {

From c3a6c963e5f18677a3680e6066a2b9a5b90dfd21 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Thu, 15 Sep 2022 21:19:57 +0200
Subject: [PATCH 056/175] Amalgamate file changes for the same file ids in
 process_changes

When receiving multiple change events for a single file id where the
last change is a delete the server panics, as it tries to access the
file contents of a deleted file. This occurs due to the VFS changes and
the in memory file contents being updated immediately, while
`process_changes` processes the events afterwards in sequence which no
longer works as it will only observe the final file contents. By
folding these events together, we will no longer try to process these
intermediate changes, as they aren't relevant anyways.

Potentially fixes https://github.com/rust-lang/rust-analyzer/issues/13236
---
 crates/rust-analyzer/src/global_state.rs | 39 +++++++++++++++++++++++-
 1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 92df4d70fd90..55fa616d5070 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -185,11 +185,48 @@ impl GlobalState {
         let (change, changed_files) = {
             let mut change = Change::new();
             let (vfs, line_endings_map) = &mut *self.vfs.write();
-            let changed_files = vfs.take_changes();
+            let mut changed_files = vfs.take_changes();
             if changed_files.is_empty() {
                 return false;
             }
 
+            // important: this needs to be a stable sort, the order between changes is relevant
+            // for the same file ids
+            changed_files.sort_by_key(|file| file.file_id);
+            // We need to fix up the changed events a bit, if we have a create or modify for a file
+            // id that is followed by a delete we actually no longer observe the file text from the
+            // create or modify which may cause problems later on
+            changed_files.dedup_by(|a, b| {
+                use vfs::ChangeKind::*;
+
+                if a.file_id != b.file_id {
+                    return false;
+                }
+
+                match (a.change_kind, b.change_kind) {
+                    // duplicate can be merged
+                    (Create, Create) | (Modify, Modify) | (Delete, Delete) => true,
+                    // just leave the create, modify is irrelevant
+                    (Create, Modify) => {
+                        std::mem::swap(a, b);
+                        true
+                    }
+                    // modify becomes irrelevant if the file is deleted
+                    (Modify, Delete) => true,
+                    // we should fully remove this occurrence,
+                    // but leaving just a delete works as well
+                    (Create, Delete) => true,
+                    // this is equivalent to a modify
+                    (Delete, Create) => {
+                        a.change_kind = Modify;
+                        true
+                    }
+                    // can't really occur
+                    (Modify, Create) => false,
+                    (Delete, Modify) => false,
+                }
+            });
+
             for file in &changed_files {
                 if let Some(path) = vfs.file_path(file.file_id).as_path() {
                     let path = path.to_path_buf();

From 1a6c1595fe6645f4dda511465e41f781c3206d09 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Wed, 7 Sep 2022 13:52:55 +0200
Subject: [PATCH 057/175] Don't retry requests that have already been cancelled

---
 Cargo.lock                               | 14 +++++++-------
 crates/rust-analyzer/Cargo.toml          |  2 +-
 crates/rust-analyzer/src/global_state.rs |  4 ++++
 crates/rust-analyzer/src/main_loop.rs    |  4 +++-
 lib/lsp-server/Cargo.toml                | 10 +++++-----
 lib/lsp-server/src/msg.rs                |  2 +-
 lib/lsp-server/src/req_queue.rs          |  7 +++++++
 7 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 216cf51447fa..93b7f746e01b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -863,7 +863,7 @@ dependencies = [
 
 [[package]]
 name = "lsp-server"
-version = "0.6.0"
+version = "0.7.0"
 dependencies = [
  "crossbeam-channel",
  "log",
@@ -1502,18 +1502,18 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.143"
+version = "1.0.144"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
+checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.143"
+version = "1.0.144"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
+checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1522,9 +1522,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.83"
+version = "1.0.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
+checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
 dependencies = [
  "indexmap",
  "itoa",
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 861753d6fb41..71566d5de6e6 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -34,7 +34,7 @@ threadpool = "1.8.1"
 rayon = "1.5.3"
 num_cpus = "1.13.1"
 mimalloc = { version = "0.1.29", default-features = false, optional = true }
-lsp-server = { version = "0.6.0", path = "../../lib/lsp-server" }
+lsp-server = { version = "0.7.0", path = "../../lib/lsp-server" }
 tracing = "0.1.35"
 tracing-subscriber = { version = "0.3.14", default-features = false, features = [
     "env-filter",
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 55fa616d5070..000ff88e458f 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -354,6 +354,10 @@ impl GlobalState {
         }
     }
 
+    pub(crate) fn is_completed(&self, request: &lsp_server::Request) -> bool {
+        self.req_queue.incoming.is_completed(&request.id)
+    }
+
     fn send(&mut self, message: lsp_server::Message) {
         self.sender.send(message).unwrap()
     }
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 3cfbc2e4e450..c64d557a118f 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -425,7 +425,9 @@ impl GlobalState {
     fn handle_task(&mut self, prime_caches_progress: &mut Vec, task: Task) {
         match task {
             Task::Response(response) => self.respond(response),
-            Task::Retry(req) => self.on_request(req),
+            // Only retry requests that haven't been cancelled. Otherwise we do unnecessary work.
+            Task::Retry(req) if self.is_completed(&req) => self.on_request(req),
+            Task::Retry(_) => (),
             Task::Diagnostics(diagnostics_per_file) => {
                 for (file_id, diagnostics) in diagnostics_per_file {
                     self.diagnostics.set_native_diagnostics(file_id, diagnostics)
diff --git a/lib/lsp-server/Cargo.toml b/lib/lsp-server/Cargo.toml
index 204d120d07c4..b236b156cf99 100644
--- a/lib/lsp-server/Cargo.toml
+++ b/lib/lsp-server/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "lsp-server"
-version = "0.6.0"
+version = "0.7.0"
 description = "Generic LSP server scaffold."
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/lsp-server"
@@ -8,9 +8,9 @@ edition = "2021"
 
 [dependencies]
 log = "0.4.17"
-serde_json = "1.0.81"
-serde = { version = "1.0.137", features = ["derive"] }
-crossbeam-channel = "0.5.5"
+serde_json = "1.0.85"
+serde = { version = "1.0.144", features = ["derive"] }
+crossbeam-channel = "0.5.6"
 
 [dev-dependencies]
-lsp-types = "0.93.0"
+lsp-types = "0.93.1"
diff --git a/lib/lsp-server/src/msg.rs b/lib/lsp-server/src/msg.rs
index ce00d37beb40..b241561f9c0d 100644
--- a/lib/lsp-server/src/msg.rs
+++ b/lib/lsp-server/src/msg.rs
@@ -98,7 +98,7 @@ pub struct ResponseError {
 }
 
 #[derive(Clone, Copy, Debug)]
-#[allow(unused)]
+#[non_exhaustive]
 pub enum ErrorCode {
     // Defined by JSON RPC:
     ParseError = -32700,
diff --git a/lib/lsp-server/src/req_queue.rs b/lib/lsp-server/src/req_queue.rs
index 1f3d447153bd..e5f19be20b06 100644
--- a/lib/lsp-server/src/req_queue.rs
+++ b/lib/lsp-server/src/req_queue.rs
@@ -35,6 +35,7 @@ impl Incoming {
     pub fn register(&mut self, id: RequestId, data: I) {
         self.pending.insert(id, data);
     }
+
     pub fn cancel(&mut self, id: RequestId) -> Option {
         let _data = self.complete(id.clone())?;
         let error = ResponseError {
@@ -44,9 +45,14 @@ impl Incoming {
         };
         Some(Response { id, result: None, error: Some(error) })
     }
+
     pub fn complete(&mut self, id: RequestId) -> Option {
         self.pending.remove(&id)
     }
+
+    pub fn is_completed(&self, id: &RequestId) -> bool {
+        !self.pending.contains_key(id)
+    }
 }
 
 impl Outgoing {
@@ -56,6 +62,7 @@ impl Outgoing {
         self.next_id += 1;
         Request::new(id, method, params)
     }
+
     pub fn complete(&mut self, id: RequestId) -> Option {
         self.pending.remove(&id)
     }

From f5fe6b157f8b653d2eeee2cba59dd5881391ee2a Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Tue, 27 Sep 2022 17:35:55 +0200
Subject: [PATCH 058/175] Make assist tests panic again on empty source changes

---
 crates/ide-assists/src/tests.rs | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs
index 258144bae3d0..a3bb66e379eb 100644
--- a/crates/ide-assists/src/tests.rs
+++ b/crates/ide-assists/src/tests.rs
@@ -96,8 +96,10 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
         });
 
     let actual = {
-        let source_change =
-            assist.source_change.expect("Assist did not contain any source changes");
+        let source_change = assist
+            .source_change
+            .filter(|it| !it.source_file_edits.is_empty() || !it.file_system_edits.is_empty())
+            .expect("Assist did not contain any source changes");
         let mut actual = before;
         if let Some(source_file_edit) = source_change.get_source_edit(file_id) {
             source_file_edit.apply(&mut actual);
@@ -140,8 +142,10 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult<'_>, assist_la
 
     match (assist, expected) {
         (Some(assist), ExpectedResult::After(after)) => {
-            let source_change =
-                assist.source_change.expect("Assist did not contain any source changes");
+            let source_change = assist
+                .source_change
+                .filter(|it| !it.source_file_edits.is_empty() || !it.file_system_edits.is_empty())
+                .expect("Assist did not contain any source changes");
             let skip_header = source_change.source_file_edits.len() == 1
                 && source_change.file_system_edits.len() == 0;
 

From b0b9f5bc269f5c5c1330bf30d25faf85741b2d49 Mon Sep 17 00:00:00 2001
From: joboet 
Date: Wed, 28 Sep 2022 16:54:00 +0200
Subject: [PATCH 059/175] std: never panic in `thread::park` and
 `thread::park_timeout`

---
 library/std/src/thread/mod.rs | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index ceea6986e333..54d611182e80 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -160,7 +160,7 @@ use crate::ffi::{CStr, CString};
 use crate::fmt;
 use crate::io;
 use crate::marker::PhantomData;
-use crate::mem;
+use crate::mem::{self, forget};
 use crate::num::NonZeroU64;
 use crate::num::NonZeroUsize;
 use crate::panic;
@@ -849,10 +849,22 @@ pub fn sleep(dur: Duration) {
     imp::Thread::sleep(dur)
 }
 
+/// Used to ensure that `park` and `park_timeout` do not unwind, as that can
+/// cause undefined behaviour if not handled correctly (see #102398 for context).
+struct PanicGuard;
+
+impl Drop for PanicGuard {
+    fn drop(&mut self) {
+        rtabort!("an irrecoverable error occurred while synchronizing threads")
+    }
+}
+
 /// Blocks unless or until the current thread's token is made available.
 ///
 /// A call to `park` does not guarantee that the thread will remain parked
-/// forever, and callers should be prepared for this possibility.
+/// forever, and callers should be prepared for this possibility. However,
+/// it is guaranteed that this function will not panic (it may abort the
+/// process if the implementation encounters some rare errors).
 ///
 /// # park and unpark
 ///
@@ -937,10 +949,13 @@ pub fn sleep(dur: Duration) {
 /// [`thread::park_timeout`]: park_timeout
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn park() {
+    let guard = PanicGuard;
     // SAFETY: park_timeout is called on the parker owned by this thread.
     unsafe {
         current().inner.as_ref().parker().park();
     }
+    // No panic occurred, do not abort.
+    forget(guard);
 }
 
 /// Use [`park_timeout`].
@@ -1001,10 +1016,13 @@ pub fn park_timeout_ms(ms: u32) {
 /// ```
 #[stable(feature = "park_timeout", since = "1.4.0")]
 pub fn park_timeout(dur: Duration) {
+    let guard = PanicGuard;
     // SAFETY: park_timeout is called on the parker owned by this thread.
     unsafe {
         current().inner.as_ref().parker().park_timeout(dur);
     }
+    // No panic occurred, do not abort.
+    forget(guard);
 }
 
 ////////////////////////////////////////////////////////////////////////////////

From 9d5e3a1f45a1f62e9826208b922cccf064d619c1 Mon Sep 17 00:00:00 2001
From: John Millikin 
Date: Sun, 18 Sep 2022 10:53:35 +0900
Subject: [PATCH 060/175] Add `is_empty()` method to `core::ffi::CStr`.

---
 library/core/src/ffi/c_str.rs | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 21f80ec025a8..55e58c4e0baa 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -474,6 +474,34 @@ impl CStr {
         self.inner.as_ptr()
     }
 
+    /// Returns `true` if `self.to_bytes()` has a length of 0.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(cstr_is_empty)]
+    ///
+    /// use std::ffi::CStr;
+    /// # use std::ffi::FromBytesWithNulError;
+    ///
+    /// # fn main() { test().unwrap(); }
+    /// # fn test() -> Result<(), FromBytesWithNulError> {
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0")?;
+    /// assert!(!cstr.is_empty());
+    ///
+    /// let empty_cstr = CStr::from_bytes_with_nul(b"\0")?;
+    /// assert!(empty_cstr.is_empty());
+    /// # Ok(())
+    /// # }
+    /// ```
+    #[inline]
+    #[unstable(feature = "cstr_is_empty", issue = "102444")]
+    pub const fn is_empty(&self) -> bool {
+        // SAFETY: We know there is at least one byte; for empty strings it
+        // is the NUL terminator.
+        (unsafe { self.inner.get_unchecked(0) }) == &0
+    }
+
     /// Converts this C string to a byte slice.
     ///
     /// The returned slice will **not** contain the trailing nul terminator that this C

From 6d8903ae5f3d3a16a96e0a3e3f32ce88d7998392 Mon Sep 17 00:00:00 2001
From: Ryo Yoshida 
Date: Thu, 29 Sep 2022 18:44:45 +0900
Subject: [PATCH 061/175] fix: infer for-loop item type with `IntoIterator` and
 `Iterator`

---
 crates/hir-expand/src/name.rs     |  1 +
 crates/hir-ty/src/infer.rs        |  6 ++++++
 crates/hir-ty/src/infer/expr.rs   |  4 +++-
 crates/hir-ty/src/tests/traits.rs | 12 +++++++++++-
 crates/ide/src/inlay_hints.rs     |  9 ++++++++-
 5 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs
index 4ce21a57967c..2679a1c36026 100644
--- a/crates/hir-expand/src/name.rs
+++ b/crates/hir-expand/src/name.rs
@@ -263,6 +263,7 @@ pub mod known {
         Iterator,
         IntoIterator,
         Item,
+        IntoIter,
         Try,
         Ok,
         Future,
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 039824694ace..25179afaca7a 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -883,6 +883,12 @@ impl<'a> InferenceContext<'a> {
     fn resolve_into_iter_item(&self) -> Option {
         let path = path![core::iter::IntoIterator];
         let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
+        self.db.trait_data(trait_).associated_type_by_name(&name![IntoIter])
+    }
+
+    fn resolve_iterator_item(&self) -> Option {
+        let path = path![core::iter::Iterator];
+        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Item])
     }
 
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index e3d6be23e658..2643baf8a329 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -207,8 +207,10 @@ impl<'a> InferenceContext<'a> {
             }
             &Expr::For { iterable, body, pat, label } => {
                 let iterable_ty = self.infer_expr(iterable, &Expectation::none());
-                let pat_ty =
+                let into_iter_ty =
                     self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
+                let pat_ty =
+                    self.resolve_associated_type(into_iter_ty, self.resolve_iterator_item());
 
                 self.infer_pat(pat, &pat_ty, BindingMode::default());
                 self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 21a86319763f..555b6972fb71 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -279,6 +279,10 @@ fn test() {
 pub mod iter {
     pub trait IntoIterator {
         type Item;
+        type IntoIter: Iterator;
+    }
+    pub trait Iterator {
+        type Item;
     }
 }
 pub mod prelude {
@@ -297,7 +301,13 @@ pub mod collections {
     }
 
     impl IntoIterator for Vec {
-        type Item=T;
+        type Item = T;
+        type IntoIter = IntoIter;
+    }
+
+    struct IntoIter {}
+    impl Iterator for IntoIter {
+        type Item = T;
     }
 }
 "#,
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 08363d21e89b..34d8bf67a301 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -2024,7 +2024,14 @@ impl Vec {
 }
 
 impl IntoIterator for Vec {
-    type Item=T;
+    type Item = T;
+    type IntoIter = IntoIter;
+}
+
+struct IntoIter {}
+
+impl Iterator for IntoIter {
+    type Item = T;
 }
 
 fn main() {

From 2c72ea7748d4ed68178afa059a0853c3e97731e6 Mon Sep 17 00:00:00 2001
From: est31 
Date: Mon, 12 Sep 2022 17:09:08 +0200
Subject: [PATCH 062/175] Stabilize map_first_last

---
 compiler/rustc_middle/src/lib.rs           |  1 -
 library/alloc/benches/lib.rs               |  1 -
 library/alloc/src/collections/btree/map.rs | 18 ++++++------------
 library/alloc/src/collections/btree/set.rs | 12 ++++--------
 src/tools/miri/src/lib.rs                  |  1 -
 5 files changed, 10 insertions(+), 23 deletions(-)

diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index a180706e1cf0..9c690fc15de4 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -32,7 +32,6 @@
 #![feature(exhaustive_patterns)]
 #![feature(get_mut_unchecked)]
 #![feature(if_let_guard)]
-#![feature(map_first_last)]
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(extern_types)]
diff --git a/library/alloc/benches/lib.rs b/library/alloc/benches/lib.rs
index 72ac897d4f17..d418965cd2f6 100644
--- a/library/alloc/benches/lib.rs
+++ b/library/alloc/benches/lib.rs
@@ -3,7 +3,6 @@
 #![cfg(not(target_os = "android"))]
 #![feature(btree_drain_filter)]
 #![feature(iter_next_chunk)]
-#![feature(map_first_last)]
 #![feature(repr_simd)]
 #![feature(slice_partition_dedup)]
 #![feature(test)]
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 3018d1c9125b..ce803a18348b 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -703,7 +703,6 @@ impl BTreeMap {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(map_first_last)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut map = BTreeMap::new();
@@ -712,7 +711,7 @@ impl BTreeMap {
     /// map.insert(2, "a");
     /// assert_eq!(map.first_key_value(), Some((&1, &"b")));
     /// ```
-    #[unstable(feature = "map_first_last", issue = "62924")]
+    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
     pub fn first_key_value(&self) -> Option<(&K, &V)>
     where
         K: Ord,
@@ -727,7 +726,6 @@ impl BTreeMap {
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_first_last)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut map = BTreeMap::new();
@@ -741,7 +739,7 @@ impl BTreeMap {
     /// assert_eq!(*map.get(&1).unwrap(), "first");
     /// assert_eq!(*map.get(&2).unwrap(), "b");
     /// ```
-    #[unstable(feature = "map_first_last", issue = "62924")]
+    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
     pub fn first_entry(&mut self) -> Option>
     where
         K: Ord,
@@ -765,7 +763,6 @@ impl BTreeMap {
     /// Draining elements in ascending order, while keeping a usable map each iteration.
     ///
     /// ```
-    /// #![feature(map_first_last)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut map = BTreeMap::new();
@@ -776,7 +773,7 @@ impl BTreeMap {
     /// }
     /// assert!(map.is_empty());
     /// ```
-    #[unstable(feature = "map_first_last", issue = "62924")]
+    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
     pub fn pop_first(&mut self) -> Option<(K, V)>
     where
         K: Ord,
@@ -792,7 +789,6 @@ impl BTreeMap {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(map_first_last)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut map = BTreeMap::new();
@@ -800,7 +796,7 @@ impl BTreeMap {
     /// map.insert(2, "a");
     /// assert_eq!(map.last_key_value(), Some((&2, &"a")));
     /// ```
-    #[unstable(feature = "map_first_last", issue = "62924")]
+    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
     pub fn last_key_value(&self) -> Option<(&K, &V)>
     where
         K: Ord,
@@ -815,7 +811,6 @@ impl BTreeMap {
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_first_last)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut map = BTreeMap::new();
@@ -829,7 +824,7 @@ impl BTreeMap {
     /// assert_eq!(*map.get(&1).unwrap(), "a");
     /// assert_eq!(*map.get(&2).unwrap(), "last");
     /// ```
-    #[unstable(feature = "map_first_last", issue = "62924")]
+    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
     pub fn last_entry(&mut self) -> Option>
     where
         K: Ord,
@@ -853,7 +848,6 @@ impl BTreeMap {
     /// Draining elements in descending order, while keeping a usable map each iteration.
     ///
     /// ```
-    /// #![feature(map_first_last)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut map = BTreeMap::new();
@@ -864,7 +858,7 @@ impl BTreeMap {
     /// }
     /// assert!(map.is_empty());
     /// ```
-    #[unstable(feature = "map_first_last", issue = "62924")]
+    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
     pub fn pop_last(&mut self) -> Option<(K, V)>
     where
         K: Ord,
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index 3caaf521240d..09f3106dcfcd 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -786,7 +786,6 @@ impl BTreeSet {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(map_first_last)]
     /// use std::collections::BTreeSet;
     ///
     /// let mut set = BTreeSet::new();
@@ -797,7 +796,7 @@ impl BTreeSet {
     /// assert_eq!(set.first(), Some(&1));
     /// ```
     #[must_use]
-    #[unstable(feature = "map_first_last", issue = "62924")]
+    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
     pub fn first(&self) -> Option<&T>
     where
         T: Ord,
@@ -813,7 +812,6 @@ impl BTreeSet {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(map_first_last)]
     /// use std::collections::BTreeSet;
     ///
     /// let mut set = BTreeSet::new();
@@ -824,7 +822,7 @@ impl BTreeSet {
     /// assert_eq!(set.last(), Some(&2));
     /// ```
     #[must_use]
-    #[unstable(feature = "map_first_last", issue = "62924")]
+    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
     pub fn last(&self) -> Option<&T>
     where
         T: Ord,
@@ -838,7 +836,6 @@ impl BTreeSet {
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_first_last)]
     /// use std::collections::BTreeSet;
     ///
     /// let mut set = BTreeSet::new();
@@ -849,7 +846,7 @@ impl BTreeSet {
     /// }
     /// assert!(set.is_empty());
     /// ```
-    #[unstable(feature = "map_first_last", issue = "62924")]
+    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
     pub fn pop_first(&mut self) -> Option
     where
         T: Ord,
@@ -863,7 +860,6 @@ impl BTreeSet {
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_first_last)]
     /// use std::collections::BTreeSet;
     ///
     /// let mut set = BTreeSet::new();
@@ -874,7 +870,7 @@ impl BTreeSet {
     /// }
     /// assert!(set.is_empty());
     /// ```
-    #[unstable(feature = "map_first_last", issue = "62924")]
+    #[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
     pub fn pop_last(&mut self) -> Option
     where
         T: Ord,
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index cda27beab300..aced15646a2a 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,5 +1,4 @@
 #![feature(rustc_private)]
-#![feature(map_first_last)]
 #![feature(map_try_insert)]
 #![feature(never_type)]
 #![feature(try_blocks)]

From 8c433c7296b090da5bb1676eeacc5f9ba00fd677 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Sat, 1 Oct 2022 00:07:33 +0200
Subject: [PATCH 063/175] Fix requests not being retried anymore

---
 crates/rust-analyzer/src/main_loop.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index c64d557a118f..15922dac651c 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -426,7 +426,7 @@ impl GlobalState {
         match task {
             Task::Response(response) => self.respond(response),
             // Only retry requests that haven't been cancelled. Otherwise we do unnecessary work.
-            Task::Retry(req) if self.is_completed(&req) => self.on_request(req),
+            Task::Retry(req) if !self.is_completed(&req) => self.on_request(req),
             Task::Retry(_) => (),
             Task::Diagnostics(diagnostics_per_file) => {
                 for (file_id, diagnostics) in diagnostics_per_file {

From 3cd57c425a1f7001cc86222f928f53a7114564df Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Sat, 1 Oct 2022 00:03:47 +0200
Subject: [PATCH 064/175] Fix annotations not resolving when lens location is
 set to whole item

---
 crates/ide/src/annotations.rs                 | 264 +++++++++++-------
 .../src/{ => annotations}/fn_references.rs    |  37 ++-
 crates/ide/src/lib.rs                         |   6 -
 crates/rust-analyzer/src/from_proto.rs        |  10 +-
 crates/rust-analyzer/src/to_proto.rs          |  12 +-
 5 files changed, 199 insertions(+), 130 deletions(-)
 rename crates/ide/src/{ => annotations}/fn_references.rs (61%)

diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs
index bfbe0db6e4b8..f994c284c713 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -8,13 +8,15 @@ use ide_db::{
 use syntax::{ast::HasName, AstNode, TextRange};
 
 use crate::{
-    fn_references::find_all_methods,
+    annotations::fn_references::find_all_methods,
     goto_implementation::goto_implementation,
     references::find_all_refs,
     runnables::{runnables, Runnable},
     NavigationTarget, RunnableKind,
 };
 
+mod fn_references;
+
 // Feature: Annotations
 //
 // Provides user with annotations above items for looking up references or impl blocks
@@ -30,8 +32,8 @@ pub struct Annotation {
 #[derive(Debug)]
 pub enum AnnotationKind {
     Runnable(Runnable),
-    HasImpls { file_id: FileId, data: Option> },
-    HasReferences { file_id: FileId, data: Option> },
+    HasImpls { pos: FilePosition, data: Option> },
+    HasReferences { pos: FilePosition, data: Option> },
 }
 
 pub struct AnnotationConfig {
@@ -68,13 +70,23 @@ pub(crate) fn annotations(
         }
     }
 
+    let mk_ranges = |(range, focus): (_, Option<_>)| {
+        let cmd_target: TextRange = focus.unwrap_or(range);
+        let annotation_range = match config.location {
+            AnnotationLocation::AboveName => cmd_target,
+            AnnotationLocation::AboveWholeItem => range,
+        };
+        let target_pos = FilePosition { file_id, offset: cmd_target.start() };
+        (annotation_range, target_pos)
+    };
+
     visit_file_defs(&Semantics::new(db), file_id, &mut |def| {
         let range = match def {
             Definition::Const(konst) if config.annotate_references => {
-                konst.source(db).and_then(|node| name_range(db, config, node, file_id))
+                konst.source(db).and_then(|node| name_range(db, node, file_id))
             }
             Definition::Trait(trait_) if config.annotate_references || config.annotate_impls => {
-                trait_.source(db).and_then(|node| name_range(db, config, node, file_id))
+                trait_.source(db).and_then(|node| name_range(db, node, file_id))
             }
             Definition::Adt(adt) => match adt {
                 hir::Adt::Enum(enum_) => {
@@ -83,27 +95,29 @@ pub(crate) fn annotations(
                             .variants(db)
                             .into_iter()
                             .map(|variant| {
-                                variant
-                                    .source(db)
-                                    .and_then(|node| name_range(db, config, node, file_id))
+                                variant.source(db).and_then(|node| name_range(db, node, file_id))
                             })
                             .flatten()
                             .for_each(|range| {
+                                let (annotation_range, target_position) = mk_ranges(range);
                                 annotations.push(Annotation {
-                                    range,
-                                    kind: AnnotationKind::HasReferences { file_id, data: None },
+                                    range: annotation_range,
+                                    kind: AnnotationKind::HasReferences {
+                                        pos: target_position,
+                                        data: None,
+                                    },
                                 })
                             })
                     }
                     if config.annotate_references || config.annotate_impls {
-                        enum_.source(db).and_then(|node| name_range(db, config, node, file_id))
+                        enum_.source(db).and_then(|node| name_range(db, node, file_id))
                     } else {
                         None
                     }
                 }
                 _ => {
                     if config.annotate_references || config.annotate_impls {
-                        adt.source(db).and_then(|node| name_range(db, config, node, file_id))
+                        adt.source(db).and_then(|node| name_range(db, node, file_id))
                     } else {
                         None
                     }
@@ -116,33 +130,32 @@ pub(crate) fn annotations(
             Some(range) => range,
             None => return,
         };
-
+        let (annotation_range, target_pos) = mk_ranges(range);
         if config.annotate_impls && !matches!(def, Definition::Const(_)) {
-            annotations
-                .push(Annotation { range, kind: AnnotationKind::HasImpls { file_id, data: None } });
+            annotations.push(Annotation {
+                range: annotation_range,
+                kind: AnnotationKind::HasImpls { pos: target_pos, data: None },
+            });
         }
 
         if config.annotate_references {
             annotations.push(Annotation {
-                range,
-                kind: AnnotationKind::HasReferences { file_id, data: None },
+                range: annotation_range,
+                kind: AnnotationKind::HasReferences { pos: target_pos, data: None },
             });
         }
 
         fn name_range(
             db: &RootDatabase,
-            config: &AnnotationConfig,
             node: InFile,
             source_file_id: FileId,
-        ) -> Option {
+        ) -> Option<(TextRange, Option)> {
             if let Some(InFile { file_id, value }) = node.original_ast_node(db) {
                 if file_id == source_file_id.into() {
-                    return match config.location {
-                        AnnotationLocation::AboveName => {
-                            value.name().map(|name| name.syntax().text_range())
-                        }
-                        AnnotationLocation::AboveWholeItem => Some(value.syntax().text_range()),
-                    };
+                    return Some((
+                        value.syntax().text_range(),
+                        value.name().map(|name| name.syntax().text_range()),
+                    ));
                 }
             }
             None
@@ -150,12 +163,13 @@ pub(crate) fn annotations(
     });
 
     if config.annotate_method_references {
-        annotations.extend(find_all_methods(db, file_id).into_iter().map(
-            |FileRange { file_id, range }| Annotation {
-                range,
-                kind: AnnotationKind::HasReferences { file_id, data: None },
-            },
-        ));
+        annotations.extend(find_all_methods(db, file_id).into_iter().map(|range| {
+            let (annotation_range, target_range) = mk_ranges(range);
+            Annotation {
+                range: annotation_range,
+                kind: AnnotationKind::HasReferences { pos: target_range, data: None },
+            }
+        }));
     }
 
     annotations
@@ -163,18 +177,11 @@ pub(crate) fn annotations(
 
 pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
     match annotation.kind {
-        AnnotationKind::HasImpls { file_id, ref mut data } => {
-            *data =
-                goto_implementation(db, FilePosition { file_id, offset: annotation.range.start() })
-                    .map(|range| range.info);
+        AnnotationKind::HasImpls { pos, ref mut data } => {
+            *data = goto_implementation(db, pos).map(|range| range.info);
         }
-        AnnotationKind::HasReferences { file_id, ref mut data } => {
-            *data = find_all_refs(
-                &Semantics::new(db),
-                FilePosition { file_id, offset: annotation.range.start() },
-                None,
-            )
-            .map(|result| {
+        AnnotationKind::HasReferences { pos, ref mut data } => {
+            *data = find_all_refs(&Semantics::new(db), pos, None).map(|result| {
                 result
                     .into_iter()
                     .flat_map(|res| res.references)
@@ -268,9 +275,12 @@ fn main() {
                     Annotation {
                         range: 6..10,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 6,
+                            },
                             data: Some(
                                 [
                                     FileRange {
@@ -286,9 +296,12 @@ fn main() {
                     Annotation {
                         range: 30..36,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 30,
+                            },
                             data: Some(
                                 [],
                             ),
@@ -297,9 +310,12 @@ fn main() {
                     Annotation {
                         range: 53..57,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 53,
+                            },
                             data: Some(
                                 [],
                             ),
@@ -344,9 +360,12 @@ fn main() {
                     Annotation {
                         range: 7..11,
                         kind: HasImpls {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 7,
+                            },
                             data: Some(
                                 [],
                             ),
@@ -355,9 +374,12 @@ fn main() {
                     Annotation {
                         range: 7..11,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 7,
+                            },
                             data: Some(
                                 [
                                     FileRange {
@@ -373,9 +395,12 @@ fn main() {
                     Annotation {
                         range: 17..21,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 17,
+                            },
                             data: Some(
                                 [],
                             ),
@@ -424,9 +449,12 @@ fn main() {
                     Annotation {
                         range: 7..11,
                         kind: HasImpls {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 7,
+                            },
                             data: Some(
                                 [
                                     NavigationTarget {
@@ -445,9 +473,12 @@ fn main() {
                     Annotation {
                         range: 7..11,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 7,
+                            },
                             data: Some(
                                 [
                                     FileRange {
@@ -469,9 +500,12 @@ fn main() {
                     Annotation {
                         range: 20..31,
                         kind: HasImpls {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 20,
+                            },
                             data: Some(
                                 [
                                     NavigationTarget {
@@ -490,9 +524,12 @@ fn main() {
                     Annotation {
                         range: 20..31,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 20,
+                            },
                             data: Some(
                                 [
                                     FileRange {
@@ -508,9 +545,12 @@ fn main() {
                     Annotation {
                         range: 69..73,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 69,
+                            },
                             data: Some(
                                 [],
                             ),
@@ -551,9 +591,12 @@ fn main() {}
                     Annotation {
                         range: 3..7,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 3,
+                            },
                             data: Some(
                                 [],
                             ),
@@ -602,9 +645,12 @@ fn main() {
                     Annotation {
                         range: 7..11,
                         kind: HasImpls {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 7,
+                            },
                             data: Some(
                                 [
                                     NavigationTarget {
@@ -623,9 +669,12 @@ fn main() {
                     Annotation {
                         range: 7..11,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 7,
+                            },
                             data: Some(
                                 [
                                     FileRange {
@@ -647,9 +696,12 @@ fn main() {
                     Annotation {
                         range: 33..44,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 33,
+                            },
                             data: Some(
                                 [
                                     FileRange {
@@ -665,9 +717,12 @@ fn main() {
                     Annotation {
                         range: 61..65,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 61,
+                            },
                             data: Some(
                                 [],
                             ),
@@ -761,9 +816,12 @@ mod tests {
                     Annotation {
                         range: 3..7,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 3,
+                            },
                             data: Some(
                                 [],
                             ),
@@ -821,9 +879,12 @@ struct Foo;
                     Annotation {
                         range: 0..71,
                         kind: HasImpls {
-                            file_id: FileId(
-                                0,
-                            ),
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 67,
+                            },
                             data: Some(
                                 [],
                             ),
@@ -832,10 +893,15 @@ struct Foo;
                     Annotation {
                         range: 0..71,
                         kind: HasReferences {
-                            file_id: FileId(
-                                0,
+                            pos: FilePosition {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 67,
+                            },
+                            data: Some(
+                                [],
                             ),
-                            data: None,
                         },
                     },
                 ]
diff --git a/crates/ide/src/fn_references.rs b/crates/ide/src/annotations/fn_references.rs
similarity index 61%
rename from crates/ide/src/fn_references.rs
rename to crates/ide/src/annotations/fn_references.rs
index 63fb322cea07..0cadf125feca 100644
--- a/crates/ide/src/fn_references.rs
+++ b/crates/ide/src/annotations/fn_references.rs
@@ -4,30 +4,38 @@
 use hir::Semantics;
 use ide_assists::utils::test_related_attribute;
 use ide_db::RootDatabase;
-use syntax::{ast, ast::HasName, AstNode, SyntaxNode};
+use syntax::{ast, ast::HasName, AstNode, SyntaxNode, TextRange};
 
-use crate::{FileId, FileRange};
+use crate::FileId;
 
-pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec {
+pub(super) fn find_all_methods(
+    db: &RootDatabase,
+    file_id: FileId,
+) -> Vec<(TextRange, Option)> {
     let sema = Semantics::new(db);
     let source_file = sema.parse(file_id);
-    source_file.syntax().descendants().filter_map(|it| method_range(it, file_id)).collect()
+    source_file.syntax().descendants().filter_map(|it| method_range(it)).collect()
 }
 
-fn method_range(item: SyntaxNode, file_id: FileId) -> Option {
+fn method_range(item: SyntaxNode) -> Option<(TextRange, Option)> {
     ast::Fn::cast(item).and_then(|fn_def| {
         if test_related_attribute(&fn_def).is_some() {
             None
         } else {
-            fn_def.name().map(|name| FileRange { file_id, range: name.syntax().text_range() })
+            Some((
+                fn_def.syntax().text_range(),
+                fn_def.name().map(|name| name.syntax().text_range()),
+            ))
         }
     })
 }
 
 #[cfg(test)]
 mod tests {
+    use syntax::TextRange;
+
     use crate::fixture;
-    use crate::{FileRange, TextSize};
+    use crate::TextSize;
     use std::ops::RangeInclusive;
 
     #[test]
@@ -42,7 +50,7 @@ mod tests {
         "#,
         );
 
-        let refs = analysis.find_all_methods(pos.file_id).unwrap();
+        let refs = super::find_all_methods(&analysis.db, pos.file_id);
         check_result(&refs, &[3..=13, 27..=33, 47..=57]);
     }
 
@@ -57,7 +65,7 @@ mod tests {
         "#,
         );
 
-        let refs = analysis.find_all_methods(pos.file_id).unwrap();
+        let refs = super::find_all_methods(&analysis.db, pos.file_id);
         check_result(&refs, &[19..=22, 35..=38]);
     }
 
@@ -78,17 +86,18 @@ mod tests {
         "#,
         );
 
-        let refs = analysis.find_all_methods(pos.file_id).unwrap();
+        let refs = super::find_all_methods(&analysis.db, pos.file_id);
         check_result(&refs, &[28..=34]);
     }
 
-    fn check_result(refs: &[FileRange], expected: &[RangeInclusive]) {
+    fn check_result(refs: &[(TextRange, Option)], expected: &[RangeInclusive]) {
         assert_eq!(refs.len(), expected.len());
 
-        for (i, item) in refs.iter().enumerate() {
+        for (i, &(full, focus)) in refs.iter().enumerate() {
             let range = &expected[i];
-            assert_eq!(TextSize::from(*range.start()), item.range.start());
-            assert_eq!(TextSize::from(*range.end()), item.range.end());
+            let item = focus.unwrap_or(full);
+            assert_eq!(TextSize::from(*range.start()), item.start());
+            assert_eq!(TextSize::from(*range.end()), item.end());
         }
     }
 }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 7820b67142fe..77fe0dbf5565 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -31,7 +31,6 @@ mod highlight_related;
 mod expand_macro;
 mod extend_selection;
 mod file_structure;
-mod fn_references;
 mod folding_ranges;
 mod goto_declaration;
 mod goto_definition;
@@ -429,11 +428,6 @@ impl Analysis {
         self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope))
     }
 
-    /// Finds all methods and free functions for the file. Does not return tests!
-    pub fn find_all_methods(&self, file_id: FileId) -> Cancellable> {
-        self.with_db(|db| fn_references::find_all_methods(db, file_id))
-    }
-
     /// Returns a short text describing element at position.
     pub fn hover(
         &self,
diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs
index 7bdd34d1f093..f2db9a273349 100644
--- a/crates/rust-analyzer/src/from_proto.rs
+++ b/crates/rust-analyzer/src/from_proto.rs
@@ -95,22 +95,22 @@ pub(crate) fn annotation(
 
     match resolve {
         lsp_ext::CodeLensResolveData::Impls(params) => {
-            let file_id =
-                snap.url_to_file_id(¶ms.text_document_position_params.text_document.uri)?;
+            let pos @ FilePosition { file_id, .. } =
+                file_position(snap, params.text_document_position_params)?;
             let line_index = snap.file_line_index(file_id)?;
 
             Ok(Annotation {
                 range: text_range(&line_index, code_lens.range)?,
-                kind: AnnotationKind::HasImpls { file_id, data: None },
+                kind: AnnotationKind::HasImpls { pos, data: None },
             })
         }
         lsp_ext::CodeLensResolveData::References(params) => {
-            let file_id = snap.url_to_file_id(¶ms.text_document.uri)?;
+            let pos @ FilePosition { file_id, .. } = file_position(snap, params)?;
             let line_index = snap.file_line_index(file_id)?;
 
             Ok(Annotation {
                 range: text_range(&line_index, code_lens.range)?,
-                kind: AnnotationKind::HasReferences { file_id, data: None },
+                kind: AnnotationKind::HasReferences { pos, data: None },
             })
         }
     }
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 1de801e23e5c..5936454a7c54 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -1177,13 +1177,13 @@ pub(crate) fn code_lens(
                 })
             }
         }
-        AnnotationKind::HasImpls { file_id, data } => {
+        AnnotationKind::HasImpls { pos: file_range, data } => {
             if !client_commands_config.show_reference {
                 return Ok(());
             }
-            let line_index = snap.file_line_index(file_id)?;
+            let line_index = snap.file_line_index(file_range.file_id)?;
             let annotation_range = range(&line_index, annotation.range);
-            let url = url(snap, file_id);
+            let url = url(snap, file_range.file_id);
 
             let id = lsp_types::TextDocumentIdentifier { uri: url.clone() };
 
@@ -1221,13 +1221,13 @@ pub(crate) fn code_lens(
                 data: Some(to_value(lsp_ext::CodeLensResolveData::Impls(goto_params)).unwrap()),
             })
         }
-        AnnotationKind::HasReferences { file_id, data } => {
+        AnnotationKind::HasReferences { pos: file_range, data } => {
             if !client_commands_config.show_reference {
                 return Ok(());
             }
-            let line_index = snap.file_line_index(file_id)?;
+            let line_index = snap.file_line_index(file_range.file_id)?;
             let annotation_range = range(&line_index, annotation.range);
-            let url = url(snap, file_id);
+            let url = url(snap, file_range.file_id);
 
             let id = lsp_types::TextDocumentIdentifier { uri: url.clone() };
 

From 77cfc9b3921dfb9ce0df891a3b6be3e9cb3da656 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Sat, 1 Oct 2022 00:21:29 +0200
Subject: [PATCH 065/175] Fix type alias hovers not rendering generic
 parameters

---
 crates/hir/src/display.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 0e29c52ade68..27b2f445d73c 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -492,6 +492,9 @@ impl HirDisplay for TypeAlias {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
         let data = f.db.type_alias_data(self.id);
         write!(f, "type {}", data.name)?;
+        let def_id = GenericDefId::TypeAliasId(self.id);
+        write_generic_params(def_id, f)?;
+        write_where_clause(def_id, f)?;
         if !data.bounds.is_empty() {
             f.write_str(": ")?;
             f.write_joined(&data.bounds, " + ")?;

From 3ad03347180445366e127e9ec589920eb3c547ed Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Sat, 1 Oct 2022 00:42:16 +0200
Subject: [PATCH 066/175] Fix move_format_string_arg being tokentree unaware

---
 .../src/handlers/move_format_string_arg.rs    | 42 +++++++++++++++----
 1 file changed, 35 insertions(+), 7 deletions(-)

diff --git a/crates/ide-assists/src/handlers/move_format_string_arg.rs b/crates/ide-assists/src/handlers/move_format_string_arg.rs
index 92b2fa79d717..aa710d2ce651 100644
--- a/crates/ide-assists/src/handlers/move_format_string_arg.rs
+++ b/crates/ide-assists/src/handlers/move_format_string_arg.rs
@@ -7,6 +7,7 @@ use ide_db::{
     },
 };
 use itertools::Itertools;
+use stdx::format_to;
 use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange};
 
 // Assist: move_format_string_arg
@@ -78,20 +79,26 @@ pub(crate) fn move_format_string_arg(acc: &mut Assists, ctx: &AssistContext<'_>)
 
             // Extract existing arguments in macro
             let tokens =
-                tt.token_trees_and_tokens().filter_map(NodeOrToken::into_token).collect_vec();
+                tt.token_trees_and_tokens().collect_vec();
 
             let mut existing_args: Vec = vec![];
 
             let mut current_arg = String::new();
-            if let [_opening_bracket, format_string, _args_start_comma, tokens @ .., end_bracket] =
+            if let [_opening_bracket, NodeOrToken::Token(format_string), _args_start_comma, tokens @ .., NodeOrToken::Token(end_bracket)] =
                 tokens.as_slice()
             {
                 for t in tokens {
-                    if t.kind() == COMMA {
-                        existing_args.push(current_arg.trim().into());
-                        current_arg.clear();
-                    } else {
-                        current_arg.push_str(t.text());
+                    match t {
+                        NodeOrToken::Node(n) => {
+                            format_to!(current_arg, "{n}");
+                        },
+                        NodeOrToken::Token(t) if t.kind() == COMMA=> {
+                            existing_args.push(current_arg.trim().into());
+                            current_arg.clear();
+                        },
+                        NodeOrToken::Token(t) => {
+                            current_arg.push_str(t.text());
+                        },
                     }
                 }
                 existing_args.push(current_arg.trim().into());
@@ -261,6 +268,27 @@ fn main() {
 fn main() {
     print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
 }
+"#,
+            ),
+        );
+    }
+
+    #[test]
+    fn nested_tt() {
+        check_assist(
+            move_format_string_arg,
+            &add_macro_decl(
+                r#"
+fn main() {
+    print!("My name is {} {x$0 + x}", stringify!(Paperino))
+}
+"#,
+            ),
+            &add_macro_decl(
+                r#"
+fn main() {
+    print!("My name is {} {}"$0, stringify!(Paperino), x + x)
+}
 "#,
             ),
         );

From bfd5f00bfc97a90f190b1f402b67d707e4bcfcc4 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Sat, 1 Oct 2022 15:34:45 +0200
Subject: [PATCH 067/175] Fix trait impl item completions using macro file text
 ranges

---
 crates/hir-expand/src/lib.rs                  | 25 +++++++++
 crates/hir/src/semantics.rs                   | 15 ++++++
 .../src/completions/item_list/trait_impl.rs   | 51 ++++++++++---------
 3 files changed, 68 insertions(+), 23 deletions(-)

diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index fc128102f225..a5b499fe8d9d 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -811,6 +811,31 @@ impl<'a> InFile<&'a SyntaxNode> {
             _ => None,
         }
     }
+
+    pub fn original_syntax_node(self, db: &dyn db::AstDatabase) -> Option> {
+        // This kind of upmapping can only be achieved in attribute expanded files,
+        // as we don't have node inputs otherwise and  therefor can't find an `N` node in the input
+        if !self.file_id.is_macro() {
+            return Some(self.map(Clone::clone));
+        } else if !self.file_id.is_attr_macro(db) {
+            return None;
+        }
+
+        if let Some(InFile { file_id, value: (first, last) }) = ascend_node_border_tokens(db, self)
+        {
+            if file_id.is_macro() {
+                let range = first.text_range().cover(last.text_range());
+                tracing::error!("Failed mapping out of macro file for {:?}", range);
+                return None;
+            }
+            // FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes
+            let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?;
+            let kind = self.value.kind();
+            let value = anc.ancestors().find(|it| it.kind() == kind)?;
+            return Some(InFile::new(file_id, value));
+        }
+        None
+    }
 }
 
 impl InFile {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 416b6f58061d..119ec3210e17 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -257,6 +257,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
     pub fn original_ast_node(&self, node: N) -> Option {
         self.imp.original_ast_node(node)
     }
+    /// Attempts to map the node out of macro expanded files.
+    /// This only work for attribute expansions, as other ones do not have nodes as input.
+    pub fn original_syntax_node(&self, node: &SyntaxNode) -> Option {
+        self.imp.original_syntax_node(node)
+    }
 
     pub fn diagnostics_display_range(&self, diagnostics: InFile) -> FileRange {
         self.imp.diagnostics_display_range(diagnostics)
@@ -956,6 +961,16 @@ impl<'db> SemanticsImpl<'db> {
         )
     }
 
+    fn original_syntax_node(&self, node: &SyntaxNode) -> Option {
+        let InFile { file_id, .. } = self.find_file(node);
+        InFile::new(file_id, node).original_syntax_node(self.db.upcast()).map(
+            |InFile { file_id, value }| {
+                self.cache(find_root(&value), file_id);
+                value
+            },
+        )
+    }
+
     fn diagnostics_display_range(&self, src: InFile) -> FileRange {
         let root = self.parse_or_expand(src.file_id).unwrap();
         let node = src.map(|it| it.to_node(&root));
diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 785db6fde1d5..e82cbfdcb840 100644
--- a/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -38,7 +38,7 @@ use ide_db::{
 };
 use syntax::{
     ast::{self, edit_in_place::AttrsOwnerEdit},
-    AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T,
+    AstNode, SyntaxElement, SyntaxKind, TextRange, T,
 };
 use text_edit::TextEdit;
 
@@ -85,20 +85,36 @@ fn complete_trait_impl_name(
     name: &Option,
     kind: ImplCompletionKind,
 ) -> Option<()> {
-    let token = ctx.token.clone();
     let item = match name {
         Some(name) => name.syntax().parent(),
-        None => if token.kind() == SyntaxKind::WHITESPACE { token.prev_token()? } else { token }
-            .parent(),
+        None => {
+            let token = &ctx.token;
+            match token.kind() {
+                SyntaxKind::WHITESPACE => token.prev_token()?,
+                _ => token.clone(),
+            }
+            .parent()
+        }
     }?;
-    complete_trait_impl(
-        acc,
-        ctx,
-        kind,
-        replacement_range(ctx, &item),
-        // item -> ASSOC_ITEM_LIST -> IMPL
-        &ast::Impl::cast(item.parent()?.parent()?)?,
-    );
+    let item = ctx.sema.original_syntax_node(&item)?;
+    // item -> ASSOC_ITEM_LIST -> IMPL
+    let impl_def = ast::Impl::cast(item.parent()?.parent()?)?;
+    let replacement_range = {
+        // ctx.sema.original_ast_node(item)?;
+        let first_child = item
+            .children_with_tokens()
+            .find(|child| {
+                !matches!(
+                    child.kind(),
+                    SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR
+                )
+            })
+            .unwrap_or_else(|| SyntaxElement::Node(item.clone()));
+
+        TextRange::new(first_child.text_range().start(), ctx.source_range().end())
+    };
+
+    complete_trait_impl(acc, ctx, kind, replacement_range, &impl_def);
     Some(())
 }
 
@@ -341,17 +357,6 @@ fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String {
     syntax.trim_end().to_owned()
 }
 
-fn replacement_range(ctx: &CompletionContext<'_>, item: &SyntaxNode) -> TextRange {
-    let first_child = item
-        .children_with_tokens()
-        .find(|child| {
-            !matches!(child.kind(), SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR)
-        })
-        .unwrap_or_else(|| SyntaxElement::Node(item.clone()));
-
-    TextRange::new(first_child.text_range().start(), ctx.source_range().end())
-}
-
 #[cfg(test)]
 mod tests {
     use expect_test::{expect, Expect};

From 26cf250cccf620f02a2df2532bcb99ed503b3f8a Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Sat, 1 Oct 2022 19:50:34 +0200
Subject: [PATCH 068/175] Do not use the sysroot proc-macro server when a
 server path is given explicitly

---
 crates/rust-analyzer/src/config.rs | 16 ++++----
 crates/rust-analyzer/src/reload.rs | 61 +++++++++++++++++-------------
 2 files changed, 44 insertions(+), 33 deletions(-)

diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 9ef79e6f3812..5241aad327cf 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -7,7 +7,7 @@
 //! configure the server itself, feature flags are passed into analysis, and
 //! tweak things like automatic insertion of `()` in completions.
 
-use std::{ffi::OsString, fmt, iter, path::PathBuf};
+use std::{fmt, iter, path::PathBuf};
 
 use flycheck::FlycheckConfig;
 use ide::{
@@ -975,15 +975,17 @@ impl Config {
         self.data.lru_capacity
     }
 
-    pub fn proc_macro_srv(&self) -> Option<(AbsPathBuf, Vec)> {
+    pub fn proc_macro_srv(&self) -> Option<(AbsPathBuf, /* is path explicitly set */ bool)> {
         if !self.data.procMacro_enable {
             return None;
         }
-        let path = match &self.data.procMacro_server {
-            Some(it) => self.root_path.join(it),
-            None => AbsPathBuf::assert(std::env::current_exe().ok()?),
-        };
-        Some((path, vec!["proc-macro".into()]))
+        Some(match &self.data.procMacro_server {
+            Some(it) => (
+                AbsPathBuf::try_from(it.clone()).unwrap_or_else(|path| self.root_path.join(path)),
+                true,
+            ),
+            None => (AbsPathBuf::assert(std::env::current_exe().ok()?), false),
+        })
     }
 
     pub fn dummy_replacements(&self) -> &FxHashMap, Box<[Box]>> {
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 4cf5de46c485..e403f36d5787 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -306,41 +306,50 @@ impl GlobalState {
             format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
 
         if self.proc_macro_clients.is_empty() {
-            if let Some((path, args)) = self.config.proc_macro_srv() {
+            if let Some((path, path_manually_set)) = self.config.proc_macro_srv() {
                 tracing::info!("Spawning proc-macro servers");
                 self.proc_macro_clients = self
                     .workspaces
                     .iter()
                     .map(|ws| {
-                        let mut args = args.clone();
-                        let mut path = path.clone();
-
-                        if let ProjectWorkspace::Cargo { sysroot, .. }
-                        | ProjectWorkspace::Json { sysroot, .. } = ws
-                        {
-                            tracing::debug!("Found a cargo workspace...");
-                            if let Some(sysroot) = sysroot.as_ref() {
-                                tracing::debug!("Found a cargo workspace with a sysroot...");
-                                let server_path =
-                                    sysroot.root().join("libexec").join(&standalone_server_name);
-                                if std::fs::metadata(&server_path).is_ok() {
-                                    tracing::debug!(
-                                        "And the server exists at {}",
-                                        server_path.display()
-                                    );
-                                    path = server_path;
-                                    args = vec![];
-                                } else {
-                                    tracing::debug!(
-                                        "And the server does not exist at {}",
-                                        server_path.display()
-                                    );
+                        let (path, args) = if path_manually_set {
+                            tracing::debug!(
+                                "Pro-macro server path explicitly set: {}",
+                                path.display()
+                            );
+                            (path.clone(), vec![])
+                        } else {
+                            let mut sysroot_server = None;
+                            if let ProjectWorkspace::Cargo { sysroot, .. }
+                            | ProjectWorkspace::Json { sysroot, .. } = ws
+                            {
+                                if let Some(sysroot) = sysroot.as_ref() {
+                                    let server_path = sysroot
+                                        .root()
+                                        .join("libexec")
+                                        .join(&standalone_server_name);
+                                    if std::fs::metadata(&server_path).is_ok() {
+                                        tracing::debug!(
+                                            "Sysroot proc-macro server exists at {}",
+                                            server_path.display()
+                                        );
+                                        sysroot_server = Some(server_path);
+                                    } else {
+                                        tracing::debug!(
+                                            "Sysroot proc-macro server does not exist at {}",
+                                            server_path.display()
+                                        );
+                                    }
                                 }
                             }
-                        }
+                            sysroot_server.map_or_else(
+                                || (path.clone(), vec!["proc-macro".to_owned()]),
+                                |path| (path, vec![]),
+                            )
+                        };
 
                         tracing::info!(?args, "Using proc-macro server at {}", path.display(),);
-                        ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| {
+                        ProcMacroServer::spawn(path.clone(), args).map_err(|err| {
                             let error = format!(
                                 "Failed to run proc-macro server from path {}, error: {:?}",
                                 path.display(),

From 5424c51158ba5d4410695bca055709051797a44b Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Sat, 1 Oct 2022 20:47:31 +0200
Subject: [PATCH 069/175] Add config for supplying sysroot path

---
 crates/project-model/src/cargo_workspace.rs   |  5 +--
 crates/project-model/src/sysroot.rs           | 44 +++++++++++++------
 crates/project-model/src/workspace.rs         | 23 +++++++---
 .../rust-analyzer/src/cli/analysis_stats.rs   |  7 ++-
 crates/rust-analyzer/src/config.rs            | 18 ++++++--
 crates/rust-analyzer/tests/slow-tests/main.rs |  8 ++--
 .../rust-analyzer/tests/slow-tests/support.rs |  2 +-
 docs/dev/README.md                            |  2 +-
 docs/user/generated_config.adoc               |  9 +++-
 editors/code/package.json                     | 11 +++--
 10 files changed, 88 insertions(+), 41 deletions(-)

diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index bd2bbadea239..8e690f1125a0 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -94,9 +94,8 @@ pub struct CargoConfig {
     pub features: CargoFeatures,
     /// rustc target
     pub target: Option,
-    /// Don't load sysroot crates (`std`, `core` & friends). Might be useful
-    /// when debugging isolated issues.
-    pub no_sysroot: bool,
+    /// Sysroot loading behavior
+    pub sysroot: Option,
     /// rustc private crate source
     pub rustc_source: Option,
     /// crates to disable `#[cfg(test)]` on
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index f0d76aa922f7..bc37e3d132a6 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -67,11 +67,14 @@ impl Sysroot {
     pub fn crates<'a>(&'a self) -> impl Iterator + ExactSizeIterator + 'a {
         self.crates.iter().map(|(id, _data)| id)
     }
+}
 
+impl Sysroot {
     pub fn discover(dir: &AbsPath, extra_env: &FxHashMap) -> Result {
         tracing::debug!("Discovering sysroot for {}", dir.display());
         let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
-        let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir, extra_env)?;
+        let sysroot_src_dir =
+            discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
         let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
         Ok(res)
     }
@@ -87,6 +90,14 @@ impl Sysroot {
             .and_then(|sysroot_dir| get_rustc_src(&sysroot_dir))
     }
 
+    pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf) -> Result {
+        let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
+            format_err!("can't load standard library from sysroot {}", sysroot_dir.display())
+        })?;
+        let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
+        Ok(res)
+    }
+
     pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result {
         let mut sysroot =
             Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
@@ -162,23 +173,28 @@ fn discover_sysroot_dir(
     Ok(AbsPathBuf::assert(PathBuf::from(stdout)))
 }
 
-fn discover_sysroot_src_dir(
+fn discover_sysroot_src_dir(sysroot_path: &AbsPathBuf) -> Option {
+    if let Ok(path) = env::var("RUST_SRC_PATH") {
+        if let Ok(path) = AbsPathBuf::try_from(path.as_str()) {
+            let core = path.join("core");
+            if fs::metadata(&core).is_ok() {
+                tracing::debug!("Discovered sysroot by RUST_SRC_PATH: {}", path.display());
+                return Some(path);
+            }
+            tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
+        } else {
+            tracing::debug!("RUST_SRC_PATH is set, but is invalid, ignoring");
+        }
+    }
+
+    get_rust_src(sysroot_path)
+}
+fn discover_sysroot_src_dir_or_add_component(
     sysroot_path: &AbsPathBuf,
     current_dir: &AbsPath,
     extra_env: &FxHashMap,
 ) -> Result {
-    if let Ok(path) = env::var("RUST_SRC_PATH") {
-        let path = AbsPathBuf::try_from(path.as_str())
-            .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
-        let core = path.join("core");
-        if fs::metadata(&core).is_ok() {
-            tracing::debug!("Discovered sysroot by RUST_SRC_PATH: {}", path.display());
-            return Ok(path);
-        }
-        tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
-    }
-
-    get_rust_src(sysroot_path)
+    discover_sysroot_src_dir(sysroot_path)
         .or_else(|| {
             let mut rustup = Command::new(toolchain::rustup());
             rustup.envs(extra_env);
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index d9d3cab45614..72ddf809288a 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -188,17 +188,26 @@ impl ProjectWorkspace {
                 })?;
                 let cargo = CargoWorkspace::new(meta);
 
-                let sysroot = if config.no_sysroot {
-                    None
-                } else {
-                    Some(Sysroot::discover(cargo_toml.parent(), &config.extra_env).with_context(
-                        || {
+                let sysroot = match &config.sysroot {
+                    Some(RustcSource::Path(path)) => {
+                        Some(Sysroot::with_sysroot_dir(path.clone()).with_context(|| {
                             format!(
+                                "Failed to find sysroot for Cargo.toml file {}.",
+                                cargo_toml.display()
+                            )
+                        })?)
+                    }
+                    Some(RustcSource::Discover) => Some(
+                        Sysroot::discover(cargo_toml.parent(), &config.extra_env).with_context(
+                            || {
+                                format!(
                             "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
                             cargo_toml.display()
                         )
-                        },
-                    )?)
+                            },
+                        )?,
+                    ),
+                    None => None,
                 };
 
                 let rustc_dir = match &config.rustc_source {
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 81c393abdb34..01fccc83e822 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -24,7 +24,7 @@ use ide_db::base_db::{
 use itertools::Itertools;
 use oorandom::Rand32;
 use profile::{Bytes, StopWatch};
-use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
+use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustcSource};
 use rayon::prelude::*;
 use rustc_hash::FxHashSet;
 use stdx::format_to;
@@ -55,7 +55,10 @@ impl flags::AnalysisStats {
         };
 
         let mut cargo_config = CargoConfig::default();
-        cargo_config.no_sysroot = self.no_sysroot;
+        cargo_config.sysroot = match self.no_sysroot {
+            true => None,
+            false => Some(RustcSource::Discover),
+        };
         let load_cargo_config = LoadCargoConfig {
             load_out_dirs_from_check: !self.disable_build_scripts,
             with_proc_macro: !self.disable_proc_macros,
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index dfef6f014ca5..577a8640a4c0 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -94,8 +94,13 @@ config_data! {
         cargo_features: CargoFeaturesDef      = "[]",
         /// Whether to pass `--no-default-features` to cargo.
         cargo_noDefaultFeatures: bool    = "false",
-        /// Internal config for debugging, disables loading of sysroot crates.
-        cargo_noSysroot: bool            = "false",
+        /// Relative path to the sysroot, or "discover" to try to automatically find it via
+        /// "rustc --print sysroot".
+        ///
+        /// Unsetting this disables sysroot loading.
+        ///
+        /// This option does not take effect until rust-analyzer is restarted.
+        cargo_sysroot: Option    = "\"discover\"",
         /// Compilation target override (target triple).
         cargo_target: Option     = "null",
         /// Unsets `#[cfg(test)]` for the specified crates.
@@ -1030,6 +1035,13 @@ impl Config {
                 RustcSource::Path(self.root_path.join(rustc_src))
             }
         });
+        let sysroot = self.data.cargo_sysroot.as_ref().map(|sysroot| {
+            if sysroot == "discover" {
+                RustcSource::Discover
+            } else {
+                RustcSource::Path(self.root_path.join(sysroot))
+            }
+        });
 
         CargoConfig {
             features: match &self.data.cargo_features {
@@ -1040,7 +1052,7 @@ impl Config {
                 },
             },
             target: self.data.cargo_target.clone(),
-            no_sysroot: self.data.cargo_noSysroot,
+            sysroot,
             rustc_source,
             unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()),
             wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper,
diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs
index 9032c21d096b..fa55f7d90c49 100644
--- a/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -59,7 +59,7 @@ use std::collections::Spam;
 "#,
     )
     .with_config(serde_json::json!({
-        "cargo": { "noSysroot": false }
+        "cargo": { "sysroot": "discover" }
     }))
     .server()
     .wait_until_workspace_is_loaded();
@@ -614,7 +614,7 @@ fn main() {{}}
         librs, libs
     ))
     .with_config(serde_json::json!({
-        "cargo": { "noSysroot": false }
+        "cargo": { "sysroot": "discover" }
     }))
     .server()
     .wait_until_workspace_is_loaded();
@@ -742,7 +742,7 @@ fn main() {
             "buildScripts": {
                 "enable": true
             },
-            "noSysroot": true,
+            "sysroot": null,
         }
     }))
     .server()
@@ -900,7 +900,7 @@ pub fn foo(_input: TokenStream) -> TokenStream {
             "buildScripts": {
                 "enable": true
             },
-            "noSysroot": true,
+            "sysroot": null,
         },
         "procMacro": {
             "enable": true,
diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs
index 4fa88c3c6da1..7257445dabe0 100644
--- a/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -34,7 +34,7 @@ impl<'a> Project<'a> {
             config: serde_json::json!({
                 "cargo": {
                     // Loading standard library is costly, let's ignore it by default
-                    "noSysroot": true,
+                    "sysroot": null,
                     // Can't use test binary as rustc wrapper.
                     "buildScripts": {
                         "useRustcWrapper": false
diff --git a/docs/dev/README.md b/docs/dev/README.md
index c7f152acc266..4ac75b4bbfd9 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -98,7 +98,7 @@ After I am done with the fix, I use `cargo xtask install --client` to try the ne
 If I need to fix something in the `rust-analyzer` crate, I feel sad because it's on the boundary between the two processes, and working there is slow.
 I usually just `cargo xtask install --server` and poke changes from my live environment.
 Note that this uses `--release`, which is usually faster overall, because loading stdlib into debug version of rust-analyzer takes a lot of time.
-To speed things up, sometimes I open a temporary hello-world project which has `"rust-analyzer.cargo.noSysroot": true` in `.code/settings.json`.
+To speed things up, sometimes I open a temporary hello-world project which has `"rust-analyzer.cargo.sysroot": null` in `.code/settings.json`.
 This flag causes rust-analyzer to skip loading the sysroot, which greatly reduces the amount of things rust-analyzer needs to do, and makes printf's more useful.
 Note that you should only use the `eprint!` family of macros for debugging: stdout is used for LSP communication, and `print!` would break it.
 
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index a34f4d5093e3..acf0aaea859a 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -64,10 +64,15 @@ Set this to `"all"` to pass `--all-features` to cargo.
 --
 Whether to pass `--no-default-features` to cargo.
 --
-[[rust-analyzer.cargo.noSysroot]]rust-analyzer.cargo.noSysroot (default: `false`)::
+[[rust-analyzer.cargo.sysroot]]rust-analyzer.cargo.sysroot (default: `"discover"`)::
 +
 --
-Internal config for debugging, disables loading of sysroot crates.
+Relative path to the sysroot, or "discover" to try to automatically find it via
+"rustc --print sysroot".
+
+Unsetting this disables sysroot loading.
+
+This option does not take effect until rust-analyzer is restarted.
 --
 [[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `null`)::
 +
diff --git a/editors/code/package.json b/editors/code/package.json
index f8eec9f62e52..f1dd3aa79ff0 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -468,10 +468,13 @@
                     "default": false,
                     "type": "boolean"
                 },
-                "rust-analyzer.cargo.noSysroot": {
-                    "markdownDescription": "Internal config for debugging, disables loading of sysroot crates.",
-                    "default": false,
-                    "type": "boolean"
+                "rust-analyzer.cargo.sysroot": {
+                    "markdownDescription": "Relative path to the sysroot, or \"discover\" to try to automatically find it via\n\"rustc --print sysroot\".\n\nUnsetting this disables sysroot loading.\n\nThis option does not take effect until rust-analyzer is restarted.",
+                    "default": "discover",
+                    "type": [
+                        "null",
+                        "string"
+                    ]
                 },
                 "rust-analyzer.cargo.target": {
                     "markdownDescription": "Compilation target override (target triple).",

From 870825b3761c1dde188dd881b3d4223c39a738c3 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Sat, 1 Oct 2022 21:29:14 +0200
Subject: [PATCH 070/175] Add proc-macro dependency to rustc crates

---
 crates/project-model/src/workspace.rs | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 72ddf809288a..8c3e8681d989 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -717,6 +717,7 @@ fn cargo_to_crate_graph(
                 load_proc_macro,
                 &mut pkg_to_lib_crate,
                 &public_deps,
+                libproc_macro,
                 cargo,
                 &pkg_crates,
                 build_scripts,
@@ -782,6 +783,7 @@ fn handle_rustc_crates(
     load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
     pkg_to_lib_crate: &mut FxHashMap,
     public_deps: &SysrootPublicDeps,
+    libproc_macro: Option,
     cargo: &CargoWorkspace,
     pkg_crates: &FxHashMap>,
     build_scripts: &WorkspaceBuildScripts,
@@ -843,6 +845,19 @@ fn handle_rustc_crates(
                         rustc_workspace[tgt].is_proc_macro,
                     );
                     pkg_to_lib_crate.insert(pkg, crate_id);
+
+                    // Even crates that don't set proc-macro = true are allowed to depend on proc_macro
+                    // (just none of the APIs work when called outside of a proc macro).
+                    if let Some(proc_macro) = libproc_macro {
+                        add_dep_with_prelude(
+                            crate_graph,
+                            crate_id,
+                            CrateName::new("proc_macro").unwrap(),
+                            proc_macro,
+                            cargo[tgt].is_proc_macro,
+                        );
+                    }
+
                     // Add dependencies on core / std / alloc for this crate
                     public_deps.add(crate_id, crate_graph);
                     rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);

From 69cafc069900905b2b48661dd013ade13186345e Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Sun, 2 Oct 2022 14:24:56 +0200
Subject: [PATCH 071/175] always panic for invalid integer logarithm

---
 library/core/src/num/int_macros.rs  | 45 +++++------------------------
 library/core/src/num/uint_macros.rs | 43 +++++----------------------
 2 files changed, 15 insertions(+), 73 deletions(-)

diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index d6aeee299e30..4eb85a281e20 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -2279,9 +2279,8 @@ macro_rules! int_impl {
         ///
         /// # Panics
         ///
-        /// When the number is negative, zero, or if the base is not at least 2; it
-        /// panics in debug mode and the return value is 0 in release
-        /// mode.
+        /// This function will panic if `self` is less than or equal to zero,
+        /// or if `base` is less then 2.
         ///
         /// # Examples
         ///
@@ -2297,24 +2296,15 @@ macro_rules! int_impl {
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
         pub const fn ilog(self, base: Self) -> u32 {
-            match self.checked_ilog(base) {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            assert!(base >= 2, "base of integer logarithm must be at least 2");
+            self.checked_ilog(base).expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the base 2 logarithm of the number, rounded down.
         ///
         /// # Panics
         ///
-        /// When the number is negative or zero it panics in debug mode and the return value
-        /// is 0 in release mode.
+        /// This function will panic if `self` is less than or equal to zero.
         ///
         /// # Examples
         ///
@@ -2330,24 +2320,14 @@ macro_rules! int_impl {
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
         pub const fn ilog2(self) -> u32 {
-            match self.checked_ilog2() {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            self.checked_ilog2().expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the base 10 logarithm of the number, rounded down.
         ///
         /// # Panics
         ///
-        /// When the number is negative or zero it panics in debug mode and the return value
-        /// is 0 in release mode.
+        /// This function will panic if `self` is less than or equal to zero.
         ///
         /// # Example
         ///
@@ -2363,16 +2343,7 @@ macro_rules! int_impl {
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
         pub const fn ilog10(self) -> u32 {
-            match self.checked_ilog10() {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            self.checked_ilog10().expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the logarithm of the number with respect to an arbitrary base,
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 46b0ca230340..83836f2a3954 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -692,8 +692,7 @@ macro_rules! uint_impl {
         ///
         /// # Panics
         ///
-        /// When the number is zero, or if the base is not at least 2;
-        /// it panics in debug mode and the return value is 0 in release mode.
+        /// This function will panic if `self` is zero, or if `base` is less then 2.
         ///
         /// # Examples
         ///
@@ -709,24 +708,15 @@ macro_rules! uint_impl {
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
         pub const fn ilog(self, base: Self) -> u32 {
-            match self.checked_ilog(base) {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            assert!(base >= 2, "base of integer logarithm must be at least 2");
+            self.checked_ilog(base).expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the base 2 logarithm of the number, rounded down.
         ///
         /// # Panics
         ///
-        /// When the number is zero it panics in debug mode and
-        /// the return value is 0 in release mode.
+        /// This function will panic if `self` is zero.
         ///
         /// # Examples
         ///
@@ -742,24 +732,14 @@ macro_rules! uint_impl {
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
         pub const fn ilog2(self) -> u32 {
-            match self.checked_ilog2() {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            self.checked_ilog2().expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the base 10 logarithm of the number, rounded down.
         ///
         /// # Panics
         ///
-        /// When the number is zero it panics in debug mode and the
-        /// return value is 0 in release mode.
+        /// This function will panic if `self` is zero.
         ///
         /// # Example
         ///
@@ -775,16 +755,7 @@ macro_rules! uint_impl {
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
         pub const fn ilog10(self) -> u32 {
-            match self.checked_ilog10() {
-                Some(n) => n,
-                None => {
-                    // In debug builds, trigger a panic on None.
-                    // This should optimize completely out in release builds.
-                    let _ = Self::MAX + 1;
-
-                    0
-                },
-            }
+            self.checked_ilog10().expect("argument of integer logarithm must be positive")
         }
 
         /// Returns the logarithm of the number with respect to an arbitrary base,

From 6acc29f88b2fdf7a048fae77b031b803f86e1551 Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Sun, 2 Oct 2022 14:25:36 +0200
Subject: [PATCH 072/175] add tests for panicking integer logarithms

---
 library/core/tests/num/int_log.rs | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs
index be203fb5c04f..a1edb1a51863 100644
--- a/library/core/tests/num/int_log.rs
+++ b/library/core/tests/num/int_log.rs
@@ -164,3 +164,33 @@ fn ilog10_u64() {
 fn ilog10_u128() {
     ilog10_loop! { u128, 38 }
 }
+
+#[test]
+#[should_panic(expected = "argument of integer logarithm must be positive")]
+fn ilog2_of_0_panic() {
+    let _ = 0u32.ilog2();
+}
+
+#[test]
+#[should_panic(expected = "argument of integer logarithm must be positive")]
+fn ilog10_of_0_panic() {
+    let _ = 0u32.ilog10();
+}
+
+#[test]
+#[should_panic(expected = "argument of integer logarithm must be positive")]
+fn ilog3_of_0_panic() {
+    let _ = 0u32.ilog(3);
+}
+
+#[test]
+#[should_panic(expected = "base of integer logarithm must be at least 2")]
+fn ilog0_of_1_panic() {
+    let _ = 1u32.ilog(0);
+}
+
+#[test]
+#[should_panic(expected = "base of integer logarithm must be at least 2")]
+fn ilog1_of_1_panic() {
+    let _ = 1u32.ilog(1);
+}

From b7dae8a5e2ad75ca8f472c953f459c45e019896d Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Sun, 2 Oct 2022 15:15:40 +0200
Subject: [PATCH 073/175] remove unneeded attributes

---
 library/core/src/num/int_macros.rs  | 6 ------
 library/core/src/num/uint_macros.rs | 6 ------
 2 files changed, 12 deletions(-)

diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 4eb85a281e20..ff3b7bc2c904 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -2293,8 +2293,6 @@ macro_rules! int_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog(self, base: Self) -> u32 {
             assert!(base >= 2, "base of integer logarithm must be at least 2");
             self.checked_ilog(base).expect("argument of integer logarithm must be positive")
@@ -2317,8 +2315,6 @@ macro_rules! int_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog2(self) -> u32 {
             self.checked_ilog2().expect("argument of integer logarithm must be positive")
         }
@@ -2340,8 +2336,6 @@ macro_rules! int_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog10(self) -> u32 {
             self.checked_ilog10().expect("argument of integer logarithm must be positive")
         }
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 83836f2a3954..d921ff9ba102 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -705,8 +705,6 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog(self, base: Self) -> u32 {
             assert!(base >= 2, "base of integer logarithm must be at least 2");
             self.checked_ilog(base).expect("argument of integer logarithm must be positive")
@@ -729,8 +727,6 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog2(self) -> u32 {
             self.checked_ilog2().expect("argument of integer logarithm must be positive")
         }
@@ -752,8 +748,6 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline]
         #[track_caller]
-        #[rustc_inherit_overflow_checks]
-        #[allow(arithmetic_overflow)]
         pub const fn ilog10(self) -> u32 {
             self.checked_ilog10().expect("argument of integer logarithm must be positive")
         }

From f8f5a5ea5788a846013545d63c9b46fd70cc4f7c Mon Sep 17 00:00:00 2001
From: Ryo Yoshida 
Date: Sun, 2 Oct 2022 18:39:42 +0900
Subject: [PATCH 074/175] refactor: use `cast()` instead of interning
 `GenericArgData`

---
 crates/hir-ty/src/builder.rs    | 39 ++++++++++++------------------
 crates/hir-ty/src/chalk_ext.rs  |  2 +-
 crates/hir-ty/src/infer/path.rs |  7 ++----
 crates/hir-ty/src/lower.rs      |  4 +--
 crates/hir-ty/src/utils.rs      | 43 +++++++++++----------------------
 5 files changed, 34 insertions(+), 61 deletions(-)

diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs
index 3ae7fb2a617c..dd4f1f25a691 100644
--- a/crates/hir-ty/src/builder.rs
+++ b/crates/hir-ty/src/builder.rs
@@ -6,7 +6,7 @@ use chalk_ir::{
     cast::{Cast, CastTo, Caster},
     fold::TypeFoldable,
     interner::HasInterner,
-    AdtId, BoundVar, DebruijnIndex, Scalar,
+    AdtId, DebruijnIndex, Scalar,
 };
 use hir_def::{
     builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId,
@@ -16,9 +16,9 @@ use smallvec::SmallVec;
 
 use crate::{
     consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
-    to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData,
-    ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty,
-    TyDefId, TyExt, TyKind, ValueTyDefId,
+    to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, BoundVar, CallableSig,
+    GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
+    ValueTyDefId,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -79,20 +79,12 @@ impl TyBuilder {
     pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
         // self.fill is inlined to make borrow checker happy
         let mut this = self;
-        let other = this.param_kinds.iter().skip(this.vec.len());
+        let other = &this.param_kinds[this.vec.len()..];
         let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
-            ParamKind::Type => {
-                GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
-                    .intern(Interner)
+            ParamKind::Type => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
+            ParamKind::Const(ty) => {
+                BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
             }
-            ParamKind::Const(ty) => GenericArgData::Const(
-                ConstData {
-                    value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
-                    ty: ty.clone(),
-                }
-                .intern(Interner),
-            )
-            .intern(Interner),
         });
         this.vec.extend(filler.take(this.remaining()).casted(Interner));
         assert_eq!(this.remaining(), 0);
@@ -102,8 +94,8 @@ impl TyBuilder {
     pub fn fill_with_unknown(self) -> Self {
         // self.fill is inlined to make borrow checker happy
         let mut this = self;
-        let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
-            ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
+        let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
+            ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
             ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
         });
         this.vec.extend(filler.casted(Interner));
@@ -113,15 +105,13 @@ impl TyBuilder {
 
     pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
         self.fill(|x| match x {
-            ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner),
-            ParamKind::Const(ty) => {
-                GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
-            }
+            ParamKind::Type => table.new_type_var().cast(Interner),
+            ParamKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
         })
     }
 
     pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
-        self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
+        self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler));
         assert_eq!(self.remaining(), 0);
         self
     }
@@ -255,7 +245,8 @@ impl TyBuilder {
     ) -> Self {
         let defaults = db.generic_defaults(self.data.into());
         for default_ty in defaults.iter().skip(self.vec.len()) {
-            if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
+            // NOTE(skip_binders): we only check if the arg type is error type.
+            if let Some(x) = default_ty.skip_binders().ty(Interner) {
                 if x.is_unknown() {
                     self.vec.push(fallback().cast(Interner));
                     continue;
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index ed97bd2da4f3..4f0e9dbf1e4e 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -152,7 +152,7 @@ impl TyExt for Ty {
             TyKind::FnDef(def, parameters) => {
                 let callable_def = db.lookup_intern_callable_def((*def).into());
                 let sig = db.callable_item_signature(callable_def);
-                Some(sig.substitute(Interner, ¶meters))
+                Some(sig.substitute(Interner, parameters))
             }
             TyKind::Closure(.., substs) => {
                 let sig_param = substs.at(Interner, 0).assert_ty_ref(Interner);
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index f580e09e9122..7bb79b519e1c 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -12,8 +12,7 @@ use crate::{
     builder::ParamKind,
     consteval,
     method_resolution::{self, VisibleFromModule},
-    GenericArgData, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
-    ValueTyDefId,
+    Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
 };
 
 use super::{ExprOrPatId, InferenceContext, TraitRef};
@@ -104,9 +103,7 @@ impl<'a> InferenceContext<'a> {
             .use_parent_substs(&parent_substs)
             .fill(|x| {
                 it.next().unwrap_or_else(|| match x {
-                    ParamKind::Type => {
-                        GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
-                    }
+                    ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
                     ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
                 })
             })
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index e28c87dfa46b..da19dab9f986 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -678,7 +678,7 @@ impl<'a> TyLoweringContext<'a> {
         let total_len =
             parent_params + self_params + type_params + const_params + impl_trait_params;
 
-        let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
+        let ty_error = TyKind::Error.intern(Interner).cast(Interner);
 
         let mut def_generic_iter = def_generics.iter_id();
 
@@ -696,7 +696,7 @@ impl<'a> TyLoweringContext<'a> {
         let fill_self_params = || {
             for x in explicit_self_ty
                 .into_iter()
-                .map(|x| GenericArgData::Ty(x).intern(Interner))
+                .map(|x| x.cast(Interner))
                 .chain(iter::repeat(ty_error.clone()))
                 .take(self_params)
             {
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index d6638db02851..32ccd5fa43db 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -4,7 +4,7 @@
 use std::iter;
 
 use base_db::CrateId;
-use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
+use chalk_ir::{cast::Cast, fold::Shift, BoundVar, DebruijnIndex};
 use hir_def::{
     db::DefDatabase,
     generics::{
@@ -24,8 +24,7 @@ use smallvec::{smallvec, SmallVec};
 use syntax::SmolStr;
 
 use crate::{
-    db::HirDatabase, ChalkTraitId, ConstData, ConstValue, GenericArgData, Interner, Substitution,
-    TraitRef, TraitRefExt, TyKind, WhereClause,
+    db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, WhereClause,
 };
 
 pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator {
@@ -282,8 +281,8 @@ impl Generics {
         }
     }
 
-    fn parent_generics(&self) -> Option<&Generics> {
-        self.parent_generics.as_ref().map(|it| &**it)
+    pub(crate) fn parent_generics(&self) -> Option<&Generics> {
+        self.parent_generics.as_deref()
     }
 
     /// Returns a Substitution that replaces each parameter by a bound variable.
@@ -295,18 +294,10 @@ impl Generics {
         Substitution::from_iter(
             Interner,
             self.iter_id().enumerate().map(|(idx, id)| match id {
-                Either::Left(_) => GenericArgData::Ty(
-                    TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner),
-                )
-                .intern(Interner),
-                Either::Right(id) => GenericArgData::Const(
-                    ConstData {
-                        value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
-                        ty: db.const_param_ty(id),
-                    }
-                    .intern(Interner),
-                )
-                .intern(Interner),
+                Either::Left(_) => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
+                Either::Right(id) => BoundVar::new(debruijn, idx)
+                    .to_const(Interner, db.const_param_ty(id))
+                    .cast(Interner),
             }),
         )
     }
@@ -316,18 +307,12 @@ impl Generics {
         Substitution::from_iter(
             Interner,
             self.iter_id().map(|id| match id {
-                Either::Left(id) => GenericArgData::Ty(
-                    TyKind::Placeholder(crate::to_placeholder_idx(db, id.into())).intern(Interner),
-                )
-                .intern(Interner),
-                Either::Right(id) => GenericArgData::Const(
-                    ConstData {
-                        value: ConstValue::Placeholder(crate::to_placeholder_idx(db, id.into())),
-                        ty: db.const_param_ty(id),
-                    }
-                    .intern(Interner),
-                )
-                .intern(Interner),
+                Either::Left(id) => {
+                    crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
+                }
+                Either::Right(id) => crate::to_placeholder_idx(db, id.into())
+                    .to_const(Interner, db.const_param_ty(id))
+                    .cast(Interner),
             }),
         )
     }

From 4385d3dcd0df7713b3a35f31f11034f0a570adbd Mon Sep 17 00:00:00 2001
From: Ryo Yoshida 
Date: Sun, 2 Oct 2022 21:13:21 +0900
Subject: [PATCH 075/175] Change generic parameter/argument order

This commit "inverts" the order of generic parameters/arguments of an
item and its parent. This is to fulfill chalk's expectation on the
order of `Substitution` for generic associated types and it's one step
forward for their support (hopefully).

Although chalk doesn't put any constraint on the order of `Substitution`
for other items, it feels natural to get everything aligned rather than
special casing GATs.

One complication is that `TyBuilder` now demands its users to pass in
parent's `Substitution` upon construction unless it's obvious that the
the item has no parent (e.g. an ADT never has parent). All users
*should* already know the parent of the item in question, and without
this, it cannot be easily reasoned about whether we're pushing the
argument for the item or for its parent.

Quick comparison of how this commit changes `Substitution`:

```rust
trait Trait {
  type Type = ();
  fn f() {}
}
```

- before this commit: `[Self, TP, CP, TC, CC]` for each trait item
- after this commit: `[TC, CC, Self, TP, CP]` for each trait item
---
 crates/hir-ty/src/builder.rs | 182 ++++++++++++++++++++---------------
 crates/hir-ty/src/lower.rs   |  13 +++
 crates/hir-ty/src/utils.rs   |  33 +++++--
 3 files changed, 141 insertions(+), 87 deletions(-)

diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs
index dd4f1f25a691..c0052258ee03 100644
--- a/crates/hir-ty/src/builder.rs
+++ b/crates/hir-ty/src/builder.rs
@@ -34,17 +34,32 @@ pub struct TyBuilder {
     data: D,
     vec: SmallVec<[GenericArg; 2]>,
     param_kinds: SmallVec<[ParamKind; 2]>,
+    parent_subst: Substitution,
 }
 
 impl TyBuilder {
     fn with_data(self, data: B) -> TyBuilder {
-        TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
+        TyBuilder {
+            data,
+            vec: self.vec,
+            param_kinds: self.param_kinds,
+            parent_subst: self.parent_subst,
+        }
     }
 }
 
 impl TyBuilder {
-    fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder {
-        TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
+    fn new(
+        data: D,
+        param_kinds: SmallVec<[ParamKind; 2]>,
+        parent_subst: Option,
+    ) -> Self {
+        let parent_subst = parent_subst.unwrap_or_else(|| Substitution::empty(Interner));
+        Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst }
+    }
+
+    fn new_empty(data: D) -> Self {
+        TyBuilder::new(data, SmallVec::new(), None)
     }
 
     fn build_internal(self) -> (D, Substitution) {
@@ -52,13 +67,18 @@ impl TyBuilder {
         for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
             self.assert_match_kind(a, e);
         }
-        let subst = Substitution::from_iter(Interner, self.vec);
+        let subst = Substitution::from_iter(
+            Interner,
+            self.vec.into_iter().chain(self.parent_subst.iter(Interner).cloned()),
+        );
         (self.data, subst)
     }
 
     pub fn push(mut self, arg: impl CastTo) -> Self {
+        assert!(self.remaining() > 0);
         let arg = arg.cast(Interner);
         let expected_kind = &self.param_kinds[self.vec.len()];
+
         let arg_kind = match arg.data(Interner) {
             chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
             chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
@@ -68,7 +88,9 @@ impl TyBuilder {
             }
         };
         assert_eq!(*expected_kind, arg_kind);
+
         self.vec.push(arg);
+
         self
     }
 
@@ -116,20 +138,6 @@ impl TyBuilder {
         self
     }
 
-    pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
-        assert!(self.vec.is_empty());
-        assert!(parent_substs.len(Interner) <= self.param_kinds.len());
-        self.extend(parent_substs.iter(Interner).cloned());
-        self
-    }
-
-    fn extend(&mut self, it: impl Iterator + Clone) {
-        for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
-            self.assert_match_kind(&x.0, &x.1);
-        }
-        self.vec.extend(it);
-    }
-
     fn assert_match_kind(&self, a: &chalk_ir::GenericArg, e: &ParamKind) {
         match (a.data(Interner), e) {
             (chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
@@ -178,53 +186,44 @@ impl TyBuilder<()> {
         params.placeholder_subst(db)
     }
 
-    pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into) -> TyBuilder<()> {
-        let def = def.into();
-        let params = generics(db.upcast(), def);
-        TyBuilder::new(
-            (),
-            params
-                .iter()
-                .map(|(id, data)| match data {
-                    TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
-                    TypeOrConstParamData::ConstParamData(_) => {
-                        ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
-                    }
-                })
-                .collect(),
-        )
+    pub fn subst_for_def(
+        db: &dyn HirDatabase,
+        def: impl Into,
+        parent_subst: Option,
+    ) -> TyBuilder<()> {
+        let generics = generics(db.upcast(), def.into());
+        // FIXME: this assertion should hold but some adjustment around
+        // `ValueTyDefId::EnumVariantId` is needed.
+        // assert!(generics.parent_generics().is_some() == parent_subst.is_some());
+        let params = generics
+            .iter_self()
+            .map(|(id, data)| match data {
+                TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
+                TypeOrConstParamData::ConstParamData(_) => {
+                    ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
+                }
+            })
+            .collect();
+        TyBuilder::new((), params, parent_subst)
     }
 
     /// Creates a `TyBuilder` to build `Substitution` for a generator defined in `parent`.
     ///
     /// A generator's substitution consists of:
-    /// - generic parameters in scope on `parent`
     /// - resume type of generator
     /// - yield type of generator ([`Generator::Yield`](std::ops::Generator::Yield))
     /// - return type of generator ([`Generator::Return`](std::ops::Generator::Return))
+    /// - generic parameters in scope on `parent`
     /// in this order.
     ///
     /// This method prepopulates the builder with placeholder substitution of `parent`, so you
     /// should only push exactly 3 `GenericArg`s before building.
     pub fn subst_for_generator(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
-        let parent_subst = match parent.as_generic_def_id() {
-            Some(parent) => generics(db.upcast(), parent).placeholder_subst(db),
-            // Static initializers *may* contain generators.
-            None => Substitution::empty(Interner),
-        };
-        let builder = TyBuilder::new(
-            (),
-            parent_subst
-                .iter(Interner)
-                .map(|arg| match arg.constant(Interner) {
-                    Some(c) => ParamKind::Const(c.data(Interner).ty.clone()),
-                    None => ParamKind::Type,
-                })
-                // These represent resume type, yield type, and return type of generator.
-                .chain(std::iter::repeat(ParamKind::Type).take(3))
-                .collect(),
-        );
-        builder.use_parent_substs(&parent_subst)
+        let parent_subst =
+            parent.as_generic_def_id().map(|p| generics(db.upcast(), p).placeholder_subst(db));
+        // These represent resume type, yield type, and return type of generator.
+        let params = std::iter::repeat(ParamKind::Type).take(3).collect();
+        TyBuilder::new((), params, parent_subst)
     }
 
     pub fn build(self) -> Substitution {
@@ -235,7 +234,7 @@ impl TyBuilder<()> {
 
 impl TyBuilder {
     pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder {
-        TyBuilder::subst_for_def(db, def).with_data(def)
+        TyBuilder::subst_for_def(db, def, None).with_data(def)
     }
 
     pub fn fill_with_defaults(
@@ -243,7 +242,9 @@ impl TyBuilder {
         db: &dyn HirDatabase,
         mut fallback: impl FnMut() -> Ty,
     ) -> Self {
+        // Note that we're building ADT, so we never have parent generic parameters.
         let defaults = db.generic_defaults(self.data.into());
+        let dummy_ty = TyKind::Error.intern(Interner).cast(Interner);
         for default_ty in defaults.iter().skip(self.vec.len()) {
             // NOTE(skip_binders): we only check if the arg type is error type.
             if let Some(x) = default_ty.skip_binders().ty(Interner) {
@@ -251,9 +252,17 @@ impl TyBuilder {
                     self.vec.push(fallback().cast(Interner));
                     continue;
                 }
-            };
-            // each default can depend on the previous parameters
-            let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
+            }
+            // Each default can only depend on the previous parameters.
+            // FIXME: we don't handle const generics here.
+            let subst_so_far = Substitution::from_iter(
+                Interner,
+                self.vec
+                    .iter()
+                    .cloned()
+                    .chain(iter::repeat(dummy_ty.clone()))
+                    .take(self.param_kinds.len()),
+            );
             self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
         }
         self
@@ -268,7 +277,7 @@ impl TyBuilder {
 pub struct Tuple(usize);
 impl TyBuilder {
     pub fn tuple(size: usize) -> TyBuilder {
-        TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
+        TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect(), None)
     }
 
     pub fn build(self) -> Ty {
@@ -279,7 +288,7 @@ impl TyBuilder {
 
 impl TyBuilder {
     pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder {
-        TyBuilder::subst_for_def(db, def).with_data(def)
+        TyBuilder::subst_for_def(db, def, None).with_data(def)
     }
 
     pub fn build(self) -> TraitRef {
@@ -289,8 +298,12 @@ impl TyBuilder {
 }
 
 impl TyBuilder {
-    pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder {
-        TyBuilder::subst_for_def(db, def).with_data(def)
+    pub fn assoc_type_projection(
+        db: &dyn HirDatabase,
+        def: TypeAliasId,
+        parent_subst: Option,
+    ) -> TyBuilder {
+        TyBuilder::subst_for_def(db, def, parent_subst).with_data(def)
     }
 
     pub fn build(self) -> ProjectionTy {
@@ -300,19 +313,6 @@ impl TyBuilder {
 }
 
 impl + TypeFoldable> TyBuilder> {
-    fn subst_binders(b: Binders) -> Self {
-        let param_kinds = b
-            .binders
-            .iter(Interner)
-            .map(|x| match x {
-                chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
-                chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
-                chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
-            })
-            .collect();
-        TyBuilder::new(b, param_kinds)
-    }
-
     pub fn build(self) -> T {
         let (b, subst) = self.build_internal();
         b.substitute(Interner, &subst)
@@ -320,15 +320,41 @@ impl + TypeFoldable> TyBuilder> {
-    pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder> {
-        TyBuilder::subst_binders(db.ty(def))
+    pub fn def_ty(
+        db: &dyn HirDatabase,
+        def: TyDefId,
+        parent_subst: Option,
+    ) -> TyBuilder> {
+        let poly_ty = db.ty(def);
+        let id: GenericDefId = match def {
+            TyDefId::BuiltinType(_) => {
+                assert!(parent_subst.is_none());
+                return TyBuilder::new_empty(poly_ty);
+            }
+            TyDefId::AdtId(id) => id.into(),
+            TyDefId::TypeAliasId(id) => id.into(),
+        };
+        TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
     }
 
     pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder> {
-        TyBuilder::subst_binders(db.impl_self_ty(def))
+        TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
     }
 
-    pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder> {
-        TyBuilder::subst_binders(db.value_ty(def))
+    pub fn value_ty(
+        db: &dyn HirDatabase,
+        def: ValueTyDefId,
+        parent_subst: Option,
+    ) -> TyBuilder> {
+        let poly_value_ty = db.value_ty(def);
+        let id = match def.to_generic_def_id() {
+            Some(id) => id,
+            None => {
+                // static items
+                assert!(parent_subst.is_none());
+                return TyBuilder::new_empty(poly_value_ty);
+            }
+        };
+        TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_value_ty)
     }
 }
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index da19dab9f986..82128ae6586d 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -1641,6 +1641,19 @@ pub enum ValueTyDefId {
 }
 impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
 
+impl ValueTyDefId {
+    pub(crate) fn to_generic_def_id(self) -> Option {
+        match self {
+            Self::FunctionId(id) => Some(id.into()),
+            Self::StructId(id) => Some(id.into()),
+            Self::UnionId(id) => Some(id.into()),
+            Self::EnumVariantId(var) => Some(var.parent.into()),
+            Self::ConstId(id) => Some(id.into()),
+            Self::StaticId(_) => None,
+        }
+    }
+}
+
 /// Build the declared type of an item. This depends on the namespace; e.g. for
 /// `struct Foo(usize)`, we have two types: The type of the struct itself, and
 /// the constructor function `(usize) -> Foo` which lives in the values
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index 32ccd5fa43db..adcf142bc35f 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -220,23 +220,30 @@ impl Generics {
         })
     }
 
-    /// Iterator over types and const params of parent, then self.
+    /// Iterator over types and const params of self, then parent.
     pub(crate) fn iter<'a>(
         &'a self,
     ) -> impl DoubleEndedIterator + 'a {
         let to_toc_id = |it: &'a Generics| {
             move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
         };
-        self.parent_generics()
-            .into_iter()
-            .flat_map(move |it| it.params.iter().map(to_toc_id(it)))
-            .chain(self.params.iter().map(to_toc_id(self)))
+        self.params.iter().map(to_toc_id(self)).chain(self.iter_parent())
+    }
+
+    /// Iterate over types and const params without parent params.
+    pub(crate) fn iter_self<'a>(
+        &'a self,
+    ) -> impl DoubleEndedIterator + 'a {
+        let to_toc_id = |it: &'a Generics| {
+            move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
+        };
+        self.params.iter().map(to_toc_id(self))
     }
 
     /// Iterator over types and const params of parent.
     pub(crate) fn iter_parent<'a>(
         &'a self,
-    ) -> impl Iterator + 'a {
+    ) -> impl DoubleEndedIterator + 'a {
         self.parent_generics().into_iter().flat_map(|it| {
             let to_toc_id =
                 move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p);
@@ -244,12 +251,18 @@ impl Generics {
         })
     }
 
+    /// Returns total number of generic parameters in scope, including those from parent.
     pub(crate) fn len(&self) -> usize {
         let parent = self.parent_generics().map_or(0, Generics::len);
         let child = self.params.type_or_consts.len();
         parent + child
     }
 
+    /// Returns numbers of generic parameters excluding those from parent.
+    pub(crate) fn len_self(&self) -> usize {
+        self.params.type_or_consts.len()
+    }
+
     /// (parent total, self param, type param list, const param list, impl trait)
     pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
         let ty_iter = || self.params.iter().filter_map(|x| x.1.type_param());
@@ -274,10 +287,12 @@ impl Generics {
         if param.parent == self.def {
             let (idx, (_local_id, data)) =
                 self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
-            let parent_len = self.parent_generics().map_or(0, Generics::len);
-            Some((parent_len + idx, data))
+            Some((idx, data))
         } else {
-            self.parent_generics().and_then(|g| g.find_param(param))
+            self.parent_generics()
+                .and_then(|g| g.find_param(param))
+                // Remember that parent parameters come after parameters for self.
+                .map(|(idx, data)| (self.len_self() + idx, data))
         }
     }
 

From 78977cd86cd17e008f94f8579d6a5aaebe46e69b Mon Sep 17 00:00:00 2001
From: Ryo Yoshida 
Date: Sun, 2 Oct 2022 22:15:57 +0900
Subject: [PATCH 076/175] Adapt to the new generic parameter/argument order

---
 crates/hir-ty/src/autoderef.rs         |   5 +-
 crates/hir-ty/src/chalk_db.rs          |  14 +-
 crates/hir-ty/src/display.rs           |  16 +-
 crates/hir-ty/src/infer.rs             |  19 ++-
 crates/hir-ty/src/infer/expr.rs        |  43 +++---
 crates/hir-ty/src/infer/path.rs        |  17 ++-
 crates/hir-ty/src/infer/unify.rs       |   7 +-
 crates/hir-ty/src/lower.rs             | 193 +++++++++++++++----------
 crates/hir-ty/src/method_resolution.rs |  34 ++---
 crates/hir/src/lib.rs                  |  26 +++-
 crates/hir/src/source_analyzer.rs      |  46 ++++--
 11 files changed, 259 insertions(+), 161 deletions(-)

diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index 344036dd8139..02332ea80d88 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -123,13 +123,14 @@ fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option {
     let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
 
     let projection = {
-        let b = TyBuilder::assoc_type_projection(db, target);
+        let b = TyBuilder::subst_for_def(db, deref_trait, None);
         if b.remaining() != 1 {
             // the Target type + Deref trait should only have one generic parameter,
             // namely Deref's Self type
             return None;
         }
-        b.push(ty).build()
+        let deref_subst = b.push(ty).build();
+        TyBuilder::assoc_type_projection(db, target, Some(deref_subst)).build()
     };
 
     // Check that the type implements Deref at all
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index c5cf6729d119..3f3f8f7d0f2a 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -382,13 +382,12 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> {
         // `resume_type`, `yield_type`, and `return_type` of the generator in question.
         let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
 
-        let len = subst.len(Interner);
         let input_output = rust_ir::GeneratorInputOutputDatum {
-            resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 3))
+            resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
                 .intern(Interner),
-            yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 2))
+            yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 1))
                 .intern(Interner),
-            return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 1))
+            return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 2))
                 .intern(Interner),
             // FIXME: calculate upvars
             upvars: vec![],
@@ -476,10 +475,15 @@ pub(crate) fn associated_ty_data_query(
     let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
     let ctx = crate::TyLoweringContext::new(db, &resolver)
         .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
-    let pro_ty = TyBuilder::assoc_type_projection(db, type_alias)
+
+    let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
+        .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
+        .build();
+    let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst))
         .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0)
         .build();
     let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner);
+
     let mut bounds: Vec<_> = type_alias_data
         .bounds
         .iter()
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index a5058f71a4a6..7f0baf49dadc 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -27,7 +27,7 @@ use crate::{
     db::HirDatabase,
     from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
     mapping::from_chalk,
-    primitive, subst_prefix, to_assoc_type_id,
+    primitive, to_assoc_type_id,
     utils::{self, generics},
     AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
     GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
@@ -506,8 +506,15 @@ impl HirDisplay for Ty {
                     let total_len = parent_params + self_param + type_params + const_params;
                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
                     if total_len > 0 {
+                        // `parameters` are in the order of fn's params (including impl traits),
+                        // parent's params (those from enclosing impl or trait, if any).
+                        let parameters = parameters.as_slice(Interner);
+                        let fn_params_len = self_param + type_params + const_params;
+                        let fn_params = parameters.get(..fn_params_len);
+                        let parent_params = parameters.get(parameters.len() - parent_params..);
+                        let params = parent_params.into_iter().chain(fn_params).flatten();
                         write!(f, "<")?;
-                        f.write_joined(¶meters.as_slice(Interner)[..total_len], ", ")?;
+                        f.write_joined(params, ", ")?;
                         write!(f, ">")?;
                     }
                 }
@@ -579,9 +586,8 @@ impl HirDisplay for Ty {
                                         Some(x) => x,
                                         None => return true,
                                     };
-                                    let actual_default = default_parameter
-                                        .clone()
-                                        .substitute(Interner, &subst_prefix(parameters, i));
+                                    let actual_default =
+                                        default_parameter.clone().substitute(Interner, ¶meters);
                                     parameter != &actual_default
                                 }
                                 let mut default_from = 0;
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 25179afaca7a..31e56dec6259 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -26,8 +26,8 @@ use hir_def::{
     path::{path, Path},
     resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
     type_ref::TypeRef,
-    AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
-    TraitId, TypeAliasId, VariantId,
+    AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
+    ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
 };
 use hir_expand::name::{name, Name};
 use itertools::Either;
@@ -713,6 +713,8 @@ impl<'a> InferenceContext<'a> {
         &mut self,
         inner_ty: Ty,
         assoc_ty: Option,
+        // FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
+        // handled when we support them.
         params: &[GenericArg],
     ) -> Ty {
         match assoc_ty {
@@ -804,7 +806,18 @@ impl<'a> InferenceContext<'a> {
                 self.resolve_variant_on_alias(ty, unresolved, path)
             }
             TypeNs::TypeAliasId(it) => {
-                let ty = TyBuilder::def_ty(self.db, it.into())
+                let container = it.lookup(self.db.upcast()).container;
+                let parent_subst = match container {
+                    ItemContainerId::TraitId(id) => {
+                        let subst = TyBuilder::subst_for_def(self.db, id, None)
+                            .fill_with_inference_vars(&mut self.table)
+                            .build();
+                        Some(subst)
+                    }
+                    // Type aliases do not exist in impls.
+                    _ => None,
+                };
+                let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst)
                     .fill_with_inference_vars(&mut self.table)
                     .build();
                 self.resolve_variant_on_alias(ty, unresolved, path)
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 2643baf8a329..f56108b26c45 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -987,11 +987,13 @@ impl<'a> InferenceContext<'a> {
         let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
         let rhs_ty = self.table.new_type_var();
 
-        let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
-            self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name)
+        let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
+            let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
+            let func = self.db.trait_data(trait_id).method_by_name(&name)?;
+            Some((trait_id, func))
         });
-        let func = match func {
-            Some(func) => func,
+        let (trait_, func) = match trait_func {
+            Some(it) => it,
             None => {
                 let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
                 let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
@@ -1001,7 +1003,9 @@ impl<'a> InferenceContext<'a> {
             }
         };
 
-        let subst = TyBuilder::subst_for_def(self.db, func)
+        // HACK: We can use this substitution for the function because the function itself doesn't
+        // have its own generic parameters.
+        let subst = TyBuilder::subst_for_def(self.db, trait_, None)
             .push(lhs_ty.clone())
             .push(rhs_ty.clone())
             .build();
@@ -1280,19 +1284,7 @@ impl<'a> InferenceContext<'a> {
         assert_eq!(self_params, 0); // method shouldn't have another Self param
         let total_len = parent_params + type_params + const_params + impl_trait_params;
         let mut substs = Vec::with_capacity(total_len);
-        // Parent arguments are unknown
-        for (id, param) in def_generics.iter_parent() {
-            match param {
-                TypeOrConstParamData::TypeParamData(_) => {
-                    substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
-                }
-                TypeOrConstParamData::ConstParamData(_) => {
-                    let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
-                    substs
-                        .push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
-                }
-            }
-        }
+
         // handle provided arguments
         if let Some(generic_args) = generic_args {
             // if args are provided, it should be all of them, but we can't rely on that
@@ -1301,7 +1293,7 @@ impl<'a> InferenceContext<'a> {
                 .iter()
                 .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
                 .take(type_params + const_params)
-                .zip(def_generics.iter_id().skip(parent_params))
+                .zip(def_generics.iter_id())
             {
                 if let Some(g) = generic_arg_to_chalk(
                     self.db,
@@ -1325,6 +1317,9 @@ impl<'a> InferenceContext<'a> {
                 }
             }
         };
+
+        // Handle everything else as unknown. This also handles generic arguments for the method's
+        // parent (impl or trait), which should come after those for the method.
         for (id, data) in def_generics.iter().skip(substs.len()) {
             match data {
                 TypeOrConstParamData::TypeParamData(_) => {
@@ -1362,9 +1357,13 @@ impl<'a> InferenceContext<'a> {
                 CallableDefId::FunctionId(f) => {
                     if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
                         // construct a TraitRef
-                        let substs = crate::subst_prefix(
-                            &*parameters,
-                            generics(self.db.upcast(), trait_.into()).len(),
+                        let params_len = parameters.len(Interner);
+                        let trait_params_len = generics(self.db.upcast(), trait_.into()).len();
+                        let substs = Substitution::from_iter(
+                            Interner,
+                            // The generic parameters for the trait come after those for the
+                            // function.
+                            ¶meters.as_slice(Interner)[params_len - trait_params_len..],
                         );
                         self.push_obligation(
                             TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 7bb79b519e1c..7a4754cdc7bb 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -12,6 +12,7 @@ use crate::{
     builder::ParamKind,
     consteval,
     method_resolution::{self, VisibleFromModule},
+    utils::generics,
     Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
 };
 
@@ -95,12 +96,18 @@ impl<'a> InferenceContext<'a> {
             ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
         };
 
-        let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner));
         let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
         let substs = ctx.substs_from_path(path, typable, true);
-        let mut it = substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned();
-        let ty = TyBuilder::value_ty(self.db, typable)
-            .use_parent_substs(&parent_substs)
+        let substs = substs.as_slice(Interner);
+        let parent_substs = self_subst.or_else(|| {
+            let generics = generics(self.db.upcast(), typable.to_generic_def_id()?);
+            let parent_params_len = generics.parent_generics()?.len();
+            let parent_args = &substs[substs.len() - parent_params_len..];
+            Some(Substitution::from_iter(Interner, parent_args))
+        });
+        let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner));
+        let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned();
+        let ty = TyBuilder::value_ty(self.db, typable, parent_substs)
             .fill(|x| {
                 it.next().unwrap_or_else(|| match x {
                     ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
@@ -246,7 +253,7 @@ impl<'a> InferenceContext<'a> {
                 };
                 let substs = match container {
                     ItemContainerId::ImplId(impl_id) => {
-                        let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
+                        let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
                             .fill_with_inference_vars(&mut self.table)
                             .build();
                         let impl_self_ty =
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index e77b55670b5e..6ccd0b215c6e 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -598,11 +598,14 @@ impl<'a> InferenceTable<'a> {
             .build();
 
         let projection = {
-            let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
+            let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
             if b.remaining() != 2 {
                 return None;
             }
-            b.push(ty.clone()).push(arg_ty).build()
+            let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
+
+            TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
+                .build()
         };
 
         let trait_env = self.trait_env.env.clone();
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 82128ae6586d..0a4b1dfda105 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -306,7 +306,7 @@ impl<'a> TyLoweringContext<'a> {
                         // FIXME we're probably doing something wrong here
                         self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
                         let (
-                            parent_params,
+                            _parent_params,
                             self_params,
                             list_params,
                             const_params,
@@ -319,7 +319,7 @@ impl<'a> TyLoweringContext<'a> {
                         };
                         TyKind::BoundVar(BoundVar::new(
                             self.in_binders,
-                            idx as usize + parent_params + self_params + list_params + const_params,
+                            idx as usize + self_params + list_params + const_params,
                         ))
                         .intern(Interner)
                     }
@@ -499,14 +499,31 @@ impl<'a> TyLoweringContext<'a> {
                 .intern(Interner)
             }
             TypeNs::SelfType(impl_id) => {
-                let generics = generics(self.db.upcast(), impl_id.into());
-                let substs = match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
-                    ParamLoweringMode::Variable => {
-                        generics.bound_vars_subst(self.db, self.in_binders)
+                let def =
+                    self.resolver.generic_def().expect("impl should have generic param scope");
+                let generics = generics(self.db.upcast(), def);
+
+                match self.type_param_mode {
+                    ParamLoweringMode::Placeholder => {
+                        // `def` can be either impl itself or item within, and we need impl itself
+                        // now.
+                        let generics = generics.parent_generics().unwrap_or(&generics);
+                        let subst = generics.placeholder_subst(self.db);
+                        self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
                     }
-                };
-                self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
+                    ParamLoweringMode::Variable => {
+                        let starting_from = match def {
+                            GenericDefId::ImplId(_) => 0,
+                            // `def` is an item within impl. We need to substitute `BoundVar`s but
+                            // remember that they are for parent (i.e. impl) generic params so they
+                            // come after our own params.
+                            _ => generics.len_self(),
+                        };
+                        TyBuilder::impl_self_ty(self.db, impl_id)
+                            .fill_with_bound_vars(self.in_binders, starting_from)
+                            .build()
+                    }
+                }
             }
             TypeNs::AdtSelfType(adt) => {
                 let generics = generics(self.db.upcast(), adt.into());
@@ -636,13 +653,9 @@ impl<'a> TyLoweringContext<'a> {
         infer_args: bool,
     ) -> Substitution {
         let last = path.segments().last().expect("path should have at least one segment");
-        let (segment, generic_def) = match resolved {
-            ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
-            ValueTyDefId::StructId(it) => (last, Some(it.into())),
-            ValueTyDefId::UnionId(it) => (last, Some(it.into())),
-            ValueTyDefId::ConstId(it) => (last, Some(it.into())),
-            ValueTyDefId::StaticId(_) => (last, None),
-            ValueTyDefId::EnumVariantId(var) => {
+        let generic_def = resolved.to_generic_def_id();
+        let segment = match resolved {
+            ValueTyDefId::EnumVariantId(_) => {
                 // the generic args for an enum variant may be either specified
                 // on the segment referring to the enum, or on the segment
                 // referring to the variant. So `Option::::None` and
@@ -650,12 +663,12 @@ impl<'a> TyLoweringContext<'a> {
                 // preferred). See also `def_ids_for_path_segments` in rustc.
                 let len = path.segments().len();
                 let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
-                let segment = match penultimate {
+                match penultimate {
                     Some(segment) if segment.args_and_bindings.is_some() => segment,
                     _ => last,
-                };
-                (segment, Some(var.parent.into()))
+                }
             }
+            _ => last,
         };
         self.substs_from_path_segment(segment, generic_def, infer_args, None)
     }
@@ -663,36 +676,27 @@ impl<'a> TyLoweringContext<'a> {
     fn substs_from_path_segment(
         &self,
         segment: PathSegment<'_>,
-        def_generic: Option,
+        def: Option,
         infer_args: bool,
         explicit_self_ty: Option,
     ) -> Substitution {
+        // Remember that the item's own generic args come before its parent's.
         let mut substs = Vec::new();
-        let def_generics = if let Some(def) = def_generic {
-            generics(self.db.upcast(), def)
+        let def = if let Some(d) = def {
+            d
         } else {
             return Substitution::empty(Interner);
         };
+        let def_generics = generics(self.db.upcast(), def);
         let (parent_params, self_params, type_params, const_params, impl_trait_params) =
             def_generics.provenance_split();
-        let total_len =
-            parent_params + self_params + type_params + const_params + impl_trait_params;
+        let item_len = self_params + type_params + const_params + impl_trait_params;
+        let total_len = parent_params + item_len;
 
         let ty_error = TyKind::Error.intern(Interner).cast(Interner);
 
         let mut def_generic_iter = def_generics.iter_id();
 
-        for _ in 0..parent_params {
-            if let Some(eid) = def_generic_iter.next() {
-                match eid {
-                    Either::Left(_) => substs.push(ty_error.clone()),
-                    Either::Right(x) => {
-                        substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
-                    }
-                }
-            }
-        }
-
         let fill_self_params = || {
             for x in explicit_self_ty
                 .into_iter()
@@ -757,37 +761,40 @@ impl<'a> TyLoweringContext<'a> {
             fill_self_params();
         }
 
+        // These params include those of parent.
+        let remaining_params: SmallVec<[_; 2]> = def_generic_iter
+            .map(|eid| match eid {
+                Either::Left(_) => ty_error.clone(),
+                Either::Right(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
+            })
+            .collect();
+        assert_eq!(remaining_params.len() + substs.len(), total_len);
+
         // handle defaults. In expression or pattern path segments without
         // explicitly specified type arguments, missing type arguments are inferred
         // (i.e. defaults aren't used).
         if !infer_args || had_explicit_args {
-            if let Some(def_generic) = def_generic {
-                let defaults = self.db.generic_defaults(def_generic);
-                assert_eq!(total_len, defaults.len());
+            let defaults = self.db.generic_defaults(def);
+            assert_eq!(total_len, defaults.len());
+            let parent_from = item_len - substs.len();
 
-                for default_ty in defaults.iter().skip(substs.len()) {
-                    // each default can depend on the previous parameters
-                    let substs_so_far = Substitution::from_iter(Interner, substs.clone());
-                    if let Some(_id) = def_generic_iter.next() {
-                        substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
-                    }
-                }
+            for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() {
+                // each default can depend on the previous parameters
+                let substs_so_far = Substitution::from_iter(
+                    Interner,
+                    substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()),
+                );
+                substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
             }
+
+            // Keep parent's params as unknown.
+            let mut remaining_params = remaining_params;
+            substs.extend(remaining_params.drain(parent_from..));
+        } else {
+            substs.extend(remaining_params);
         }
 
-        // add placeholders for args that were not provided
-        // FIXME: emit diagnostics in contexts where this is not allowed
-        for eid in def_generic_iter {
-            match eid {
-                Either::Left(_) => substs.push(ty_error.clone()),
-                Either::Right(x) => {
-                    substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
-                }
-            }
-        }
-        // If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
         assert_eq!(substs.len(), total_len);
-
         Substitution::from_iter(Interner, substs)
     }
 
@@ -1168,10 +1175,18 @@ fn named_associated_type_shorthand_candidates(
             }
             // Handle `Self::Type` referring to own associated type in trait definitions
             if let GenericDefId::TraitId(trait_id) = param_id.parent() {
-                let generics = generics(db.upcast(), trait_id.into());
-                if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
+                let trait_generics = generics(db.upcast(), trait_id.into());
+                if trait_generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
+                    let def_generics = generics(db.upcast(), def);
+                    let starting_idx = match def {
+                        GenericDefId::TraitId(_) => 0,
+                        // `def` is an item within trait. We need to substitute `BoundVar`s but
+                        // remember that they are for parent (i.e. trait) generic params so they
+                        // come after our own params.
+                        _ => def_generics.len_self(),
+                    };
                     let trait_ref = TyBuilder::trait_ref(db, trait_id)
-                        .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
+                        .fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
                         .build();
                     return search(trait_ref);
                 }
@@ -1413,6 +1428,7 @@ pub(crate) fn generic_defaults_query(
     let ctx =
         TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
     let generic_params = generics(db.upcast(), def);
+    let parent_start_idx = generic_params.len_self();
 
     let defaults = generic_params
         .iter()
@@ -1425,19 +1441,17 @@ pub(crate) fn generic_defaults_query(
                     let val = unknown_const_as_generic(
                         db.const_param_ty(ConstParamId::from_unchecked(id)),
                     );
-                    return crate::make_binders_with_count(db, idx, &generic_params, val);
+                    return make_binders(db, &generic_params, val);
                 }
             };
             let mut ty =
                 p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
 
             // Each default can only refer to previous parameters.
-            // type variable default referring to parameter coming
-            // after it. This is forbidden (FIXME: report
-            // diagnostic)
-            ty = fallback_bound_vars(ty, idx);
-            let val = GenericArgData::Ty(ty).intern(Interner);
-            crate::make_binders_with_count(db, idx, &generic_params, val)
+            // Type variable default referring to parameter coming
+            // after it is forbidden (FIXME: report diagnostic)
+            ty = fallback_bound_vars(ty, idx, parent_start_idx);
+            crate::make_binders(db, &generic_params, ty.cast(Interner))
         })
         .collect();
 
@@ -1454,15 +1468,14 @@ pub(crate) fn generic_defaults_recover(
     // we still need one default per parameter
     let defaults = generic_params
         .iter_id()
-        .enumerate()
-        .map(|(count, id)| {
+        .map(|id| {
             let val = match id {
                 itertools::Either::Left(_) => {
                     GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
                 }
                 itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
             };
-            crate::make_binders_with_count(db, count, &generic_params, val)
+            crate::make_binders(db, &generic_params, val)
         })
         .collect();
 
@@ -1837,26 +1850,48 @@ pub(crate) fn const_or_path_to_chalk(
     }
 }
 
-/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
-/// num_vars_to_keep) by `TyKind::Unknown`.
+/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
+/// parameter whose index is `param_index`. A `BoundVar` is free when it is or (syntactically)
+/// appears after the generic parameter of `param_index`.
 fn fallback_bound_vars + HasInterner>(
     s: T,
-    num_vars_to_keep: usize,
+    param_index: usize,
+    parent_start: usize,
 ) -> T {
+    // Keep in mind that parent generic parameters, if any, come *after* those of the item in
+    // question. In the diagrams below, `c*` and `p*` represent generic parameters of the item and
+    // its parent respectively.
+    let is_allowed = |index| {
+        if param_index < parent_start {
+            // The parameter of `param_index` is one from the item in question. Any parent generic
+            // parameters or the item's generic parameters that come before `param_index` is
+            // allowed.
+            // [c1, .., cj, .., ck, p1, .., pl] where cj is `param_index`
+            //  ^^^^^^              ^^^^^^^^^^ these are allowed
+            !(param_index..parent_start).contains(&index)
+        } else {
+            // The parameter of `param_index` is one from the parent generics. Only parent generic
+            // parameters that come before `param_index` are allowed.
+            // [c1, .., ck, p1, .., pj, .., pl] where pj is `param_index`
+            //              ^^^^^^ these are allowed
+            (parent_start..param_index).contains(&index)
+        }
+    };
+
     crate::fold_free_vars(
         s,
         |bound, binders| {
-            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
-                TyKind::Error.intern(Interner)
-            } else {
+            if bound.index_if_innermost().map_or(true, is_allowed) {
                 bound.shifted_in_from(binders).to_ty(Interner)
+            } else {
+                TyKind::Error.intern(Interner)
             }
         },
         |ty, bound, binders| {
-            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
-                unknown_const(ty.clone())
-            } else {
+            if bound.index_if_innermost().map_or(true, is_allowed) {
                 bound.shifted_in_from(binders).to_const(Interner, ty)
+            } else {
+                unknown_const(ty.clone())
             }
         },
     )
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 41fcef73d9be..5998680dcd39 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -654,7 +654,7 @@ fn find_matching_impl(
         let r = table.run_in_snapshot(|table| {
             let impl_data = db.impl_data(impl_);
             let substs =
-                TyBuilder::subst_for_def(db, impl_).fill_with_inference_vars(table).build();
+                TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
             let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
 
             table
@@ -1147,10 +1147,9 @@ fn is_valid_candidate(
             }));
             if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
                 let self_ty_matches = table.run_in_snapshot(|table| {
-                    let subst =
-                        TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build();
-                    let expected_self_ty =
-                        subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner);
+                    let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
+                        .fill_with_inference_vars(table)
+                        .build();
                     table.unify(&expected_self_ty, &self_ty)
                 });
                 if !self_ty_matches {
@@ -1186,31 +1185,26 @@ fn is_valid_fn_candidate(
 
     table.run_in_snapshot(|table| {
         let container = fn_id.lookup(db.upcast()).container;
-        let impl_subst = match container {
+        let (impl_subst, expect_self_ty) = match container {
             ItemContainerId::ImplId(it) => {
-                TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
+                let subst =
+                    TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
+                let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
+                (subst, self_ty)
             }
             ItemContainerId::TraitId(it) => {
-                TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
+                let subst =
+                    TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
+                let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
+                (subst, self_ty)
             }
             _ => unreachable!(),
         };
 
-        let fn_subst = TyBuilder::subst_for_def(db, fn_id)
-            .use_parent_substs(&impl_subst)
+        let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
             .fill_with_inference_vars(table)
             .build();
 
-        let expect_self_ty = match container {
-            ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
-            ItemContainerId::ImplId(impl_id) => {
-                fn_subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
-            }
-            // We should only get called for associated items (impl/trait)
-            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
-                unreachable!()
-            }
-        };
         check_that!(table.unify(&expect_self_ty, self_ty));
 
         if let Some(receiver_ty) = receiver_ty {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d1c8fa59aef4..e08dd8dadebc 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -61,7 +61,6 @@ use hir_ty::{
     diagnostics::BodyValidationDiagnostic,
     method_resolution::{self, TyFingerprint},
     primitive::UintTy,
-    subst_prefix,
     traits::FnTrait,
     AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
     GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
@@ -1090,7 +1089,7 @@ impl Adt {
     pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
         let id = AdtId::from(self);
         let mut it = args.iter().map(|t| t.ty.clone());
-        let ty = TyBuilder::def_ty(db, id.into())
+        let ty = TyBuilder::def_ty(db, id.into(), None)
             .fill(|x| {
                 let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
                 match x {
@@ -2547,7 +2546,7 @@ impl TypeParam {
         let resolver = self.id.parent().resolver(db.upcast());
         let ty = params.get(local_idx)?.clone();
         let subst = TyBuilder::placeholder_subst(db, self.id.parent());
-        let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
+        let ty = ty.substitute(Interner, &subst);
         match ty.data(Interner) {
             GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
             _ => None,
@@ -2801,7 +2800,18 @@ impl Type {
     }
 
     fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into) -> Type {
-        let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build();
+        let ty_def = def.into();
+        let parent_subst = match ty_def {
+            TyDefId::TypeAliasId(id) => match id.lookup(db.upcast()).container {
+                ItemContainerId::TraitId(id) => {
+                    let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
+                    Some(subst)
+                }
+                _ => None,
+            },
+            _ => None,
+        };
+        let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build();
         Type::new(db, def, ty)
     }
 
@@ -2941,7 +2951,11 @@ impl Type {
         alias: TypeAlias,
     ) -> Option {
         let mut args = args.iter();
-        let projection = TyBuilder::assoc_type_projection(db, alias.id)
+        let trait_id = match alias.id.lookup(db.upcast()).container {
+            ItemContainerId::TraitId(id) => id,
+            _ => unreachable!("non assoc type alias reached in normalize_trait_assoc_type()"),
+        };
+        let parent_subst = TyBuilder::subst_for_def(db, trait_id, None)
             .push(self.ty.clone())
             .fill(|x| {
                 // FIXME: this code is not covered in tests.
@@ -2953,6 +2967,8 @@ impl Type {
                 }
             })
             .build();
+        // FIXME: We don't handle GATs yet.
+        let projection = TyBuilder::assoc_type_projection(db, alias.id, Some(parent_subst)).build();
 
         let ty = db.normalize_projection(projection, self.env.clone());
         if ty.is_unknown() {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 342912b678a1..07bae2b38c79 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -22,7 +22,7 @@ use hir_def::{
     resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
     type_ref::Mutability,
     AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
-    Lookup, ModuleDefId, VariantId,
+    Lookup, ModuleDefId, TraitId, VariantId,
 };
 use hir_expand::{
     builtin_fn_macro::BuiltinFnLikeExpander,
@@ -302,10 +302,15 @@ impl SourceAnalyzer {
             }
         }
 
+        let future_trait = db
+            .lang_item(self.resolver.krate(), hir_expand::name![future_trait].to_smol_str())?
+            .as_trait()?;
         let poll_fn = db
             .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
             .as_function()?;
-        let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
+        // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
+        // doesn't have any generic parameters, so we skip building another subst for `poll()`.
+        let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
         Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
     }
 
@@ -321,8 +326,10 @@ impl SourceAnalyzer {
         };
         let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
 
-        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
-        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+        let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+        // HACK: subst for all methods coincides with that for their trait because the methods
+        // don't have any generic parameters, so we skip building another subst for the methods.
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
 
         Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
     }
@@ -337,8 +344,10 @@ impl SourceAnalyzer {
 
         let lang_item_name = name![index];
 
-        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
-        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
+        let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+        // HACK: subst for all methods coincides with that for their trait because the methods
+        // don't have any generic parameters, so we skip building another subst for the methods.
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
             .push(base_ty.clone())
             .push(index_ty.clone())
             .build();
@@ -354,10 +363,14 @@ impl SourceAnalyzer {
         let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
         let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
 
-        let op_fn = lang_names_for_bin_op(op)
+        let (op_trait, op_fn) = lang_names_for_bin_op(op)
             .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
-        let substs =
-            hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
+        // HACK: subst for `index()` coincides with that for `Index` because `index()` itself
+        // doesn't have any generic parameters, so we skip building another subst for `index()`.
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
+            .push(lhs.clone())
+            .push(rhs.clone())
+            .build();
 
         Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
     }
@@ -371,7 +384,13 @@ impl SourceAnalyzer {
 
         let op_fn =
             db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
-        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+        let op_trait = match op_fn.lookup(db.upcast()).container {
+            ItemContainerId::TraitId(id) => id,
+            _ => return None,
+        };
+        // HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself
+        // doesn't have any generic parameters, so we skip building another subst for `branch()`.
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
 
         Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
     }
@@ -799,9 +818,10 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         lang_trait: &Name,
         method_name: &Name,
-    ) -> Option {
-        db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
-            .method_by_name(method_name)
+    ) -> Option<(TraitId, FunctionId)> {
+        let trait_id = db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?;
+        let fn_id = db.trait_data(trait_id).method_by_name(method_name)?;
+        Some((trait_id, fn_id))
     }
 
     fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {

From 7556f74b1691276d12e4cf96eb2df8f74836cdc1 Mon Sep 17 00:00:00 2001
From: Ryo Yoshida 
Date: Sun, 2 Oct 2022 21:13:30 +0900
Subject: [PATCH 077/175] Remove hack

---
 crates/hir-ty/src/tests/regression.rs | 29 +++++++++------------------
 crates/hir-ty/src/utils.rs            | 25 -----------------------
 2 files changed, 10 insertions(+), 44 deletions(-)

diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index 47cc3341e707..16ba3dd6e3c9 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -1488,7 +1488,6 @@ fn regression_11688_4() {
 
 #[test]
 fn gat_crash_1() {
-    cov_mark::check!(ignore_gats);
     check_no_mismatches(
         r#"
 trait ATrait {}
@@ -1527,30 +1526,22 @@ unsafe impl Storage for InlineStorage {
 
 #[test]
 fn gat_crash_3() {
-    // FIXME: This test currently crashes rust analyzer in a debug build but not in a
-    // release build (i.e. for the user). With the assumption that tests will always be run
-    // in debug mode, we catch the unwind and expect that it panicked. See the
-    // [`crate::utils::generics`] function for more information.
-    cov_mark::check!(ignore_gats);
-    std::panic::catch_unwind(|| {
-        check_no_mismatches(
-            r#"
+    check_no_mismatches(
+        r#"
 trait Collection {
-    type Item;
-    type Member: Collection;
-    fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
+type Item;
+type Member: Collection;
+fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
 }
 struct ConstGen {
-    data: [T; N],
+data: [T; N],
 }
 impl Collection for ConstGen {
-    type Item = T;
-    type Member = ConstGen;
+type Item = T;
+type Member = ConstGen;
 }
-        "#,
-        );
-    })
-    .expect_err("must panic");
+    "#,
+    );
 }
 
 #[test]
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index adcf142bc35f..e54bcb421a22 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -173,31 +173,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
 
 pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
     let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
-    if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) {
-        let params = db.generic_params(def);
-        let parent_params = &parent_generics.as_ref().unwrap().params;
-        let has_consts =
-            params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
-        let parent_has_consts =
-            parent_params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
-        return if has_consts || parent_has_consts {
-            // XXX: treat const generic associated types as not existing to avoid crashes
-            // (#11769)
-            //
-            // Note: Also crashes when the parent has const generics (also even if the GAT
-            // doesn't use them), see `tests::regression::gat_crash_3` for an example.
-            // Avoids that by disabling GATs when the parent (i.e. `impl` block) has
-            // const generics (#12193).
-            //
-            // Chalk expects the inner associated type's parameters to come
-            // *before*, not after the trait's generics as we've always done it.
-            // Adapting to this requires a larger refactoring
-            cov_mark::hit!(ignore_gats);
-            Generics { def, params: Interned::new(Default::default()), parent_generics }
-        } else {
-            Generics { def, params, parent_generics }
-        };
-    }
     Generics { def, params: db.generic_params(def), parent_generics }
 }
 

From 31cd0aa823a379b6c0d0f66ba4172585d1780e8b Mon Sep 17 00:00:00 2001
From: Scott McMurray 
Date: Sun, 2 Oct 2022 12:26:58 -0700
Subject: [PATCH 078/175] Do the `calloc` optimization for `Option`

Inspired by .
---
 library/alloc/src/vec/is_zero.rs | 22 ++++++++++++++++++++++
 src/test/codegen/vec-calloc.rs   | 19 ++++++++++++++++++-
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs
index 2e025c8a4a5d..8e652d676dc0 100644
--- a/library/alloc/src/vec/is_zero.rs
+++ b/library/alloc/src/vec/is_zero.rs
@@ -160,3 +160,25 @@ unsafe impl IsZero for Saturating {
         self.0.is_zero()
     }
 }
+
+macro_rules! impl_for_optional_bool {
+    ($($t:ty,)+) => {$(
+        unsafe impl IsZero for $t {
+            #[inline]
+            fn is_zero(&self) -> bool {
+                // SAFETY: This is *not* a stable layout guarantee, but
+                // inside `core` we're allowed to rely on the current rustc
+                // behaviour that options of bools will be one byte with
+                // no padding, so long as they're nested less than 254 deep.
+                let raw: u8 = unsafe { core::mem::transmute(*self) };
+                raw == 0
+            }
+        }
+    )+};
+}
+impl_for_optional_bool! {
+    Option,
+    Option>,
+    Option>>,
+    // Could go further, but not worth the metadata overhead
+}
diff --git a/src/test/codegen/vec-calloc.rs b/src/test/codegen/vec-calloc.rs
index 435a4ab5187f..ae6e448f172f 100644
--- a/src/test/codegen/vec-calloc.rs
+++ b/src/test/codegen/vec-calloc.rs
@@ -1,4 +1,4 @@
-// compile-flags: -O
+// compile-flags: -O -Z merge-functions=disabled
 // only-x86_64
 // ignore-debug
 // min-llvm-version: 15.0
@@ -144,6 +144,23 @@ pub fn vec_non_zero_tuple(n: usize) -> Vec<(i16, u8, char)> {
     vec![(0, 0, 'A'); n]
 }
 
+// CHECK-LABEL: @vec_option_bool
+#[no_mangle]
+pub fn vec_option_bool(n: usize) -> Vec> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![Some(false); n]
+}
+
 // Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away.
 // CHECK: declare noalias ptr @__rust_alloc_zeroed(i64, i64 allocalign) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]]
 

From 59168035551959e089eaf4778acc84978accb9c4 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 3 Oct 2022 14:03:54 +0200
Subject: [PATCH 079/175] Prioritize restart messages in flycheck

---
 crates/flycheck/src/lib.rs | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index fdc03f4053a2..e8c63d410aa7 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -169,13 +169,17 @@ impl FlycheckActor {
     }
     fn next_event(&self, inbox: &Receiver) -> Option {
         let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
+        if let Ok(msg) = inbox.try_recv() {
+            // give restarts a preference so check outputs don't block a restart or stop
+            return Some(Event::Restart(msg));
+        }
         select! {
             recv(inbox) -> msg => msg.ok().map(Event::Restart),
             recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
         }
     }
     fn run(mut self, inbox: Receiver) {
-        while let Some(event) = self.next_event(&inbox) {
+        'event: while let Some(event) = self.next_event(&inbox) {
             match event {
                 Event::Restart(Restart::No) => {
                     self.cancel_check_process();
@@ -183,7 +187,12 @@ impl FlycheckActor {
                 Event::Restart(Restart::Yes) => {
                     // Cancel the previously spawned process
                     self.cancel_check_process();
-                    while let Ok(_) = inbox.recv_timeout(Duration::from_millis(50)) {}
+                    while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) {
+                        // restart chained with a stop, so just cancel
+                        if let Restart::No = restart {
+                            continue 'event;
+                        }
+                    }
 
                     let command = self.check_command();
                     tracing::debug!(?command, "will restart flycheck");

From 78b577c065f71c7ad30a70c8c65c7ff561fee852 Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Sun, 2 Oct 2022 18:30:55 +0200
Subject: [PATCH 080/175] scoped threads: pass closure through MaybeUninit to
 avoid invalid dangling references

---
 library/std/src/thread/mod.rs | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index ceea6986e333..809b835345f7 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -499,6 +499,31 @@ impl Builder {
         let output_capture = crate::io::set_output_capture(None);
         crate::io::set_output_capture(output_capture.clone());
 
+        // Pass `f` in `MaybeUninit` because actually that closure might *run longer than the lifetime of `F`*.
+        // See  for more details.
+        // To prevent leaks we use a wrapper that drops its contents.
+        #[repr(transparent)]
+        struct MaybeDangling(mem::MaybeUninit);
+        impl MaybeDangling {
+            fn new(x: T) -> Self {
+                MaybeDangling(mem::MaybeUninit::new(x))
+            }
+            fn into_inner(self) -> T {
+                // SAFETY: we are always initiailized.
+                let ret = unsafe { self.0.assume_init_read() };
+                // Make sure we don't drop.
+                mem::forget(self);
+                ret
+            }
+        }
+        impl Drop for MaybeDangling {
+            fn drop(&mut self) {
+                // SAFETY: we are always initiailized.
+                unsafe { self.0.assume_init_drop() };
+            }
+        }
+
+        let f = MaybeDangling::new(f);
         let main = move || {
             if let Some(name) = their_thread.cname() {
                 imp::Thread::set_name(name);
@@ -506,6 +531,8 @@ impl Builder {
 
             crate::io::set_output_capture(output_capture);
 
+            // SAFETY: we constructed `f` initialized.
+            let f = f.into_inner();
             // SAFETY: the stack guard passed is the one for the current thread.
             // This means the current thread's stack and the new thread's stack
             // are properly set and protected from each other.
@@ -518,6 +545,12 @@ impl Builder {
             // same `JoinInner` as this closure meaning the mutation will be
             // safe (not modify it and affect a value far away).
             unsafe { *their_packet.result.get() = Some(try_result) };
+            // Here `their_packet` gets dropped, and if this is the last `Arc` for that packet that
+            // will call `decrement_num_running_threads` and therefore signal that this thread is
+            // done.
+            drop(their_packet);
+            // Here, the lifetime `'a` and even `'scope` can end. `main` keeps running for a bit
+            // after that before returning itself.
         };
 
         if let Some(scope_data) = &my_packet.scope {

From e0a161b2e3a9345fd92fd3617e49648ee43ada86 Mon Sep 17 00:00:00 2001
From: Ryo Yoshida 
Date: Tue, 4 Oct 2022 00:07:34 +0900
Subject: [PATCH 081/175] fix: treat enum variants as generic item on their own

---
 crates/hir-ty/src/builder.rs |  4 +---
 crates/hir-ty/src/lower.rs   | 18 +++++++++++-------
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs
index c0052258ee03..9ae752556d89 100644
--- a/crates/hir-ty/src/builder.rs
+++ b/crates/hir-ty/src/builder.rs
@@ -192,9 +192,7 @@ impl TyBuilder<()> {
         parent_subst: Option,
     ) -> TyBuilder<()> {
         let generics = generics(db.upcast(), def.into());
-        // FIXME: this assertion should hold but some adjustment around
-        // `ValueTyDefId::EnumVariantId` is needed.
-        // assert!(generics.parent_generics().is_some() == parent_subst.is_some());
+        assert!(generics.parent_generics().is_some() == parent_subst.is_some());
         let params = generics
             .iter_self()
             .map(|(id, data)| match data {
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 0a4b1dfda105..a77dd910ff71 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -653,9 +653,13 @@ impl<'a> TyLoweringContext<'a> {
         infer_args: bool,
     ) -> Substitution {
         let last = path.segments().last().expect("path should have at least one segment");
-        let generic_def = resolved.to_generic_def_id();
-        let segment = match resolved {
-            ValueTyDefId::EnumVariantId(_) => {
+        let (segment, generic_def) = match resolved {
+            ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
+            ValueTyDefId::StructId(it) => (last, Some(it.into())),
+            ValueTyDefId::UnionId(it) => (last, Some(it.into())),
+            ValueTyDefId::ConstId(it) => (last, Some(it.into())),
+            ValueTyDefId::StaticId(_) => (last, None),
+            ValueTyDefId::EnumVariantId(var) => {
                 // the generic args for an enum variant may be either specified
                 // on the segment referring to the enum, or on the segment
                 // referring to the variant. So `Option::::None` and
@@ -663,12 +667,12 @@ impl<'a> TyLoweringContext<'a> {
                 // preferred). See also `def_ids_for_path_segments` in rustc.
                 let len = path.segments().len();
                 let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
-                match penultimate {
+                let segment = match penultimate {
                     Some(segment) if segment.args_and_bindings.is_some() => segment,
                     _ => last,
-                }
+                };
+                (segment, Some(var.parent.into()))
             }
-            _ => last,
         };
         self.substs_from_path_segment(segment, generic_def, infer_args, None)
     }
@@ -1660,7 +1664,7 @@ impl ValueTyDefId {
             Self::FunctionId(id) => Some(id.into()),
             Self::StructId(id) => Some(id.into()),
             Self::UnionId(id) => Some(id.into()),
-            Self::EnumVariantId(var) => Some(var.parent.into()),
+            Self::EnumVariantId(var) => Some(var.into()),
             Self::ConstId(id) => Some(id.into()),
             Self::StaticId(_) => None,
         }

From e0c9e28d1fab830d410872944a422ec692e51a68 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Tue, 4 Oct 2022 08:18:01 +0200
Subject: [PATCH 082/175] Revert "Add proc-macro dependency to rustc crates"

---
 crates/project-model/src/workspace.rs | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 8c3e8681d989..72ddf809288a 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -717,7 +717,6 @@ fn cargo_to_crate_graph(
                 load_proc_macro,
                 &mut pkg_to_lib_crate,
                 &public_deps,
-                libproc_macro,
                 cargo,
                 &pkg_crates,
                 build_scripts,
@@ -783,7 +782,6 @@ fn handle_rustc_crates(
     load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
     pkg_to_lib_crate: &mut FxHashMap,
     public_deps: &SysrootPublicDeps,
-    libproc_macro: Option,
     cargo: &CargoWorkspace,
     pkg_crates: &FxHashMap>,
     build_scripts: &WorkspaceBuildScripts,
@@ -845,19 +843,6 @@ fn handle_rustc_crates(
                         rustc_workspace[tgt].is_proc_macro,
                     );
                     pkg_to_lib_crate.insert(pkg, crate_id);
-
-                    // Even crates that don't set proc-macro = true are allowed to depend on proc_macro
-                    // (just none of the APIs work when called outside of a proc macro).
-                    if let Some(proc_macro) = libproc_macro {
-                        add_dep_with_prelude(
-                            crate_graph,
-                            crate_id,
-                            CrateName::new("proc_macro").unwrap(),
-                            proc_macro,
-                            cargo[tgt].is_proc_macro,
-                        );
-                    }
-
                     // Add dependencies on core / std / alloc for this crate
                     public_deps.add(crate_id, crate_graph);
                     rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);

From 9fb509e8844301ec0a2a2d8bfa42f47f352d8688 Mon Sep 17 00:00:00 2001
From: Rageking8 
Date: Tue, 4 Oct 2022 00:29:29 +0800
Subject: [PATCH 083/175] fix backtrace small typo

---
 library/std/src/backtrace.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index 5cf6ec817892..34b57c37635c 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -14,8 +14,8 @@
 //! Backtraces are attempted to be as accurate as possible, but no guarantees
 //! are provided about the exact accuracy of a backtrace. Instruction pointers,
 //! symbol names, filenames, line numbers, etc, may all be incorrect when
-//! reported. Accuracy is attempted on a best-effort basis, however, and bugs
-//! are always welcome to indicate areas of improvement!
+//! reported. Accuracy is attempted on a best-effort basis, however, any bug
+//! reports are always welcome to indicate areas of improvement!
 //!
 //! For most platforms a backtrace with a filename/line number requires that
 //! programs be compiled with debug information. Without debug information
@@ -39,7 +39,7 @@
 //! default. Its behavior is governed by two environment variables:
 //!
 //! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture`
-//!   will never capture a backtrace. Any other value this is set to will enable
+//!   will never capture a backtrace. Any other value set will enable
 //!   `Backtrace::capture`.
 //!
 //! * `RUST_BACKTRACE` - if `RUST_LIB_BACKTRACE` is not set, then this variable

From ded3326a64c2ef220f3cec9af863f738749d6ce2 Mon Sep 17 00:00:00 2001
From: Ryo Yoshida 
Date: Wed, 5 Oct 2022 00:20:01 +0900
Subject: [PATCH 084/175] fix: use `BoundVar`s from current generic scope

---
 crates/hir-ty/src/lower.rs            | 23 ++++++++++++++++++++---
 crates/hir-ty/src/tests/regression.rs | 13 +++++++++++++
 2 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index a77dd910ff71..223d705b157b 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -1158,11 +1158,28 @@ fn named_associated_type_shorthand_candidates(
     };
 
     match res {
-        TypeNs::SelfType(impl_id) => search(
+        TypeNs::SelfType(impl_id) => {
             // we're _in_ the impl -- the binders get added back later. Correct,
             // but it would be nice to make this more explicit
-            db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
-        ),
+            let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0;
+
+            let impl_id_as_generic_def: GenericDefId = impl_id.into();
+            if impl_id_as_generic_def != def {
+                // `trait_ref` contains `BoundVar`s bound by impl's `Binders`, but here we need
+                // `BoundVar`s from `def`'s point of view.
+                // FIXME: A `HirDatabase` query may be handy if this process is needed in more
+                // places. It'd be almost identical as `impl_trait_query` where `resolver` would be
+                // of `def` instead of `impl_id`.
+                let starting_idx = generics(db.upcast(), def).len_self();
+                let subst = TyBuilder::subst_for_def(db, impl_id, None)
+                    .fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
+                    .build();
+                let trait_ref = subst.apply(trait_ref, Interner);
+                search(trait_ref)
+            } else {
+                search(trait_ref)
+            }
+        }
         TypeNs::GenericParam(param_id) => {
             let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
             let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index 16ba3dd6e3c9..a155adcec6c3 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -1694,3 +1694,16 @@ fn foo(a: &dyn DoesNotExist) {
         "#,
     );
 }
+
+#[test]
+fn self_assoc_with_const_generics_crash() {
+    check_no_mismatches(
+        r#"
+trait Trait { type Item; }
+impl Trait for [T; N] {
+    type Item = ();
+    fn f(_: Self::Item) {}
+}
+        "#,
+    );
+}

From 1e8dc45fb502c39a81ddda532d35a4c3dbd6b4ad Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Wed, 5 Oct 2022 10:33:49 +1100
Subject: [PATCH 085/175] Rearrange `to_internal`.

`TokenTree::Punct` is handled outside the `match`. This commits moves it
inside the `match`, avoiding the need for the `return`s and making it
easier to read.
---
 .../rustc_expand/src/proc_macro_server.rs     | 81 +++++++++----------
 1 file changed, 40 insertions(+), 41 deletions(-)

diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index ff09a9fb87a7..a7b94a40f5c0 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -246,18 +246,49 @@ impl ToInternal for (TokenTree, &mut Rus
         use rustc_ast::token::*;
 
         let (tree, rustc) = self;
-        let (ch, joint, span) = match tree {
-            TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
+        match tree {
+            TokenTree::Punct(Punct { ch, joint, span }) => {
+                let kind = match ch {
+                    b'=' => Eq,
+                    b'<' => Lt,
+                    b'>' => Gt,
+                    b'!' => Not,
+                    b'~' => Tilde,
+                    b'+' => BinOp(Plus),
+                    b'-' => BinOp(Minus),
+                    b'*' => BinOp(Star),
+                    b'/' => BinOp(Slash),
+                    b'%' => BinOp(Percent),
+                    b'^' => BinOp(Caret),
+                    b'&' => BinOp(And),
+                    b'|' => BinOp(Or),
+                    b'@' => At,
+                    b'.' => Dot,
+                    b',' => Comma,
+                    b';' => Semi,
+                    b':' => Colon,
+                    b'#' => Pound,
+                    b'$' => Dollar,
+                    b'?' => Question,
+                    b'\'' => SingleQuote,
+                    _ => unreachable!(),
+                };
+                if joint {
+                    tokenstream::TokenStream::token_joint(kind, span)
+                } else {
+                    tokenstream::TokenStream::token_alone(kind, span)
+                }
+            }
             TokenTree::Group(Group { delimiter, stream, span: DelimSpan { open, close, .. } }) => {
-                return tokenstream::TokenStream::delimited(
+                tokenstream::TokenStream::delimited(
                     tokenstream::DelimSpan { open, close },
                     delimiter.to_internal(),
                     stream.unwrap_or_default(),
-                );
+                )
             }
             TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
                 rustc.sess().symbol_gallery.insert(sym, span);
-                return tokenstream::TokenStream::token_alone(Ident(sym, is_raw), span);
+                tokenstream::TokenStream::token_alone(Ident(sym, is_raw), span)
             }
             TokenTree::Literal(self::Literal {
                 kind: self::LitKind::Integer,
@@ -270,7 +301,7 @@ impl ToInternal for (TokenTree, &mut Rus
                 let integer = TokenKind::lit(token::Integer, symbol, suffix);
                 let a = tokenstream::TokenTree::token_alone(minus, span);
                 let b = tokenstream::TokenTree::token_alone(integer, span);
-                return [a, b].into_iter().collect();
+                [a, b].into_iter().collect()
             }
             TokenTree::Literal(self::Literal {
                 kind: self::LitKind::Float,
@@ -283,46 +314,14 @@ impl ToInternal for (TokenTree, &mut Rus
                 let float = TokenKind::lit(token::Float, symbol, suffix);
                 let a = tokenstream::TokenTree::token_alone(minus, span);
                 let b = tokenstream::TokenTree::token_alone(float, span);
-                return [a, b].into_iter().collect();
+                [a, b].into_iter().collect()
             }
             TokenTree::Literal(self::Literal { kind, symbol, suffix, span }) => {
-                return tokenstream::TokenStream::token_alone(
+                tokenstream::TokenStream::token_alone(
                     TokenKind::lit(kind.to_internal(), symbol, suffix),
                     span,
-                );
+                )
             }
-        };
-
-        let kind = match ch {
-            b'=' => Eq,
-            b'<' => Lt,
-            b'>' => Gt,
-            b'!' => Not,
-            b'~' => Tilde,
-            b'+' => BinOp(Plus),
-            b'-' => BinOp(Minus),
-            b'*' => BinOp(Star),
-            b'/' => BinOp(Slash),
-            b'%' => BinOp(Percent),
-            b'^' => BinOp(Caret),
-            b'&' => BinOp(And),
-            b'|' => BinOp(Or),
-            b'@' => At,
-            b'.' => Dot,
-            b',' => Comma,
-            b';' => Semi,
-            b':' => Colon,
-            b'#' => Pound,
-            b'$' => Dollar,
-            b'?' => Question,
-            b'\'' => SingleQuote,
-            _ => unreachable!(),
-        };
-
-        if joint {
-            tokenstream::TokenStream::token_joint(kind, span)
-        } else {
-            tokenstream::TokenStream::token_alone(kind, span)
         }
     }
 }

From 1e848a564b12e3e1dff2da48e1762c983b9bda3e Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Wed, 5 Oct 2022 10:38:15 +1100
Subject: [PATCH 086/175] Remove `TokenStreamBuilder`.

`TokenStreamBuilder` exists to concatenate multiple `TokenStream`s
together. This commit removes it, and moves the concatenation
functionality directly into `TokenStream`, via two new methods
`push_tree` and `push_stream`. This makes things both simpler and
faster.

`push_tree` is particularly important. `TokenStreamBuilder` only had a
single `push` method, which pushed a stream. But in practice most of the
time we push a single token tree rather than a stream, and `push_tree`
avoids the need to build a token stream with a single entry (which
requires two allocations, one for the `Lrc` and one for the `Vec`).

The main `push_tree` use arises from a change to one of the `ToInternal`
impls in `proc_macro_server.rs`. It now returns a `SmallVec` instead of
a `TokenStream`. This return value is then iterated over by
`concat_trees`, which does `push_tree` on each element. Furthermore, the
use of `SmallVec` avoids more allocations, because there is always only
one or two token trees.

Note: the removed `TokenStreamBuilder::push` method had some code to
deal with a quadratic blowup case from #57735. This commit removes the
code. I tried and failed to reproduce the blowup from that PR, before
and after this change. Various other changes have happened to
`TokenStreamBuilder` in the meantime, so I suspect the original problem
is no longer relevant, though I don't have proof of this. Generally
speaking, repeatedly extending a `Vec` without pre-determining its
capacity is *not* quadratic. It's also incredibly common, within rustc
and many other Rust programs, so if there were performance problems
there you'd think it would show up in other places, too.
---
 compiler/rustc_ast/src/tokenstream.rs         | 107 +++++++-----------
 .../rustc_expand/src/proc_macro_server.rs     |  67 +++++------
 .../rustc_expand/src/tokenstream/tests.rs     |  18 ++-
 3 files changed, 82 insertions(+), 110 deletions(-)

diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 4d2049cbc41e..1d3c4fcca0a4 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -245,12 +245,12 @@ impl AttrTokenStream {
                                 // properly implemented - we always synthesize fake tokens,
                                 // so we never reach this code.
 
-                                let mut builder = TokenStreamBuilder::new();
+                                let mut stream = TokenStream::default();
                                 for inner_attr in inner_attrs {
-                                    builder.push(inner_attr.tokens());
+                                    stream.push_stream(inner_attr.tokens());
                                 }
-                                builder.push(delim_tokens.clone());
-                                *tree = TokenTree::Delimited(*span, *delim, builder.build());
+                                stream.push_stream(delim_tokens.clone());
+                                *tree = TokenTree::Delimited(*span, *delim, stream);
                                 found = true;
                                 break;
                             }
@@ -505,76 +505,49 @@ impl TokenStream {
 
         self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
     }
-}
 
-// 99.5%+ of the time we have 1 or 2 elements in this vector.
-#[derive(Clone)]
-pub struct TokenStreamBuilder(SmallVec<[TokenStream; 2]>);
-
-impl TokenStreamBuilder {
-    pub fn new() -> TokenStreamBuilder {
-        TokenStreamBuilder(SmallVec::new())
+    // If `vec` is not empty, try to glue `tt` onto its last token. The return
+    // value indicates if gluing took place.
+    fn try_glue_to_last(vec: &mut Vec, tt: &TokenTree) -> bool {
+        if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = vec.last()
+            && let TokenTree::Token(tok, spacing) = tt
+            && let Some(glued_tok) = last_tok.glue(&tok)
+        {
+            // ...then overwrite the last token tree in `vec` with the
+            // glued token, and skip the first token tree from `stream`.
+            *vec.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing);
+            true
+        } else {
+            false
+        }
     }
 
-    pub fn push(&mut self, stream: TokenStream) {
-        self.0.push(stream);
+    // Push `tt` onto the end of the stream, possibly gluing it to the last
+    // token. Uses `make_mut` to maximize efficiency.
+    pub fn push_tree(&mut self, tt: TokenTree) {
+        let vec_mut = Lrc::make_mut(&mut self.0);
+
+        if Self::try_glue_to_last(vec_mut, &tt) {
+            // nothing else to do
+        } else {
+            vec_mut.push(tt);
+        }
     }
 
-    pub fn build(self) -> TokenStream {
-        let mut streams = self.0;
-        match streams.len() {
-            0 => TokenStream::default(),
-            1 => streams.pop().unwrap(),
-            _ => {
-                // We will extend the first stream in `streams` with the
-                // elements from the subsequent streams. This requires using
-                // `make_mut()` on the first stream, and in practice this
-                // doesn't cause cloning 99.9% of the time.
-                //
-                // One very common use case is when `streams` has two elements,
-                // where the first stream has any number of elements within
-                // (often 1, but sometimes many more) and the second stream has
-                // a single element within.
+    // Push `stream` onto the end of the stream, possibly gluing the first
+    // token tree to the last token. (No other token trees will be glued.)
+    // Uses `make_mut` to maximize efficiency.
+    pub fn push_stream(&mut self, stream: TokenStream) {
+        let vec_mut = Lrc::make_mut(&mut self.0);
 
-                // Determine how much the first stream will be extended.
-                // Needed to avoid quadratic blow up from on-the-fly
-                // reallocations (#57735).
-                let num_appends = streams.iter().skip(1).map(|ts| ts.len()).sum();
+        let stream_iter = stream.0.iter().cloned();
 
-                // Get the first stream, which will become the result stream.
-                // If it's `None`, create an empty stream.
-                let mut iter = streams.into_iter();
-                let mut res_stream_lrc = iter.next().unwrap().0;
-
-                // Append the subsequent elements to the result stream, after
-                // reserving space for them.
-                let res_vec_mut = Lrc::make_mut(&mut res_stream_lrc);
-                res_vec_mut.reserve(num_appends);
-                for stream in iter {
-                    let stream_iter = stream.0.iter().cloned();
-
-                    // If (a) `res_mut_vec` is not empty and the last tree
-                    // within it is a token tree marked with `Joint`, and (b)
-                    // `stream` is not empty and the first tree within it is a
-                    // token tree, and (c) the two tokens can be glued
-                    // together...
-                    if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = res_vec_mut.last()
-                        && let Some(TokenTree::Token(tok, spacing)) = stream.0.first()
-                        && let Some(glued_tok) = last_tok.glue(&tok)
-                    {
-                        // ...then overwrite the last token tree in
-                        // `res_vec_mut` with the glued token, and skip the
-                        // first token tree from `stream`.
-                        *res_vec_mut.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing);
-                        res_vec_mut.extend(stream_iter.skip(1));
-                    } else {
-                        // Append all of `stream`.
-                        res_vec_mut.extend(stream_iter);
-                    }
-                }
-
-                TokenStream(res_stream_lrc)
-            }
+        if let Some(first) = stream.0.first() && Self::try_glue_to_last(vec_mut, first) {
+            // Now skip the first token tree from `stream`.
+            vec_mut.extend(stream_iter.skip(1));
+        } else {
+            // Append all of `stream`.
+            vec_mut.extend(stream_iter);
         }
     }
 }
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index a7b94a40f5c0..24762b8346b1 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -1,5 +1,8 @@
 use crate::base::ExtCtxt;
-
+use pm::bridge::{
+    server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
+};
+use pm::{Delimiter, Level, LineColumn};
 use rustc_ast as ast;
 use rustc_ast::token;
 use rustc_ast::tokenstream::{self, Spacing::*, TokenStream};
@@ -13,11 +16,7 @@ use rustc_session::parse::ParseSess;
 use rustc_span::def_id::CrateNum;
 use rustc_span::symbol::{self, sym, Symbol};
 use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
-
-use pm::bridge::{
-    server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
-};
-use pm::{Delimiter, Level, LineColumn};
+use smallvec::{smallvec, SmallVec};
 use std::ops::Bound;
 
 trait FromInternal {
@@ -241,8 +240,11 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec for (TokenTree, &mut Rustc<'_, '_>) {
-    fn to_internal(self) -> TokenStream {
+// We use a `SmallVec` because the output size is always one or two `TokenTree`s.
+impl ToInternal>
+    for (TokenTree, &mut Rustc<'_, '_>)
+{
+    fn to_internal(self) -> SmallVec<[tokenstream::TokenTree; 2]> {
         use rustc_ast::token::*;
 
         let (tree, rustc) = self;
@@ -273,22 +275,22 @@ impl ToInternal for (TokenTree, &mut Rus
                     b'\'' => SingleQuote,
                     _ => unreachable!(),
                 };
-                if joint {
-                    tokenstream::TokenStream::token_joint(kind, span)
+                smallvec![if joint {
+                    tokenstream::TokenTree::token_joint(kind, span)
                 } else {
-                    tokenstream::TokenStream::token_alone(kind, span)
-                }
+                    tokenstream::TokenTree::token_alone(kind, span)
+                }]
             }
             TokenTree::Group(Group { delimiter, stream, span: DelimSpan { open, close, .. } }) => {
-                tokenstream::TokenStream::delimited(
+                smallvec![tokenstream::TokenTree::Delimited(
                     tokenstream::DelimSpan { open, close },
                     delimiter.to_internal(),
                     stream.unwrap_or_default(),
-                )
+                )]
             }
             TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
                 rustc.sess().symbol_gallery.insert(sym, span);
-                tokenstream::TokenStream::token_alone(Ident(sym, is_raw), span)
+                smallvec![tokenstream::TokenTree::token_alone(Ident(sym, is_raw), span)]
             }
             TokenTree::Literal(self::Literal {
                 kind: self::LitKind::Integer,
@@ -301,7 +303,7 @@ impl ToInternal for (TokenTree, &mut Rus
                 let integer = TokenKind::lit(token::Integer, symbol, suffix);
                 let a = tokenstream::TokenTree::token_alone(minus, span);
                 let b = tokenstream::TokenTree::token_alone(integer, span);
-                [a, b].into_iter().collect()
+                smallvec![a, b]
             }
             TokenTree::Literal(self::Literal {
                 kind: self::LitKind::Float,
@@ -314,13 +316,13 @@ impl ToInternal for (TokenTree, &mut Rus
                 let float = TokenKind::lit(token::Float, symbol, suffix);
                 let a = tokenstream::TokenTree::token_alone(minus, span);
                 let b = tokenstream::TokenTree::token_alone(float, span);
-                [a, b].into_iter().collect()
+                smallvec![a, b]
             }
             TokenTree::Literal(self::Literal { kind, symbol, suffix, span }) => {
-                tokenstream::TokenStream::token_alone(
+                smallvec![tokenstream::TokenTree::token_alone(
                     TokenKind::lit(kind.to_internal(), symbol, suffix),
                     span,
-                )
+                )]
             }
         }
     }
@@ -536,7 +538,7 @@ impl server::TokenStream for Rustc<'_, '_> {
         &mut self,
         tree: TokenTree,
     ) -> Self::TokenStream {
-        (tree, &mut *self).to_internal()
+        Self::TokenStream::new((tree, &mut *self).to_internal().into_iter().collect::>())
     }
 
     fn concat_trees(
@@ -544,14 +546,14 @@ impl server::TokenStream for Rustc<'_, '_> {
         base: Option,
         trees: Vec>,
     ) -> Self::TokenStream {
-        let mut builder = tokenstream::TokenStreamBuilder::new();
-        if let Some(base) = base {
-            builder.push(base);
-        }
+        let mut stream =
+            if let Some(base) = base { base } else { tokenstream::TokenStream::default() };
         for tree in trees {
-            builder.push((tree, &mut *self).to_internal());
+            for tt in (tree, &mut *self).to_internal() {
+                stream.push_tree(tt);
+            }
         }
-        builder.build()
+        stream
     }
 
     fn concat_streams(
@@ -559,14 +561,12 @@ impl server::TokenStream for Rustc<'_, '_> {
         base: Option,
         streams: Vec,
     ) -> Self::TokenStream {
-        let mut builder = tokenstream::TokenStreamBuilder::new();
-        if let Some(base) = base {
-            builder.push(base);
+        let mut stream =
+            if let Some(base) = base { base } else { tokenstream::TokenStream::default() };
+        for s in streams {
+            stream.push_stream(s);
         }
-        for stream in streams {
-            builder.push(stream);
-        }
-        builder.build()
+        stream
     }
 
     fn into_trees(
@@ -692,6 +692,7 @@ impl server::Span for Rustc<'_, '_> {
     fn source_text(&mut self, span: Self::Span) -> Option {
         self.sess().source_map().span_to_snippet(span).ok()
     }
+
     /// Saves the provided span into the metadata of
     /// *the crate we are currently compiling*, which must
     /// be a proc-macro crate. This id can be passed to
diff --git a/compiler/rustc_expand/src/tokenstream/tests.rs b/compiler/rustc_expand/src/tokenstream/tests.rs
index eed69681011e..91c4dd732e3a 100644
--- a/compiler/rustc_expand/src/tokenstream/tests.rs
+++ b/compiler/rustc_expand/src/tokenstream/tests.rs
@@ -1,7 +1,7 @@
 use crate::tests::string_to_stream;
 
 use rustc_ast::token;
-use rustc_ast::tokenstream::{TokenStream, TokenStreamBuilder};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_span::create_default_session_globals_then;
 use rustc_span::{BytePos, Span, Symbol};
 
@@ -19,10 +19,9 @@ fn test_concat() {
         let test_res = string_to_ts("foo::bar::baz");
         let test_fst = string_to_ts("foo::bar");
         let test_snd = string_to_ts("::baz");
-        let mut builder = TokenStreamBuilder::new();
-        builder.push(test_fst);
-        builder.push(test_snd);
-        let eq_res = builder.build();
+        let mut eq_res = TokenStream::default();
+        eq_res.push_stream(test_fst);
+        eq_res.push_stream(test_snd);
         assert_eq!(test_res.trees().count(), 5);
         assert_eq!(eq_res.trees().count(), 5);
         assert_eq!(test_res.eq_unspanned(&eq_res), true);
@@ -99,11 +98,10 @@ fn test_is_empty() {
 #[test]
 fn test_dotdotdot() {
     create_default_session_globals_then(|| {
-        let mut builder = TokenStreamBuilder::new();
-        builder.push(TokenStream::token_joint(token::Dot, sp(0, 1)));
-        builder.push(TokenStream::token_joint(token::Dot, sp(1, 2)));
-        builder.push(TokenStream::token_alone(token::Dot, sp(2, 3)));
-        let stream = builder.build();
+        let mut stream = TokenStream::default();
+        stream.push_tree(TokenTree::token_joint(token::Dot, sp(0, 1)));
+        stream.push_tree(TokenTree::token_joint(token::Dot, sp(1, 2)));
+        stream.push_tree(TokenTree::token_alone(token::Dot, sp(2, 3)));
         assert!(stream.eq_unspanned(&string_to_ts("...")));
         assert_eq!(stream.trees().count(), 1);
     })

From 8bda13367e4987937ddc2ba9bbe01b5f7a4cce3e Mon Sep 17 00:00:00 2001
From: Gary Guo 
Date: Wed, 5 Oct 2022 02:29:56 +0100
Subject: [PATCH 087/175] Interpret EH actions properly

The EH actions stored in the LSDA follows the format of GCC except table
(even for LLVM-generated code). An missing action in the table is the
encoding for `Terminate`, see [1].

The currently code interprets it as `None`, as a workaround for #35011,
an issue that seems to occur in LLVM 3.7 and not after 3.9. These are
very old versions of LLVM and we don't support them anymore, so remove
this workaround and interpret them properly.

Note that LLVM currently does not emit any `Terminate` actions, but GCC
does. Although GCC backend currently doesn't do unwinding, removing it
preemptively would prevent future developers from wasting time to figure
out what's wrong.

[1]: https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/eh_personality.cc#L522-L526
---
 library/std/src/personality/dwarf/eh.rs | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/library/std/src/personality/dwarf/eh.rs b/library/std/src/personality/dwarf/eh.rs
index 8799137b78f9..27b50c13b77c 100644
--- a/library/std/src/personality/dwarf/eh.rs
+++ b/library/std/src/personality/dwarf/eh.rs
@@ -98,9 +98,8 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
                 }
             }
         }
-        // Ip is not present in the table.  This should not happen... but it does: issue #35011.
-        // So rather than returning EHAction::Terminate, we do this.
-        Ok(EHAction::None)
+        // Ip is not present in the table. This indicates a nounwind call.
+        Ok(EHAction::Terminate)
     } else {
         // SjLj version:
         // The "IP" is an index into the call-site table, with two exceptions:

From ed6f4813bb5838e472e1e59d0454b75f777d1b9d Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Wed, 5 Oct 2022 13:10:28 +1100
Subject: [PATCH 088/175] A tiny fix for `define_client_side`.

The return type can only appear once.
---
 library/proc_macro/src/bridge/client.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs
index 4461b21802ad..506b2a773cc4 100644
--- a/library/proc_macro/src/bridge/client.rs
+++ b/library/proc_macro/src/bridge/client.rs
@@ -223,10 +223,10 @@ pub(crate) use super::symbol::Symbol;
 
 macro_rules! define_client_side {
     ($($name:ident {
-        $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
+        $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
     }),* $(,)?) => {
         $(impl $name {
-            $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* {
+            $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? {
                 Bridge::with(|bridge| {
                     let mut buf = bridge.cached_buffer.take();
 

From 8862fe6ff25c209ec4c027f0c253005ec3a9e3e0 Mon Sep 17 00:00:00 2001
From: Wildbook 
Date: Wed, 5 Oct 2022 17:45:32 +0200
Subject: [PATCH 089/175] Fix assertion failure in type inference (#13352)

---
 crates/hir/src/lib.rs               |  4 ++++
 crates/ide/src/highlight_related.rs | 16 ++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index e08dd8dadebc..f5324208c9a4 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2807,6 +2807,10 @@ impl Type {
                     let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
                     Some(subst)
                 }
+                ItemContainerId::ImplId(id) => {
+                    let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
+                    Some(subst)
+                }
                 _ => None,
             },
             _ => None,
diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs
index 1bdd626f1e83..540a115832d3 100644
--- a/crates/ide/src/highlight_related.rs
+++ b/crates/ide/src/highlight_related.rs
@@ -1373,6 +1373,22 @@ fn main() {
     ().func$0();
      //^^^^
 }
+"#,
+        );
+    }
+
+    #[test]
+    fn test_assoc_type_highlighting() {
+        check(
+            r#"
+trait Trait {
+    type Output;
+      // ^^^^^^
+}
+impl Trait for () {
+    type Output$0 = ();
+      // ^^^^^^
+}
 "#,
         );
     }

From 5f3a4240c5ea5a5943eca5a467e3be04159e89a4 Mon Sep 17 00:00:00 2001
From: Peter Collingbourne 
Date: Wed, 5 Oct 2022 21:46:44 -0700
Subject: [PATCH 090/175] Fix the sanitizer_scs_attr_check.rs test

The test is failing when targeting aarch64 Android. The intent appears
to have been to look for a function attributes comment (or the absence
of one) on the line preceding the function declaration. But this isn't
quite possible with FileCheck and the test as written was looking for a
line with `no_scs` after a line with `scs`, which doesn't appear in the
output. Instead, match on the function attributes comment on the line
following the demangled function name comment.
---
 src/test/codegen/sanitizer_scs_attr_check.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/test/codegen/sanitizer_scs_attr_check.rs b/src/test/codegen/sanitizer_scs_attr_check.rs
index 0b53db3b767c..a885d911717f 100644
--- a/src/test/codegen/sanitizer_scs_attr_check.rs
+++ b/src/test/codegen/sanitizer_scs_attr_check.rs
@@ -7,11 +7,11 @@
 #![crate_type = "lib"]
 #![feature(no_sanitize)]
 
-// CHECK: ; Function Attrs:{{.*}}shadowcallstack
-// CHECK-NEXT: scs
+// CHECK: ; sanitizer_scs_attr_check::scs
+// CHECK-NEXT: ; Function Attrs:{{.*}}shadowcallstack
 pub fn scs() {}
 
+// CHECK: ; sanitizer_scs_attr_check::no_scs
 // CHECK-NOT: ; Function Attrs:{{.*}}shadowcallstack
-// CHECK-NEXT: no_scs
 #[no_sanitize(shadow_call_stack)]
 pub fn no_scs() {}

From a57ef6b0b17b1cbeac14789908b62df6ffef4079 Mon Sep 17 00:00:00 2001
From: Maybe Waffle 
Date: Thu, 6 Oct 2022 06:10:28 +0000
Subject: [PATCH 091/175] Fix go-to-def for shadowed `include*!`

---
 crates/ide/src/goto_definition.rs | 33 ++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 36a648fe4a8e..7d8ef7ab9dc2 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -95,6 +95,14 @@ fn try_lookup_include_path(
     if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
         return None;
     }
+
+    // Ignore non-built-in macros to account for shadowing
+    if let Some(it) = sema.resolve_macro_call(¯o_call) {
+        if !matches!(it.kind(sema.db), hir::MacroKind::BuiltIn) {
+            return None;
+        }
+    }
+
     let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
     let size = sema.db.file_text(file_id).len().try_into().ok()?;
     Some(NavigationTarget {
@@ -156,9 +164,6 @@ mod tests {
     fn check(ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
         let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
-        if navs.is_empty() {
-            panic!("unresolved reference")
-        }
 
         let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
         let navs = navs
@@ -1348,6 +1353,10 @@ fn f(e: Enum) {
         check(
             r#"
 //- /main.rs
+
+#[rustc_builtin_macro]
+macro_rules! include_str {}
+
 fn main() {
     let str = include_str!("foo.txt$0");
 }
@@ -1357,6 +1366,24 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn goto_shadow_include() {
+        check(
+            r#"
+//- /main.rs
+macro_rules! include {
+    ("included.rs") => {}
+}
+
+include!("included.rs$0");
+
+//- /included.rs
+// empty
+"#,
+        );
+    }
+
     #[cfg(test)]
     mod goto_impl_of_trait_fn {
         use super::check;

From 8e70c82f572be26a9d838e52f451b270160ffdba Mon Sep 17 00:00:00 2001
From: Florian Bartels 
Date: Thu, 29 Sep 2022 11:04:25 +0200
Subject: [PATCH 092/175] Prevent UB in child process after calling libc::fork

After calling libc::fork, the child process tried to access
a TLS variable when processing a panic. This caused
a memory allocation which is UB in the child.
To prevent this from happening, the panic handler will
not access the TLS variable in case `panic::always_abort`
was called before.
---
 library/std/src/panicking.rs | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 4b07b393a2f5..cd4d41fe1237 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -308,6 +308,14 @@ pub mod panic_count {
     // Additionally, the top bit of GLOBAL_PANIC_COUNT (GLOBAL_ALWAYS_ABORT_FLAG)
     // records whether panic::always_abort() has been called.  This can only be
     // set, never cleared.
+    // panic::always_abort() is usually called to prevent memory allocations done by
+    // the panic handling in the child created by `libc::fork`. 
+    // Memory allocations performed in  a child created with `libc::fork` are undefined
+    // behavior in most operating systems.
+    // Accessing LOCAL_PANIC_COUNT in a child created by `libc::fork` would lead to a memory 
+    // allocation. Only GLOBAL_PANIC_COUNT can be accessed in this situation. This is
+    // sufficient because a child process will always have exactly one thread only.
+    // See also #85261 for details.
     //
     // This could be viewed as a struct containing a single bit and an n-1-bit
     // value, but if we wrote it like that it would be more than a single word,
@@ -318,15 +326,26 @@ pub mod panic_count {
     // panicking thread consumes at least 2 bytes of address space.
     static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);
 
+    // Return the state of the ALWAYS_ABORT_FLAG and number of panics.
+    //
+    // If ALWAYS_ABORT_FLAG is not set, the number is determined on a per-thread
+    // base (stored in LOCAL_PANIC_COUNT), i.e. it is the amount of recursive calls
+    // of the calling thread.
+    // If ALWAYS_ABORT_FLAG is set, the number equals the *global* number of panic
+    // calls. See above why LOCAL_PANIC_COUNT is not used.
     pub fn increase() -> (bool, usize) {
-        (
-            GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed) & ALWAYS_ABORT_FLAG != 0,
+        let global_count = GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed);
+        let must_abort = global_count & ALWAYS_ABORT_FLAG != 0;
+        let panics = if must_abort {
+            global_count & !ALWAYS_ABORT_FLAG
+        } else {
             LOCAL_PANIC_COUNT.with(|c| {
                 let next = c.get() + 1;
                 c.set(next);
                 next
-            }),
-        )
+            })
+        };
+        (must_abort, panics)
     }
 
     pub fn decrease() {

From 8b821ccc51fef460a97b5dd299421c91730537f5 Mon Sep 17 00:00:00 2001
From: Florian Bartels 
Date: Thu, 29 Sep 2022 11:18:23 +0200
Subject: [PATCH 093/175] Enable test on Android

---
 src/test/ui/process/process-panic-after-fork.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/test/ui/process/process-panic-after-fork.rs b/src/test/ui/process/process-panic-after-fork.rs
index d0a938c03e80..9b0f9f82f8f6 100644
--- a/src/test/ui/process/process-panic-after-fork.rs
+++ b/src/test/ui/process/process-panic-after-fork.rs
@@ -5,7 +5,6 @@
 // ignore-sgx no libc
 // ignore-emscripten no processes
 // ignore-sgx no processes
-// ignore-android: FIXME(#85261)
 // ignore-fuchsia no fork
 
 #![feature(rustc_private)]

From 56503460c88844a61fbf47cc6702e206355b0a2b Mon Sep 17 00:00:00 2001
From: Florian Bartels 
Date: Thu, 6 Oct 2022 08:43:27 +0200
Subject: [PATCH 094/175] Fix test for Android

---
 .../ui/process/process-panic-after-fork.rs    | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/src/test/ui/process/process-panic-after-fork.rs b/src/test/ui/process/process-panic-after-fork.rs
index 9b0f9f82f8f6..43c23b49737d 100644
--- a/src/test/ui/process/process-panic-after-fork.rs
+++ b/src/test/ui/process/process-panic-after-fork.rs
@@ -78,7 +78,29 @@ unsafe impl GlobalAlloc for PidChecking {
 fn expect_aborted(status: ExitStatus) {
     dbg!(status);
     let signal = status.signal().expect("expected child process to die of signal");
+
+    #[cfg(not(target_os = "android"))]
     assert!(signal == libc::SIGABRT || signal == libc::SIGILL || signal == libc::SIGTRAP);
+
+    #[cfg(target_os = "android")]
+    {
+        // Android signals an abort() call with SIGSEGV at address 0xdeadbaad
+        // See e.g. https://groups.google.com/g/android-ndk/c/laW1CJc7Icc
+        assert!(signal == libc::SIGSEGV);
+        // Check if the crash occured at addres deadbaad to ensure it is not some undefined
+        // behavior but actually an abort
+        let tombstone = (0..100)
+            .map(|n| format!("/data/tombstones/tombstone_{n:02}"))
+            .filter(|f| std::path::Path::new(&f).exists())
+            .last()
+            .expect("no tombstone found");
+        let tombstone =
+            std::fs::read_to_string(&tombstone).expect("Cannot read tombstone file");
+        // If the next assert fails sporadically we might have an issue with parallel crashing apps
+        assert!(tombstone
+            .contains(&std::env::current_exe().unwrap().into_os_string().into_string().unwrap()));
+        assert!(tombstone.contains("signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad"));
+    }
 }
 
 fn main() {

From 9a97cc8ca5f863cacf39c9aaa4ca6ad872bc8172 Mon Sep 17 00:00:00 2001
From: Florian Bartels 
Date: Thu, 6 Oct 2022 08:52:36 +0200
Subject: [PATCH 095/175] Fix whitespace

---
 library/std/src/panicking.rs                    | 4 ++--
 src/test/ui/process/process-panic-after-fork.rs | 4 +++-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index cd4d41fe1237..d4976a469cc1 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -309,10 +309,10 @@ pub mod panic_count {
     // records whether panic::always_abort() has been called.  This can only be
     // set, never cleared.
     // panic::always_abort() is usually called to prevent memory allocations done by
-    // the panic handling in the child created by `libc::fork`. 
+    // the panic handling in the child created by `libc::fork`.
     // Memory allocations performed in  a child created with `libc::fork` are undefined
     // behavior in most operating systems.
-    // Accessing LOCAL_PANIC_COUNT in a child created by `libc::fork` would lead to a memory 
+    // Accessing LOCAL_PANIC_COUNT in a child created by `libc::fork` would lead to a memory
     // allocation. Only GLOBAL_PANIC_COUNT can be accessed in this situation. This is
     // sufficient because a child process will always have exactly one thread only.
     // See also #85261 for details.
diff --git a/src/test/ui/process/process-panic-after-fork.rs b/src/test/ui/process/process-panic-after-fork.rs
index 43c23b49737d..b08aa895dec5 100644
--- a/src/test/ui/process/process-panic-after-fork.rs
+++ b/src/test/ui/process/process-panic-after-fork.rs
@@ -99,7 +99,9 @@ fn expect_aborted(status: ExitStatus) {
         // If the next assert fails sporadically we might have an issue with parallel crashing apps
         assert!(tombstone
             .contains(&std::env::current_exe().unwrap().into_os_string().into_string().unwrap()));
-        assert!(tombstone.contains("signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad"));
+        assert!(tombstone.contains(
+            "signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad"
+        ));
     }
 }
 

From 53caa9fafbf199c8dd1b312203045a618e1c38dc Mon Sep 17 00:00:00 2001
From: Florian Bartels 
Date: Thu, 6 Oct 2022 15:11:21 +0200
Subject: [PATCH 096/175] Ensure crash is caused by libc::abort

---
 .../ui/process/process-panic-after-fork.rs    | 26 ++++++++++++++++---
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/src/test/ui/process/process-panic-after-fork.rs b/src/test/ui/process/process-panic-after-fork.rs
index b08aa895dec5..ed4c2b5bd392 100644
--- a/src/test/ui/process/process-panic-after-fork.rs
+++ b/src/test/ui/process/process-panic-after-fork.rs
@@ -87,21 +87,39 @@ fn expect_aborted(status: ExitStatus) {
         // Android signals an abort() call with SIGSEGV at address 0xdeadbaad
         // See e.g. https://groups.google.com/g/android-ndk/c/laW1CJc7Icc
         assert!(signal == libc::SIGSEGV);
-        // Check if the crash occured at addres deadbaad to ensure it is not some undefined
-        // behavior but actually an abort
-        let tombstone = (0..100)
+
+        // Additional checks performed:
+        // 1. Crash is from same executable (path) as we are (must be because of fork):
+        //    This ensures that we look into the correct tombstone.
+        // 2. Cause of crash is a SIGSEGV with address 0xdeadbaad.
+        // 3. libc::abort call is in one of top two functions on callstack.
+        // The last two steps distinguish between a normal SIGSEGV and one caused
+        // by libc::abort.
+
+        let tombstone_name = (0..100)
             .map(|n| format!("/data/tombstones/tombstone_{n:02}"))
             .filter(|f| std::path::Path::new(&f).exists())
             .last()
             .expect("no tombstone found");
+
         let tombstone =
-            std::fs::read_to_string(&tombstone).expect("Cannot read tombstone file");
+            std::fs::read_to_string(&tombstone_name).expect("Cannot read tombstone file");
+        println!("Content of {tombstone_name}:\n{tombstone}");
+
         // If the next assert fails sporadically we might have an issue with parallel crashing apps
         assert!(tombstone
             .contains(&std::env::current_exe().unwrap().into_os_string().into_string().unwrap()));
         assert!(tombstone.contains(
             "signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad"
         ));
+        let abort_on_top = tombstone
+            .lines()
+            .skip_while(|l| !l.contains("backtrace:"))
+            .skip(1)
+            .take_while(|l| l.starts_with("    #"))
+            .take(2)
+            .any(|f| f.contains("/system/lib/libc.so (abort"));
+        assert!(abort_on_top);
     }
 }
 

From 9a1c1c7941e111b67e89cc6e0738455d6edbbd5e Mon Sep 17 00:00:00 2001
From: Peter Collingbourne 
Date: Wed, 5 Oct 2022 19:07:12 -0700
Subject: [PATCH 097/175] tools/remote-test-{server,client}: Use
 /data/local/tmp on Android

The /data/tmp directory does not exist, at least not on recent versions
of Android, which currently leads to test failures on that platform. I
checked a virtual device running AOSP master and a Nexus 5 running
Android Marshmallow and on both devices the /data/tmp directory does
not exist and /data/local/tmp does, so let's switch to /data/local/tmp.
---
 src/bootstrap/test.rs                    | 2 +-
 src/tools/remote-test-client/src/main.rs | 4 ++--
 src/tools/remote-test-server/src/main.rs | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 01f4cacd771f..2271c18eb1d9 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -23,7 +23,7 @@ use crate::toolstate::ToolState;
 use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t};
 use crate::{envify, CLang, DocTests, GitRepo, Mode};
 
-const ADB_TEST_DIR: &str = "/data/tmp/work";
+const ADB_TEST_DIR: &str = "/data/local/tmp/work";
 
 /// The two modes of the test runner; tests or benchmarks.
 #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)]
diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs
index 2d99f2cb8e2c..bcda930d093c 100644
--- a/src/tools/remote-test-client/src/main.rs
+++ b/src/tools/remote-test-client/src/main.rs
@@ -93,7 +93,7 @@ fn start_android_emulator(server: &Path) {
 
     println!("pushing server");
     let status =
-        Command::new("adb").arg("push").arg(server).arg("/data/tmp/testd").status().unwrap();
+        Command::new("adb").arg("push").arg(server).arg("/data/local/tmp/testd").status().unwrap();
     assert!(status.success());
 
     println!("forwarding tcp");
@@ -102,7 +102,7 @@ fn start_android_emulator(server: &Path) {
     assert!(status.success());
 
     println!("executing server");
-    Command::new("adb").arg("shell").arg("/data/tmp/testd").spawn().unwrap();
+    Command::new("adb").arg("shell").arg("/data/local/tmp/testd").spawn().unwrap();
 }
 
 fn prepare_rootfs(target: &str, rootfs: &Path, server: &Path, rootfs_img: &Path) {
diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs
index 0c60d500a80b..bed9d39161df 100644
--- a/src/tools/remote-test-server/src/main.rs
+++ b/src/tools/remote-test-server/src/main.rs
@@ -98,7 +98,7 @@ fn main() {
 
     let listener = t!(TcpListener::bind(config.bind));
     let (work, tmp): (PathBuf, PathBuf) = if cfg!(target_os = "android") {
-        ("/data/tmp/work".into(), "/data/tmp/work/tmp".into())
+        ("/data/local/tmp/work".into(), "/data/local/tmp/work/tmp".into())
     } else {
         let mut work_dir = env::temp_dir();
         work_dir.push("work");

From 1c0ec9f0c84e59cb6eda77fcb082f26c77566685 Mon Sep 17 00:00:00 2001
From: Maybe Waffle 
Date: Fri, 7 Oct 2022 09:04:41 +0000
Subject: [PATCH 098/175] Fix go-to-def for `#[doc = include_str!("path")]`

---
 crates/ide/src/doc_links.rs       |  9 +++++++--
 crates/ide/src/goto_definition.rs | 18 ++++++++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 92ce26b422e1..d96827326cfd 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -232,8 +232,13 @@ pub(crate) fn token_as_doc_comment(doc_token: &SyntaxToken) -> Option TextSize::try_from(comment.prefix().len()).ok(),
-            ast::String(string) => doc_token.parent_ancestors().find_map(ast::Attr::cast)
-                .filter(|attr| attr.simple_name().as_deref() == Some("doc")).and_then(|_| string.open_quote_text_range().map(|it| it.len())),
+            ast::String(string) => {
+                doc_token.parent_ancestors().find_map(ast::Attr::cast).filter(|attr| attr.simple_name().as_deref() == Some("doc"))?;
+                if doc_token.parent_ancestors().find_map(ast::MacroCall::cast).filter(|mac| mac.path().and_then(|p| p.segment()?.name_ref()).as_ref().map(|n| n.text()).as_deref() == Some("include_str")).is_some() {
+                    return None;
+                }
+                string.open_quote_text_range().map(|it| it.len())
+            },
             _ => None,
         }
     }).map(|prefix_len| DocCommentToken { prefix_len, doc_token: doc_token.clone() })
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 7d8ef7ab9dc2..f86ea61d1586 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1367,6 +1367,24 @@ fn main() {
         );
     }
 
+    #[test]
+    fn goto_doc_include_str() {
+        check(
+            r#"
+//- /main.rs
+#[rustc_builtin_macro]
+macro_rules! include_str {}
+
+#[doc = include_str!("docs.md$0")]
+struct Item;
+
+//- /docs.md
+// docs
+//^file
+"#,
+        );
+    }
+
     #[test]
     fn goto_shadow_include() {
         check(

From 4c5d6bb490af0b046c4e445ae90edc0c38623591 Mon Sep 17 00:00:00 2001
From: Florian Bartels 
Date: Fri, 7 Oct 2022 10:22:01 +0200
Subject: [PATCH 099/175] Ensure the correct tombstone file is opened

---
 .../ui/process/process-panic-after-fork.rs    | 22 +++++++++----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/test/ui/process/process-panic-after-fork.rs b/src/test/ui/process/process-panic-after-fork.rs
index ed4c2b5bd392..6d4d24922253 100644
--- a/src/test/ui/process/process-panic-after-fork.rs
+++ b/src/test/ui/process/process-panic-after-fork.rs
@@ -89,29 +89,29 @@ fn expect_aborted(status: ExitStatus) {
         assert!(signal == libc::SIGSEGV);
 
         // Additional checks performed:
-        // 1. Crash is from same executable (path) as we are (must be because of fork):
+        // 1. Find last tombstone (similar to coredump but in text format) from the
+        //    same executable (path) as we are (must be because of usage of fork):
         //    This ensures that we look into the correct tombstone.
         // 2. Cause of crash is a SIGSEGV with address 0xdeadbaad.
         // 3. libc::abort call is in one of top two functions on callstack.
         // The last two steps distinguish between a normal SIGSEGV and one caused
         // by libc::abort.
 
-        let tombstone_name = (0..100)
+        let this_exe = std::env::current_exe().unwrap().into_os_string().into_string().unwrap();
+        let exe_string = format!(">>> {this_exe} <<<");
+        let tombstone = (0..100)
             .map(|n| format!("/data/tombstones/tombstone_{n:02}"))
             .filter(|f| std::path::Path::new(&f).exists())
+            .map(|f| std::fs::read_to_string(&f).expect("Cannot read tombstone file"))
+            .filter(|f| f.contains(&exe_string))
             .last()
             .expect("no tombstone found");
 
-        let tombstone =
-            std::fs::read_to_string(&tombstone_name).expect("Cannot read tombstone file");
-        println!("Content of {tombstone_name}:\n{tombstone}");
+        println!("Content of tombstone:\n{tombstone}");
 
-        // If the next assert fails sporadically we might have an issue with parallel crashing apps
-        assert!(tombstone
-            .contains(&std::env::current_exe().unwrap().into_os_string().into_string().unwrap()));
-        assert!(tombstone.contains(
-            "signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad"
-        ));
+        assert!(
+            tombstone.contains("signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad")
+        );
         let abort_on_top = tombstone
             .lines()
             .skip_while(|l| !l.contains("backtrace:"))

From b0b072d7477a2d10ac7bee77b84ec33151f8eb65 Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Tue, 4 Oct 2022 13:23:53 -0400
Subject: [PATCH 100/175] ADD - codegen_ssa initial diags translations
 machinery

ADD - migrate MissingNativeStaticLibrary fatal error
---
 compiler/rustc_codegen_ssa/src/errors.rs                 | 9 +++++++++
 compiler/rustc_codegen_ssa/src/lib.rs                    | 1 +
 .../rustc_error_messages/locales/en-US/codegen_ssa.ftl   | 1 +
 compiler/rustc_error_messages/src/lib.rs                 | 1 +
 4 files changed, 12 insertions(+)
 create mode 100644 compiler/rustc_codegen_ssa/src/errors.rs
 create mode 100644 compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl

diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
new file mode 100644
index 000000000000..170b7983dbe5
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -0,0 +1,9 @@
+//! Errors emitted by codegen_ssa
+
+use rustc_macros::SessionDiagnostic;
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::missing_native_static_library)]
+pub struct MissingNativeStaticLibrary<'a> {
+    pub library_name: &'a str,
+}
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 3ef9a634e185..e62b6f342b2e 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -43,6 +43,7 @@ pub mod base;
 pub mod common;
 pub mod coverageinfo;
 pub mod debuginfo;
+pub mod errors;
 pub mod glue;
 pub mod meth;
 pub mod mir;
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
new file mode 100644
index 000000000000..deba0dc6f995
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -0,0 +1 @@
+codegen_ssa_missing_native_static_library = could not find native static library `{$library_name}`, perhaps an -L flag is missing?
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 18be60975e4e..10f8efdffa8b 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -63,6 +63,7 @@ fluent_messages! {
     symbol_mangling => "../locales/en-US/symbol_mangling.ftl",
     trait_selection => "../locales/en-US/trait_selection.ftl",
     ty_utils => "../locales/en-US/ty_utils.ftl",
+    codegen_ssa => "../locales/en-US/codegen_ssa.ftl",
 }
 
 pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};

From 4e0de5319c3543b7960394f612a0527923522ae1 Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Wed, 24 Aug 2022 23:40:07 -0400
Subject: [PATCH 101/175] ADD - migrate lib.def write fatal error
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This diagnostic has no UI test 🤔 Should we add some? If so, how?
---
 compiler/rustc_codegen_ssa/src/back/linker.rs              | 7 ++++---
 compiler/rustc_codegen_ssa/src/errors.rs                   | 6 ++++++
 .../rustc_error_messages/locales/en-US/codegen_ssa.ftl     | 2 ++
 3 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index c71d332475a5..60547acc9566 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1,5 +1,6 @@
 use super::command::Command;
 use super::symbol_export;
+use crate::errors::LibDefWriteFailure;
 use rustc_span::symbol::sym;
 
 use std::ffi::{OsStr, OsString};
@@ -666,7 +667,7 @@ impl<'a> Linker for GccLinker<'a> {
                 }
             };
             if let Err(e) = res {
-                self.sess.fatal(&format!("failed to write lib.def file: {}", e));
+                self.sess.emit_fatal(LibDefWriteFailure { error_description: format!("{e}") });
             }
         } else if is_windows {
             let res: io::Result<()> = try {
@@ -681,7 +682,7 @@ impl<'a> Linker for GccLinker<'a> {
                 }
             };
             if let Err(e) = res {
-                self.sess.fatal(&format!("failed to write list.def file: {}", e));
+                self.sess.emit_fatal(LibDefWriteFailure { error_description: format!("{e}") });
             }
         } else {
             // Write an LD version script
@@ -972,7 +973,7 @@ impl<'a> Linker for MsvcLinker<'a> {
             }
         };
         if let Err(e) = res {
-            self.sess.fatal(&format!("failed to write lib.def file: {}", e));
+            self.sess.emit_fatal(LibDefWriteFailure { error_description: format!("{e}") });
         }
         let mut arg = OsString::from("/DEF:");
         arg.push(path);
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 170b7983dbe5..718ad5c7bf56 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -7,3 +7,9 @@ use rustc_macros::SessionDiagnostic;
 pub struct MissingNativeStaticLibrary<'a> {
     pub library_name: &'a str,
 }
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::lib_def_write_failure)]
+pub struct LibDefWriteFailure {
+    pub error_description: String,
+}
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
index deba0dc6f995..597f3488fc1b 100644
--- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -1 +1,3 @@
 codegen_ssa_missing_native_static_library = could not find native static library `{$library_name}`, perhaps an -L flag is missing?
+
+codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error_description}

From 0a2d7f83cb3aea0556ef7cfd7662a028ac974d87 Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Fri, 26 Aug 2022 20:21:55 -0400
Subject: [PATCH 102/175] UPDATE - LibDefWriteFailure to accept type instead of
 formatted string
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This follows team’s suggestions in this thread https://rust-lang.zulipchat.com/#narrow/stream/336883-i18n/topic/.23100717.20diag.20translation/near/295305249
---
 compiler/rustc_codegen_ssa/src/back/linker.rs        | 12 ++++++------
 compiler/rustc_codegen_ssa/src/errors.rs             |  3 ++-
 .../locales/en-US/codegen_ssa.ftl                    |  2 +-
 3 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 60547acc9566..e9335e53125f 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -666,8 +666,8 @@ impl<'a> Linker for GccLinker<'a> {
                     writeln!(f, "_{}", sym)?;
                 }
             };
-            if let Err(e) = res {
-                self.sess.emit_fatal(LibDefWriteFailure { error_description: format!("{e}") });
+            if let Err(error) = res {
+                self.sess.emit_fatal(LibDefWriteFailure { error });
             }
         } else if is_windows {
             let res: io::Result<()> = try {
@@ -681,8 +681,8 @@ impl<'a> Linker for GccLinker<'a> {
                     writeln!(f, "  {}", symbol)?;
                 }
             };
-            if let Err(e) = res {
-                self.sess.emit_fatal(LibDefWriteFailure { error_description: format!("{e}") });
+            if let Err(error) = res {
+                self.sess.emit_fatal(LibDefWriteFailure { error });
             }
         } else {
             // Write an LD version script
@@ -972,8 +972,8 @@ impl<'a> Linker for MsvcLinker<'a> {
                 writeln!(f, "  {}", symbol)?;
             }
         };
-        if let Err(e) = res {
-            self.sess.emit_fatal(LibDefWriteFailure { error_description: format!("{e}") });
+        if let Err(error) = res {
+            self.sess.emit_fatal(LibDefWriteFailure { error });
         }
         let mut arg = OsString::from("/DEF:");
         arg.push(path);
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 718ad5c7bf56..13d9c1a7b6b8 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1,6 +1,7 @@
 //! Errors emitted by codegen_ssa
 
 use rustc_macros::SessionDiagnostic;
+use std::io::Error;
 
 #[derive(SessionDiagnostic)]
 #[diag(codegen_ssa::missing_native_static_library)]
@@ -11,5 +12,5 @@ pub struct MissingNativeStaticLibrary<'a> {
 #[derive(SessionDiagnostic)]
 #[diag(codegen_ssa::lib_def_write_failure)]
 pub struct LibDefWriteFailure {
-    pub error_description: String,
+    pub error: Error,
 }
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
index 597f3488fc1b..d84a774710ac 100644
--- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -1,3 +1,3 @@
 codegen_ssa_missing_native_static_library = could not find native static library `{$library_name}`, perhaps an -L flag is missing?
 
-codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error_description}
+codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error}

From 086e70f13e9259d7949fbfeec6fa824c6327f42d Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Fri, 7 Oct 2022 10:03:45 -0400
Subject: [PATCH 103/175] UPDATE - migrate linker.rs to new diagnostics infra

---
 compiler/rustc_codegen_ssa/src/back/linker.rs | 35 ++++++++--------
 compiler/rustc_codegen_ssa/src/errors.rs      | 42 +++++++++++++++++++
 .../locales/en-US/codegen_ssa.ftl             | 18 ++++++++
 3 files changed, 77 insertions(+), 18 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index e9335e53125f..debcffcd326f 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1,6 +1,6 @@
 use super::command::Command;
 use super::symbol_export;
-use crate::errors::LibDefWriteFailure;
+use crate::errors;
 use rustc_span::symbol::sym;
 
 use std::ffi::{OsStr, OsString};
@@ -91,13 +91,13 @@ pub fn get_linker<'a>(
                     arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a));
                     cmd.arg(&arg);
                 } else {
-                    warn!("arch is not supported");
+                    sess.emit_warning(errors::UnsupportedArch);
                 }
             } else {
-                warn!("MSVC root path lib location not found");
+                sess.emit_warning(errors::MsvcPathNotFound);
             }
         } else {
-            warn!("link.exe not found");
+            sess.emit_warning(errors::LinkExeNotFound);
         }
     }
 
@@ -435,11 +435,11 @@ impl<'a> Linker for GccLinker<'a> {
                 // FIXME(81490): ld64 doesn't support these flags but macOS 11
                 // has -needed-l{} / -needed_library {}
                 // but we have no way to detect that here.
-                self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+                self.sess.emit_warning(errors::Ld64UnimplementedModifier);
             } else if self.is_gnu && !self.sess.target.is_like_windows {
                 self.linker_arg("--no-as-needed");
             } else {
-                self.sess.warn("`as-needed` modifier not supported for current linker");
+                self.sess.emit_warning(errors::LinkerUnsupportedModifier);
             }
         }
         self.hint_dynamic();
@@ -493,7 +493,7 @@ impl<'a> Linker for GccLinker<'a> {
             // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
             // flag but we have no way to detect that here.
             // self.cmd.arg("-needed_framework").arg(framework);
-            self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+            self.sess.emit_warning(errors::Ld64UnimplementedModifier);
         }
         self.cmd.arg("-framework").arg(framework);
     }
@@ -667,7 +667,7 @@ impl<'a> Linker for GccLinker<'a> {
                 }
             };
             if let Err(error) = res {
-                self.sess.emit_fatal(LibDefWriteFailure { error });
+                self.sess.emit_fatal(errors::LibDefWriteFailure { error });
             }
         } else if is_windows {
             let res: io::Result<()> = try {
@@ -682,7 +682,7 @@ impl<'a> Linker for GccLinker<'a> {
                 }
             };
             if let Err(error) = res {
-                self.sess.emit_fatal(LibDefWriteFailure { error });
+                self.sess.emit_fatal(errors::LibDefWriteFailure { error });
             }
         } else {
             // Write an LD version script
@@ -698,8 +698,8 @@ impl<'a> Linker for GccLinker<'a> {
                 }
                 writeln!(f, "\n  local:\n    *;\n}};")?;
             };
-            if let Err(e) = res {
-                self.sess.fatal(&format!("failed to write version script: {}", e));
+            if let Err(error) = res {
+                self.sess.emit_fatal(errors::VersionScriptWriteFailure { error });
             }
         }
 
@@ -916,9 +916,8 @@ impl<'a> Linker for MsvcLinker<'a> {
                                     self.cmd.arg(arg);
                                 }
                             }
-                            Err(err) => {
-                                self.sess
-                                    .warn(&format!("error enumerating natvis directory: {}", err));
+                            Err(error) => {
+                                self.sess.emit_warning(errors::NoNatvisDirectory { error });
                             }
                         }
                     }
@@ -973,7 +972,7 @@ impl<'a> Linker for MsvcLinker<'a> {
             }
         };
         if let Err(error) = res {
-            self.sess.emit_fatal(LibDefWriteFailure { error });
+            self.sess.emit_fatal(errors::LibDefWriteFailure { error });
         }
         let mut arg = OsString::from("/DEF:");
         arg.push(path);
@@ -1436,7 +1435,7 @@ impl<'a> Linker for L4Bender<'a> {
 
     fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
         // ToDo, not implemented, copy from GCC
-        self.sess.warn("exporting symbols not implemented yet for L4Bender");
+        self.sess.emit_warning(errors::L4BenderExportingSymbolsUnimplemented);
         return;
     }
 
@@ -1728,8 +1727,8 @@ impl<'a> Linker for BpfLinker<'a> {
                 writeln!(f, "{}", sym)?;
             }
         };
-        if let Err(e) = res {
-            self.sess.fatal(&format!("failed to write symbols file: {}", e));
+        if let Err(error) = res {
+            self.sess.emit_fatal(errors::SymbolFileWriteFailure { error });
         } else {
             self.cmd.arg("--export-symbols").arg(&path);
         }
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 13d9c1a7b6b8..05d89b32618e 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -14,3 +14,45 @@ pub struct MissingNativeStaticLibrary<'a> {
 pub struct LibDefWriteFailure {
     pub error: Error,
 }
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::version_script_write_failure)]
+pub struct VersionScriptWriteFailure {
+    pub error: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::symbol_file_write_failure)]
+pub struct SymbolFileWriteFailure {
+    pub error: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::unsupported_arch)]
+pub struct UnsupportedArch;
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::msvc_path_not_found)]
+pub struct MsvcPathNotFound;
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::link_exe_not_found)]
+pub struct LinkExeNotFound;
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::ld64_unimplemented_modifier)]
+pub struct Ld64UnimplementedModifier;
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::linker_unsupported_modifier)]
+pub struct LinkerUnsupportedModifier;
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::L4Bender_exporting_symbols_unimplemented)]
+pub struct L4BenderExportingSymbolsUnimplemented;
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::no_natvis_directory)]
+pub struct NoNatvisDirectory {
+    pub error: Error,
+}
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
index d84a774710ac..090a4dc9510b 100644
--- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -1,3 +1,21 @@
 codegen_ssa_missing_native_static_library = could not find native static library `{$library_name}`, perhaps an -L flag is missing?
 
 codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error}
+
+codegen_ssa_version_script_write_failure = failed to write version script: {$error}
+
+codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
+
+codegen_ssa_unsupported_arch = arch is not supported
+
+codegen_ssa_msvc_path_not_found = MSVC root path lib location not found
+
+codegen_ssa_link_exe_not_found = link.exe not found
+
+codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64
+
+codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
+
+codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender
+
+codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}

From d9197dbbcd35c69a210806cea18d2ce0f3691839 Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Sun, 28 Aug 2022 19:58:12 -0400
Subject: [PATCH 104/175] UPDATE - migrate write.rs to new diagnostics infra

---
 compiler/rustc_codegen_ssa/src/back/write.rs  | 41 ++++++++--------
 compiler/rustc_codegen_ssa/src/errors.rs      | 48 +++++++++++++++++++
 .../locales/en-US/codegen_ssa.ftl             |  8 ++++
 3 files changed, 75 insertions(+), 22 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 6188094bbbdd..125b231b2748 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -2,11 +2,11 @@ use super::link::{self, ensure_removed};
 use super::lto::{self, SerializedModule};
 use super::symbol_export::symbol_name_for_instance_in_crate;
 
+use crate::errors;
+use crate::traits::*;
 use crate::{
     CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
 };
-
-use crate::traits::*;
 use jobserver::{Acquired, Client};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::memmap::Mmap;
@@ -530,7 +530,7 @@ fn produce_final_output_artifacts(
     // Produce final compile outputs.
     let copy_gracefully = |from: &Path, to: &Path| {
         if let Err(e) = fs::copy(from, to) {
-            sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e));
+            sess.emit_err(errors::CopyPath::new(from, to, e));
         }
     };
 
@@ -546,7 +546,7 @@ fn produce_final_output_artifacts(
                 ensure_removed(sess.diagnostic(), &path);
             }
         } else {
-            let ext = crate_output
+            let extension = crate_output
                 .temp_path(output_type, None)
                 .extension()
                 .unwrap()
@@ -557,19 +557,11 @@ fn produce_final_output_artifacts(
             if crate_output.outputs.contains_key(&output_type) {
                 // 2) Multiple codegen units, with `--emit foo=some_name`.  We have
                 //    no good solution for this case, so warn the user.
-                sess.warn(&format!(
-                    "ignoring emit path because multiple .{} files \
-                                    were produced",
-                    ext
-                ));
+                sess.emit_warning(errors::IgnoringEmitPath { extension });
             } else if crate_output.single_output_file.is_some() {
                 // 3) Multiple codegen units, with `-o some_name`.  We have
                 //    no good solution for this case, so warn the user.
-                sess.warn(&format!(
-                    "ignoring -o because multiple .{} files \
-                                    were produced",
-                    ext
-                ));
+                sess.emit_warning(errors::IgnoringOutput { extension });
             } else {
                 // 4) Multiple codegen units, but no explicit name.  We
                 //    just leave the `foo.0.x` files in place.
@@ -880,14 +872,19 @@ fn execute_copy_from_cache_work_item(
         );
         match link_or_copy(&source_file, &output_path) {
             Ok(_) => Some(output_path),
-            Err(err) => {
-                let diag_handler = cgcx.create_diag_handler();
-                diag_handler.err(&format!(
-                    "unable to copy {} to {}: {}",
-                    source_file.display(),
-                    output_path.display(),
-                    err
-                ));
+            Err(_) => {
+                // FIXME:
+                // Should we add Translations support in Handler, or should we pass a session here ?
+                //
+                // As Luis Cardoso mentioned here https://github.com/rust-lang/rust/pull/100753#discussion_r952975345,
+                // Translations support in Handler is tricky because SessionDiagnostic is not a trait,
+                // and we can't implement it in Handler because rustc_errors cannot depend on rustc_session.
+                //
+                // As for passing a session here, my understanding is that all these errors should be reported via
+                // the Shared Handler, which leads us to probably having to support Translations in another way.
+
+                // let diag_handler = cgcx.create_diag_handler();
+                // diag_handler.emit_err(errors::CopyPathBuf { source_file, output_path, error });
                 None
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 05d89b32618e..2ae5e659d2da 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1,7 +1,10 @@
 //! Errors emitted by codegen_ssa
 
+use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
 use rustc_macros::SessionDiagnostic;
+use std::borrow::Cow;
 use std::io::Error;
+use std::path::{Path, PathBuf};
 
 #[derive(SessionDiagnostic)]
 #[diag(codegen_ssa::missing_native_static_library)]
@@ -56,3 +59,48 @@ pub struct L4BenderExportingSymbolsUnimplemented;
 pub struct NoNatvisDirectory {
     pub error: Error,
 }
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::copy_path_buf)]
+pub struct CopyPathBuf {
+    pub source_file: PathBuf,
+    pub output_path: PathBuf,
+    pub error: Error,
+}
+
+// Reports Paths using `Debug` implementation rather than Path's `Display` implementation.
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::copy_path)]
+pub struct CopyPath<'a> {
+    from: DebugArgPath<'a>,
+    to: DebugArgPath<'a>,
+    error: Error,
+}
+
+impl<'a> CopyPath<'a> {
+    pub fn new(from: &'a Path, to: &'a Path, error: Error) -> CopyPath<'a> {
+        CopyPath { from: DebugArgPath { path: from }, to: DebugArgPath { path: to }, error }
+    }
+}
+
+struct DebugArgPath<'a> {
+    pub path: &'a Path,
+}
+
+impl IntoDiagnosticArg for DebugArgPath<'_> {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.path)))
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::ignoring_emit_path)]
+pub struct IgnoringEmitPath {
+    pub extension: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(codegen_ssa::ignoring_output)]
+pub struct IgnoringOutput {
+    pub extension: String,
+}
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
index 090a4dc9510b..0d021edc4f76 100644
--- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -19,3 +19,11 @@ codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for
 codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender
 
 codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
+
+codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
+
+codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}
+
+codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
+
+codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced

From 67eb01c3f3c9ce8237bb09ecb4a77b3030af025b Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Sat, 10 Sep 2022 13:16:37 -0400
Subject: [PATCH 105/175] UPDATE - codege-ssa errors to new Diagnostic macro
 name

---
 compiler/rustc_codegen_ssa/src/errors.rs | 32 ++++++++++++------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 2ae5e659d2da..8c09aa96c8ef 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1,66 +1,66 @@
 //! Errors emitted by codegen_ssa
 
 use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::Diagnostic;
 use std::borrow::Cow;
 use std::io::Error;
 use std::path::{Path, PathBuf};
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::missing_native_static_library)]
 pub struct MissingNativeStaticLibrary<'a> {
     pub library_name: &'a str,
 }
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::lib_def_write_failure)]
 pub struct LibDefWriteFailure {
     pub error: Error,
 }
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::version_script_write_failure)]
 pub struct VersionScriptWriteFailure {
     pub error: Error,
 }
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::symbol_file_write_failure)]
 pub struct SymbolFileWriteFailure {
     pub error: Error,
 }
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::unsupported_arch)]
 pub struct UnsupportedArch;
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::msvc_path_not_found)]
 pub struct MsvcPathNotFound;
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::link_exe_not_found)]
 pub struct LinkExeNotFound;
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::ld64_unimplemented_modifier)]
 pub struct Ld64UnimplementedModifier;
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::linker_unsupported_modifier)]
 pub struct LinkerUnsupportedModifier;
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::L4Bender_exporting_symbols_unimplemented)]
 pub struct L4BenderExportingSymbolsUnimplemented;
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::no_natvis_directory)]
 pub struct NoNatvisDirectory {
     pub error: Error,
 }
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::copy_path_buf)]
 pub struct CopyPathBuf {
     pub source_file: PathBuf,
@@ -69,7 +69,7 @@ pub struct CopyPathBuf {
 }
 
 // Reports Paths using `Debug` implementation rather than Path's `Display` implementation.
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::copy_path)]
 pub struct CopyPath<'a> {
     from: DebugArgPath<'a>,
@@ -93,13 +93,13 @@ impl IntoDiagnosticArg for DebugArgPath<'_> {
     }
 }
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::ignoring_emit_path)]
 pub struct IgnoringEmitPath {
     pub extension: String,
 }
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(codegen_ssa::ignoring_output)]
 pub struct IgnoringOutput {
     pub extension: String,

From 7548d952af07e7df18bb894b3f470d321f4d6c04 Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Sat, 10 Sep 2022 13:24:46 -0400
Subject: [PATCH 106/175] UPDATE - resolve fixme and emit errors via Handler

---
 compiler/rustc_codegen_ssa/src/back/write.rs | 19 ++++++-------------
 1 file changed, 6 insertions(+), 13 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 125b231b2748..1f577e9f3524 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -872,19 +872,12 @@ fn execute_copy_from_cache_work_item(
         );
         match link_or_copy(&source_file, &output_path) {
             Ok(_) => Some(output_path),
-            Err(_) => {
-                // FIXME:
-                // Should we add Translations support in Handler, or should we pass a session here ?
-                //
-                // As Luis Cardoso mentioned here https://github.com/rust-lang/rust/pull/100753#discussion_r952975345,
-                // Translations support in Handler is tricky because SessionDiagnostic is not a trait,
-                // and we can't implement it in Handler because rustc_errors cannot depend on rustc_session.
-                //
-                // As for passing a session here, my understanding is that all these errors should be reported via
-                // the Shared Handler, which leads us to probably having to support Translations in another way.
-
-                // let diag_handler = cgcx.create_diag_handler();
-                // diag_handler.emit_err(errors::CopyPathBuf { source_file, output_path, error });
+            Err(error) => {
+                cgcx.create_diag_handler().emit_err(errors::CopyPathBuf {
+                    source_file,
+                    output_path,
+                    error,
+                });
                 None
             }
         }

From 0f97d4a1417cdf58b7a39e351dcdf40cf58e48b9 Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Tue, 13 Sep 2022 08:46:47 -0400
Subject: [PATCH 107/175] DELETE - unused error after PR# 100101 was merged

---
 compiler/rustc_codegen_ssa/src/errors.rs                    | 6 ------
 compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl | 2 --
 2 files changed, 8 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 8c09aa96c8ef..cf98cb2468ab 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -6,12 +6,6 @@ use std::borrow::Cow;
 use std::io::Error;
 use std::path::{Path, PathBuf};
 
-#[derive(Diagnostic)]
-#[diag(codegen_ssa::missing_native_static_library)]
-pub struct MissingNativeStaticLibrary<'a> {
-    pub library_name: &'a str,
-}
-
 #[derive(Diagnostic)]
 #[diag(codegen_ssa::lib_def_write_failure)]
 pub struct LibDefWriteFailure {
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
index 0d021edc4f76..4d43b2eb0b69 100644
--- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -1,5 +1,3 @@
-codegen_ssa_missing_native_static_library = could not find native static library `{$library_name}`, perhaps an -L flag is missing?
-
 codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error}
 
 codegen_ssa_version_script_write_failure = failed to write version script: {$error}

From 12aa84bdf3231f563b7f86186dbece2023d1235a Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Sun, 2 Oct 2022 23:21:15 -0400
Subject: [PATCH 108/175] ADD - initial port of link.rs

---
 compiler/rustc_codegen_ssa/src/back/link.rs   |  89 ++++++--------
 compiler/rustc_codegen_ssa/src/errors.rs      | 109 +++++++++++++++++-
 compiler/rustc_codegen_ssa/src/lib.rs         |   1 +
 .../locales/en-US/codegen_ssa.ftl             |  25 ++++
 4 files changed, 166 insertions(+), 58 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 9a0c379b4e44..ac2a8f969df0 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -31,7 +31,9 @@ use super::command::Command;
 use super::linker::{self, Linker};
 use super::metadata::{create_rmeta_file, MetadataPosition};
 use super::rpath::{self, RPathConfig};
-use crate::{looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib};
+use crate::{
+    errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
+};
 
 use cc::windows_registry;
 use regex::Regex;
@@ -93,7 +95,7 @@ pub fn link_binary<'a>(
             let tmpdir = TempFileBuilder::new()
                 .prefix("rustc")
                 .tempdir()
-                .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
+                .unwrap_or_else(|error| sess.emit_fatal(errors::CreateTempDir { error }));
             let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
             let out_filename = out_filename(
                 sess,
@@ -208,7 +210,7 @@ pub fn link_binary<'a>(
 pub fn each_linked_rlib(
     info: &CrateInfo,
     f: &mut dyn FnMut(CrateNum, &Path),
-) -> Result<(), String> {
+) -> Result<(), errors::LinkRlibError> {
     let crates = info.used_crates.iter();
     let mut fmts = None;
     for (ty, list) in info.dependency_formats.iter() {
@@ -224,26 +226,23 @@ pub fn each_linked_rlib(
         }
     }
     let Some(fmts) = fmts else {
-        return Err("could not find formats for rlibs".to_string());
+        return Err(errors::LinkRlibError::MissingFormat);
     };
     for &cnum in crates {
         match fmts.get(cnum.as_usize() - 1) {
             Some(&Linkage::NotLinked | &Linkage::IncludedFromDylib) => continue,
             Some(_) => {}
-            None => return Err("could not find formats for rlibs".to_string()),
+            None => return Err(errors::LinkRlibError::MissingFormat),
         }
-        let name = info.crate_name[&cnum];
+        let crate_name = info.crate_name[&cnum];
         let used_crate_source = &info.used_crate_source[&cnum];
         if let Some((path, _)) = &used_crate_source.rlib {
             f(cnum, &path);
         } else {
             if used_crate_source.rmeta.is_some() {
-                return Err(format!(
-                    "could not find rlib for: `{}`, found rmeta (metadata) file",
-                    name
-                ));
+                return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name });
             } else {
-                return Err(format!("could not find rlib for: `{}`", name));
+                return Err(errors::LinkRlibError::NotFound { crate_name });
             }
         }
     }
@@ -340,10 +339,7 @@ fn link_rlib<'a>(
                 // -whole-archive and it isn't clear how we can currently handle such a
                 // situation correctly.
                 // See https://github.com/rust-lang/rust/issues/88085#issuecomment-901050897
-                sess.err(
-                    "the linking modifiers `+bundle` and `+whole-archive` are not compatible \
-                        with each other when generating rlibs",
-                );
+                sess.emit_err(errors::IncompatibleLinkingModifiers);
             }
             NativeLibKind::Static { bundle: None | Some(true), .. } => {}
             NativeLibKind::Static { bundle: Some(false), .. }
@@ -365,12 +361,11 @@ fn link_rlib<'a>(
                 ));
                 continue;
             }
-            ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|e| {
-                sess.fatal(&format!(
-                    "failed to add native library {}: {}",
-                    location.to_string_lossy(),
-                    e
-                ));
+            ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|error| {
+                sess.emit_fatal(errors::AddNativeLibrary {
+                    library_path: &location.to_string_lossy(),
+                    error,
+                });
             });
         }
     }
@@ -385,8 +380,11 @@ fn link_rlib<'a>(
             tmpdir.as_ref(),
         );
 
-        ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|e| {
-            sess.fatal(&format!("failed to add native library {}: {}", output_path.display(), e));
+        ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
+            sess.emit_fatal(errors::AddNativeLibrary {
+                library_path: &output_path.display().to_string(),
+                error,
+            });
         });
     }
 
@@ -451,14 +449,11 @@ fn collate_raw_dylibs(
                     // FIXME: when we add support for ordinals, figure out if we need to do anything
                     // if we have two DllImport values with the same name but different ordinals.
                     if import.calling_convention != old_import.calling_convention {
-                        sess.span_err(
-                            import.span,
-                            &format!(
-                                "multiple declarations of external function `{}` from \
-                                 library `{}` have different calling conventions",
-                                import.name, name,
-                            ),
-                        );
+                        sess.emit_err(errors::MultipleExternalFuncDecl {
+                            span: import.span,
+                            function: import.name,
+                            library_name: &name,
+                        });
                     }
                 }
             }
@@ -560,7 +555,7 @@ fn link_staticlib<'a>(
         all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
     });
     if let Err(e) = res {
-        sess.fatal(&e);
+        sess.emit_fatal(e);
     }
 
     ab.build(out_filename);
@@ -673,9 +668,8 @@ fn link_dwarf_object<'a>(
     }) {
         Ok(()) => {}
         Err(e) => {
-            sess.struct_err("linking dwarf objects with thorin failed")
-                .note(&format!("{:?}", e))
-                .emit();
+            let thorin_error = errors::ThorinErrorWrapper(e);
+            sess.emit_err(errors::ThorinDwarfLinking { thorin_error });
             sess.abort_if_errors();
         }
     }
@@ -879,23 +873,14 @@ fn link_natively<'a>(
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
                 let escaped_output = escape_string(&output);
-                let mut err = sess.struct_err(&format!(
-                    "linking with `{}` failed: {}",
-                    linker_path.display(),
-                    prog.status
-                ));
-                err.note(&format!("{:?}", &cmd)).note(&escaped_output);
-                if escaped_output.contains("undefined reference to") {
-                    err.help(
-                        "some `extern` functions couldn't be found; some native libraries may \
-                         need to be installed or have their path specified",
-                    );
-                    err.note("use the `-l` flag to specify native libraries to link");
-                    err.note("use the `cargo:rustc-link-lib` directive to specify the native \
-                              libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)");
-                }
-                err.emit();
-
+                // FIXME: Add UI tests for this error.
+                let err = errors::LinkingFailed {
+                    linker_path: &linker_path,
+                    exit_status: prog.status,
+                    command: &cmd,
+                    escaped_output: &escaped_output,
+                };
+                sess.diagnostic().emit_err(err);
                 // If MSVC's `link.exe` was expected but the return code
                 // is not a Microsoft LNK error then suggest a way to fix or
                 // install the Visual Studio build tools.
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index cf98cb2468ab..6bd1dc2e03f6 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1,10 +1,16 @@
 //! Errors emitted by codegen_ssa
 
-use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
+use crate::back::command::Command;
+use rustc_errors::{
+    fluent, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
+    IntoDiagnosticArg,
+};
 use rustc_macros::Diagnostic;
+use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 use std::io::Error;
 use std::path::{Path, PathBuf};
+use std::process::ExitStatus;
 
 #[derive(Diagnostic)]
 #[diag(codegen_ssa::lib_def_write_failure)]
@@ -73,17 +79,15 @@ pub struct CopyPath<'a> {
 
 impl<'a> CopyPath<'a> {
     pub fn new(from: &'a Path, to: &'a Path, error: Error) -> CopyPath<'a> {
-        CopyPath { from: DebugArgPath { path: from }, to: DebugArgPath { path: to }, error }
+        CopyPath { from: DebugArgPath(from), to: DebugArgPath(to), error }
     }
 }
 
-struct DebugArgPath<'a> {
-    pub path: &'a Path,
-}
+struct DebugArgPath<'a>(pub &'a Path);
 
 impl IntoDiagnosticArg for DebugArgPath<'_> {
     fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.path)))
+        DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.0)))
     }
 }
 
@@ -98,3 +102,96 @@ pub struct IgnoringEmitPath {
 pub struct IgnoringOutput {
     pub extension: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::create_temp_dir)]
+pub struct CreateTempDir {
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::incompatible_linking_modifiers)]
+pub struct IncompatibleLinkingModifiers;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::add_native_library)]
+pub struct AddNativeLibrary<'a> {
+    pub library_path: &'a str,
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::multiple_external_func_decl)]
+pub struct MultipleExternalFuncDecl<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub function: Symbol,
+    pub library_name: &'a str,
+}
+
+pub enum LinkRlibError {
+    MissingFormat,
+    OnlyRmetaFound { crate_name: Symbol },
+    NotFound { crate_name: Symbol },
+}
+
+impl IntoDiagnostic<'_, !> for LinkRlibError {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
+        match self {
+            LinkRlibError::MissingFormat => {
+                handler.struct_fatal(fluent::codegen_ssa::rlib_missing_format)
+            }
+            LinkRlibError::OnlyRmetaFound { crate_name } => {
+                let mut diag = handler.struct_fatal(fluent::codegen_ssa::rlib_only_rmeta_found);
+                diag.set_arg("crate_name", crate_name);
+                diag
+            }
+            LinkRlibError::NotFound { crate_name } => {
+                let mut diag = handler.struct_fatal(fluent::codegen_ssa::rlib_not_found);
+                diag.set_arg("crate_name", crate_name);
+                diag
+            }
+        }
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::thorin_dwarf_linking)]
+#[note]
+pub struct ThorinDwarfLinking {
+    pub thorin_error: ThorinErrorWrapper,
+}
+pub struct ThorinErrorWrapper(pub thorin::Error);
+
+// FIXME: How should we support translations for external crate errors?
+impl IntoDiagnosticArg for ThorinErrorWrapper {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.0)))
+    }
+}
+
+pub struct LinkingFailed<'a> {
+    pub linker_path: &'a PathBuf,
+    pub exit_status: ExitStatus,
+    pub command: &'a Command,
+    pub escaped_output: &'a str,
+}
+
+impl IntoDiagnostic<'_> for LinkingFailed<'_> {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = handler.struct_err(fluent::codegen_ssa::linking_failed);
+        diag.set_arg("linker_path", format!("{}", self.linker_path.display()));
+        diag.set_arg("exit_status", format!("{}", self.exit_status));
+
+        diag.note(format!("{:?}", self.command)).note(self.escaped_output);
+
+        // Trying to match an error from OS linkers
+        // which by now we have no way to translate.
+        if self.escaped_output.contains("undefined reference to") {
+            diag.note(fluent::codegen_ssa::extern_funcs_not_found)
+                .note(fluent::codegen_ssa::specify_libraries_to_link)
+                .note(fluent::codegen_ssa::use_cargo_directive);
+        }
+        diag
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index e62b6f342b2e..ceebe4d417f7 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(strict_provenance)]
 #![feature(int_roundings)]
 #![feature(if_let_guard)]
+#![feature(never_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
index 4d43b2eb0b69..d996a096a892 100644
--- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -25,3 +25,28 @@ codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$e
 codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
 
 codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced
+
+codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
+
+codegen_ssa_incompatible_linking_modifiers = the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs
+
+codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
+
+codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
+
+codegen_ssa_rlib_missing_format = could not find formats for rlibs
+
+codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, found rmeta (metadata) file
+
+codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
+
+codegen_ssa_thorin_dwarf_linking = linking dwarf objects with thorin failed
+    .note = {$thorin_error}
+
+codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
+
+codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
+
+codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
+
+codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)

From a25f939170bb73d813c5eb4cbed631253ba0cc15 Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Tue, 4 Oct 2022 13:25:13 -0400
Subject: [PATCH 109/175] Address PR comments

- UPDATE - revert migration of logs

- UPDATE - use derive on LinkRlibError enum

- [Gardening] UPDATE - alphabetically sort fluent_messages

- UPDATE - use PathBuf and unify both AddNativeLibrary to use Display (which is what PathBuf uses when conforming to IntoDiagnosticArg)

- UPDATE - fluent messages sort after rebase
---
 compiler/rustc_codegen_ssa/src/back/link.rs   | 10 +----
 compiler/rustc_codegen_ssa/src/back/linker.rs |  6 +--
 compiler/rustc_codegen_ssa/src/errors.rs      | 44 ++++---------------
 .../locales/en-US/codegen_ssa.ftl             |  6 ---
 compiler/rustc_error_messages/src/lib.rs      |  4 +-
 5 files changed, 16 insertions(+), 54 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index ac2a8f969df0..e798fb421df3 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -362,10 +362,7 @@ fn link_rlib<'a>(
                 continue;
             }
             ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|error| {
-                sess.emit_fatal(errors::AddNativeLibrary {
-                    library_path: &location.to_string_lossy(),
-                    error,
-                });
+                sess.emit_fatal(errors::AddNativeLibrary { library_path: location, error });
             });
         }
     }
@@ -381,10 +378,7 @@ fn link_rlib<'a>(
         );
 
         ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
-            sess.emit_fatal(errors::AddNativeLibrary {
-                library_path: &output_path.display().to_string(),
-                error,
-            });
+            sess.emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
         });
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index debcffcd326f..bad22ccb1fed 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -91,13 +91,13 @@ pub fn get_linker<'a>(
                     arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a));
                     cmd.arg(&arg);
                 } else {
-                    sess.emit_warning(errors::UnsupportedArch);
+                    warn!("arch is not supported");
                 }
             } else {
-                sess.emit_warning(errors::MsvcPathNotFound);
+                warn!("MSVC root path lib location not found");
             }
         } else {
-            sess.emit_warning(errors::LinkExeNotFound);
+            warn!("link.exe not found");
         }
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 6bd1dc2e03f6..bd399ffb5a6f 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -30,18 +30,6 @@ pub struct SymbolFileWriteFailure {
     pub error: Error,
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_ssa::unsupported_arch)]
-pub struct UnsupportedArch;
-
-#[derive(Diagnostic)]
-#[diag(codegen_ssa::msvc_path_not_found)]
-pub struct MsvcPathNotFound;
-
-#[derive(Diagnostic)]
-#[diag(codegen_ssa::link_exe_not_found)]
-pub struct LinkExeNotFound;
-
 #[derive(Diagnostic)]
 #[diag(codegen_ssa::ld64_unimplemented_modifier)]
 pub struct Ld64UnimplementedModifier;
@@ -115,8 +103,8 @@ pub struct IncompatibleLinkingModifiers;
 
 #[derive(Diagnostic)]
 #[diag(codegen_ssa::add_native_library)]
-pub struct AddNativeLibrary<'a> {
-    pub library_path: &'a str,
+pub struct AddNativeLibrary {
+    pub library_path: PathBuf,
     pub error: Error,
 }
 
@@ -129,30 +117,16 @@ pub struct MultipleExternalFuncDecl<'a> {
     pub library_name: &'a str,
 }
 
+#[derive(Diagnostic)]
 pub enum LinkRlibError {
+    #[diag(codegen_ssa::rlib_missing_format)]
     MissingFormat,
-    OnlyRmetaFound { crate_name: Symbol },
-    NotFound { crate_name: Symbol },
-}
 
-impl IntoDiagnostic<'_, !> for LinkRlibError {
-    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
-        match self {
-            LinkRlibError::MissingFormat => {
-                handler.struct_fatal(fluent::codegen_ssa::rlib_missing_format)
-            }
-            LinkRlibError::OnlyRmetaFound { crate_name } => {
-                let mut diag = handler.struct_fatal(fluent::codegen_ssa::rlib_only_rmeta_found);
-                diag.set_arg("crate_name", crate_name);
-                diag
-            }
-            LinkRlibError::NotFound { crate_name } => {
-                let mut diag = handler.struct_fatal(fluent::codegen_ssa::rlib_not_found);
-                diag.set_arg("crate_name", crate_name);
-                diag
-            }
-        }
-    }
+    #[diag(codegen_ssa::rlib_only_rmeta_found)]
+    OnlyRmetaFound { crate_name: Symbol },
+
+    #[diag(codegen_ssa::rlib_not_found)]
+    NotFound { crate_name: Symbol },
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
index d996a096a892..99ddf6842dab 100644
--- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -4,12 +4,6 @@ codegen_ssa_version_script_write_failure = failed to write version script: {$err
 
 codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
 
-codegen_ssa_unsupported_arch = arch is not supported
-
-codegen_ssa_msvc_path_not_found = MSVC root path lib location not found
-
-codegen_ssa_link_exe_not_found = link.exe not found
-
 codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64
 
 codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 10f8efdffa8b..77f87d5b007e 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -40,9 +40,10 @@ fluent_messages! {
     attr => "../locales/en-US/attr.ftl",
     borrowck => "../locales/en-US/borrowck.ftl",
     builtin_macros => "../locales/en-US/builtin_macros.ftl",
+    codegen_gcc => "../locales/en-US/codegen_gcc.ftl",
+    codegen_ssa => "../locales/en-US/codegen_ssa.ftl",
     compiletest => "../locales/en-US/compiletest.ftl",
     const_eval => "../locales/en-US/const_eval.ftl",
-    codegen_gcc => "../locales/en-US/codegen_gcc.ftl",
     driver => "../locales/en-US/driver.ftl",
     expand => "../locales/en-US/expand.ftl",
     hir_analysis => "../locales/en-US/hir_analysis.ftl",
@@ -63,7 +64,6 @@ fluent_messages! {
     symbol_mangling => "../locales/en-US/symbol_mangling.ftl",
     trait_selection => "../locales/en-US/trait_selection.ftl",
     ty_utils => "../locales/en-US/ty_utils.ftl",
-    codegen_ssa => "../locales/en-US/codegen_ssa.ftl",
 }
 
 pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};

From 13d4f27c829a332f50a2109647f3b16bce119b8d Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Tue, 4 Oct 2022 13:21:22 -0400
Subject: [PATCH 110/175] ADD - implement IntoDiagnostic for thorin::Error
 wrapper

---
 compiler/rustc_codegen_ssa/src/back/link.rs   |   3 +-
 compiler/rustc_codegen_ssa/src/errors.rs      | 202 +++++++++++++++++-
 .../locales/en-US/codegen_ssa.ftl             |  79 ++++++-
 3 files changed, 269 insertions(+), 15 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index e798fb421df3..95e72184ff03 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -662,8 +662,7 @@ fn link_dwarf_object<'a>(
     }) {
         Ok(()) => {}
         Err(e) => {
-            let thorin_error = errors::ThorinErrorWrapper(e);
-            sess.emit_err(errors::ThorinDwarfLinking { thorin_error });
+            sess.emit_err(errors::ThorinErrorWrapper(e));
             sess.abort_if_errors();
         }
     }
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index bd399ffb5a6f..0ffe88720226 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -129,18 +129,200 @@ pub enum LinkRlibError {
     NotFound { crate_name: Symbol },
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_ssa::thorin_dwarf_linking)]
-#[note]
-pub struct ThorinDwarfLinking {
-    pub thorin_error: ThorinErrorWrapper,
-}
 pub struct ThorinErrorWrapper(pub thorin::Error);
 
-// FIXME: How should we support translations for external crate errors?
-impl IntoDiagnosticArg for ThorinErrorWrapper {
-    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.0)))
+impl IntoDiagnostic<'_> for ThorinErrorWrapper {
+    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag;
+        match self.0 {
+            thorin::Error::ReadInput(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_read_input_failure);
+                diag
+            }
+            thorin::Error::ParseFileKind(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_file_kind);
+                diag
+            }
+            thorin::Error::ParseObjectFile(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_object_file);
+                diag
+            }
+            thorin::Error::ParseArchiveFile(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_archive_file);
+                diag
+            }
+            thorin::Error::ParseArchiveMember(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_archive_member);
+                diag
+            }
+            thorin::Error::InvalidInputKind => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_invalid_input_kind);
+                diag
+            }
+            thorin::Error::DecompressData(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_decompress_data);
+                diag
+            }
+            thorin::Error::NamelessSection(_, offset) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_section_without_name);
+                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag
+            }
+            thorin::Error::RelocationWithInvalidSymbol(section, offset) => {
+                diag =
+                    handler.struct_err(fluent::codegen_ssa::thorin_relocation_with_invalid_symbol);
+                diag.set_arg("section", section);
+                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag
+            }
+            thorin::Error::MultipleRelocations(section, offset) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_relocations);
+                diag.set_arg("section", section);
+                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag
+            }
+            thorin::Error::UnsupportedRelocation(section, offset) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_unsupported_relocation);
+                diag.set_arg("section", section);
+                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag
+            }
+            thorin::Error::MissingDwoName(id) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_dwo_name);
+                diag.set_arg("id", format!("0x{:08x}", id));
+                diag
+            }
+            thorin::Error::NoCompilationUnits => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_no_compilation_units);
+                diag
+            }
+            thorin::Error::NoDie => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_no_die);
+                diag
+            }
+            thorin::Error::TopLevelDieNotUnit => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_top_level_die_not_unit);
+                diag
+            }
+            thorin::Error::MissingRequiredSection(section) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_required_section);
+                diag.set_arg("section", section);
+                diag
+            }
+            thorin::Error::ParseUnitAbbreviations(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_abbreviations);
+                diag
+            }
+            thorin::Error::ParseUnitAttribute(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_attribute);
+                diag
+            }
+            thorin::Error::ParseUnitHeader(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_header);
+                diag
+            }
+            thorin::Error::ParseUnit(_) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit);
+                diag
+            }
+            thorin::Error::IncompatibleIndexVersion(section, format, actual) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_incompatible_index_version);
+                diag.set_arg("section", section);
+                diag.set_arg("actual", actual);
+                diag.set_arg("format", format);
+                diag
+            }
+            thorin::Error::OffsetAtIndex(_, index) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_offset_at_index);
+                diag.set_arg("index", index);
+                diag
+            }
+            thorin::Error::StrAtOffset(_, offset) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_str_at_offset);
+                diag.set_arg("offset", format!("0x{:08x}", offset));
+                diag
+            }
+            thorin::Error::ParseIndex(_, section) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_index);
+                diag.set_arg("section", section);
+                diag
+            }
+            thorin::Error::UnitNotInIndex(unit) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_unit_not_in_index);
+                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag
+            }
+            thorin::Error::RowNotInIndex(_, row) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_row_not_in_index);
+                diag.set_arg("row", row);
+                diag
+            }
+            thorin::Error::SectionNotInRow => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_section_not_in_row);
+                diag
+            }
+            thorin::Error::EmptyUnit(unit) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_empty_unit);
+                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag
+            }
+            thorin::Error::MultipleDebugInfoSection => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_info_section);
+                diag
+            }
+            thorin::Error::MultipleDebugTypesSection => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_types_section);
+                diag
+            }
+            thorin::Error::NotSplitUnit => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_not_split_unit);
+                diag
+            }
+            thorin::Error::DuplicateUnit(unit) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_duplicate_unit);
+                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag
+            }
+            thorin::Error::MissingReferencedUnit(unit) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_referenced_unit);
+                diag.set_arg("unit", format!("0x{:08x}", unit));
+                diag
+            }
+            thorin::Error::NoOutputObjectCreated => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_not_output_object_created);
+                diag
+            }
+            thorin::Error::MixedInputEncodings => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_mixed_input_encodings);
+                diag
+            }
+            thorin::Error::Io(e) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_io);
+                diag.set_arg("error", format!("{e}"));
+                diag
+            }
+            thorin::Error::ObjectRead(e) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_object_read);
+                diag.set_arg("error", format!("{e}"));
+                diag
+            }
+            thorin::Error::ObjectWrite(e) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_object_write);
+                diag.set_arg("error", format!("{e}"));
+                diag
+            }
+            thorin::Error::GimliRead(e) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_read);
+                diag.set_arg("error", format!("{e}"));
+                diag
+            }
+            thorin::Error::GimliWrite(e) => {
+                diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_write);
+                diag.set_arg("error", format!("{e}"));
+                diag
+            }
+            _ => unimplemented!("Untranslated thorin error"),
+        }
     }
 }
 
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
index 99ddf6842dab..0d0388a039e2 100644
--- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -34,9 +34,6 @@ codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, fo
 
 codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
 
-codegen_ssa_thorin_dwarf_linking = linking dwarf objects with thorin failed
-    .note = {$thorin_error}
-
 codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
 
 codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
@@ -44,3 +41,79 @@ codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found;
 codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
 
 codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)
+
+codegen_ssa_thorin_read_input_failure = failed to read input file
+
+codegen_ssa_thorin_parse_input_file_kind = failed to parse input file kind
+
+codegen_ssa_thorin_parse_input_object_file = failed to parse input object file
+
+codegen_ssa_thorin_parse_input_archive_file = failed to parse input archive file
+
+codegen_ssa_thorin_parse_archive_member = failed to parse archive member
+
+codegen_ssa_thorin_invalid_input_kind = input is not an archive or elf object
+
+codegen_ssa_thorin_decompress_data = failed to decompress compressed section
+
+codegen_ssa_thorin_section_without_name = section without name at offset {$offset}
+
+codegen_ssa_thorin_relocation_with_invalid_symbol = relocation with invalid symbol for section `{$section}` at offset {$offset}
+
+codegen_ssa_thorin_multiple_relocations = multiple relocations for section `{$section}` at offset {$offset}
+
+codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset}
+
+codegen_ssa_thorin_missing_dwo_name = missing path attribute to DWARF object ({$id})
+
+codegen_ssa_thorin_no_compilation_units = input object has no compilation units
+
+codegen_ssa_thorin_no_die = no top-level debugging information entry in compilation/type unit
+
+codegen_ssa_thorin_top_level_die_not_unit = top-level debugging information entry is not a compilation/type unit
+
+codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}`
+
+codegen_ssa_thorin_parse_unit_abbreviations = failed to parse unit abbreviations
+
+codegen_ssa_thorin_parse_unit_attribute = failed to parse unit attribute
+
+codegen_ssa_thorin_parse_unit_header = failed to parse unit header
+
+codegen_ssa_thorin_parse_unit = failed to parse unit
+
+codegen_ssa_thorin_incompatible_index_version = incompatible `{$section}` index version: found version {$actual}, expected version {$format}
+
+codegen_ssa_thorin_offset_at_index = read offset at index {$index} of `.debug_str_offsets.dwo` section
+
+codegen_ssa_thorin_str_at_offset = read string at offset {$offset} of `.debug_str.dwo` section
+
+codegen_ssa_thorin_parse_index = failed to parse `{$section}` index section
+
+codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in its index
+
+codegen_ssa_thorin_row_not_in_index = row {$row} found in index's hash table not present in index
+
+codegen_ssa_thorin_section_not_in_row = section not found in unit's row in index
+
+codegen_ssa_thorin_empty_unit = unit {$unit} in input DWARF object with no data
+
+codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections
+
+codegen_ssa_thorin_multiple_debug_types_section = multiple `.debug_types.dwo` sections in a package
+
+codegen_ssa_thorin_not_split_unit = regular compilation unit in object (missing dwo identifier)
+
+codegen_ssa_thorin_duplicate_unit = duplicate split compilation unit ({$unit})
+
+codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executable was not found
+
+codegen_ssa_thorin_not_output_object_created = no output object was created from inputs
+
+codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings
+
+codegen_ssa_thorin_io = {$error}
+codegen_ssa_thorin_object_read = {$error}
+codegen_ssa_thorin_object_write = {$error}
+codegen_ssa_thorin_gimli_read = {$error}
+codegen_ssa_thorin_gimli_write = {$error}

From bde80f745b86750a31294013fef590dd9e6965c3 Mon Sep 17 00:00:00 2001
From: rdvdev2 
Date: Mon, 22 Aug 2022 08:56:46 +0200
Subject: [PATCH 111/175] Add lint for diagnostic migration

---
 compiler/rustc_passes/src/lib.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 6e621b7eb5eb..15f60f626c89 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -5,6 +5,8 @@
 //! This API is completely unstable and subject to change.
 
 #![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]

From 2f74d1d14ff08bfc5995ba1379840e5bd3f30efb Mon Sep 17 00:00:00 2001
From: rdvdev2 
Date: Mon, 22 Aug 2022 10:05:13 +0200
Subject: [PATCH 112/175] Migrate weak_lang_items.rs

---
 .../locales/en-US/passes.ftl                    |  9 +++++++++
 compiler/rustc_passes/src/errors.rs             | 17 +++++++++++++++++
 compiler/rustc_passes/src/weak_lang_items.rs    | 15 +++++----------
 3 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 995ad4fe2585..bfe22727483d 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -271,3 +271,12 @@ passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to
 
 passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect
     .suggestion = remove the unnecessary deprecation attribute
+    
+passes_missing_panic_handler = `#[panic_handler]` function required, but not found
+
+passes_missing_alloc_error_handler = `#[alloc_error_handler]` function required, but not found
+    .note = use `#![feature(default_alloc_error_handler)]` for a default error handler
+
+passes_missing_lang_item = language item required, but not found: `{$name}`
+    .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
+    .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config`
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index cc231af71a27..7dbdee8a87ae 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -665,3 +665,20 @@ pub struct DeprecatedAnnotationHasNoEffect {
     #[suggestion(applicability = "machine-applicable", code = "")]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(passes::missing_panic_handler)]
+pub struct MissingPanicHandler;
+
+#[derive(Diagnostic)]
+#[diag(passes::missing_alloc_error_handler)]
+#[note]
+pub struct MissingAllocErrorHandler;
+
+#[derive(Diagnostic)]
+#[diag(passes::missing_lang_item)]
+#[note]
+#[help]
+pub struct MissingLangItem {
+    pub name: Symbol,
+}
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index c48b4ecf87a3..2345de74bdfb 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -8,6 +8,8 @@ use rustc_middle::middle::lang_items::required;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
 
+use crate::errors::{MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler};
+
 /// Checks the crate for usage of weak lang items, returning a vector of all the
 /// language items required by this crate, but not defined yet.
 pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItems) {
@@ -71,20 +73,13 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
     for (name, &item) in WEAK_ITEMS_REFS.iter() {
         if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() {
             if item == LangItem::PanicImpl {
-                tcx.sess.err("`#[panic_handler]` function required, but not found");
+                tcx.sess.emit_err(MissingPanicHandler);
             } else if item == LangItem::Oom {
                 if !tcx.features().default_alloc_error_handler {
-                    tcx.sess.err("`#[alloc_error_handler]` function required, but not found");
-                    tcx.sess.note_without_error("use `#![feature(default_alloc_error_handler)]` for a default error handler");
+                    tcx.sess.emit_err(MissingAllocErrorHandler);
                 }
             } else {
-                tcx
-                    .sess
-                    .diagnostic()
-                    .struct_err(&format!("language item required, but not found: `{}`", name))
-                    .note(&format!("this can occur when a binary crate with `#![no_std]` is compiled for a target where `{}` is defined in the standard library", name))
-                    .help(&format!("you may be able to compile for a target that doesn't need `{}`, specify a target with `--target` or in `.cargo/config`", name))
-                    .emit();
+                tcx.sess.emit_err(MissingLangItem { name: *name });
             }
         }
     }

From 17a4a68ab0ffa0e8736d5ccf71f6e56794a0320a Mon Sep 17 00:00:00 2001
From: rdvdev2 
Date: Fri, 2 Sep 2022 00:11:44 +0200
Subject: [PATCH 113/175] Migrate derivable diagnostics in lang_items.rs

---
 .../locales/en-US/passes.ftl                  |  8 +++++
 compiler/rustc_passes/src/errors.rs           | 21 +++++++++++++
 compiler/rustc_passes/src/lang_items.rs       | 30 +++++--------------
 3 files changed, 37 insertions(+), 22 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index bfe22727483d..6512af1d14c8 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -280,3 +280,11 @@ passes_missing_alloc_error_handler = `#[alloc_error_handler]` function required,
 passes_missing_lang_item = language item required, but not found: `{$name}`
     .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
     .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config`
+
+passes_lang_item_on_incorrect_target = `{$name}` language item must be applied to a {$expected_target}
+    .label = attribute should be applied to a {$expected_target}, not a {$actual_target}
+
+passes_unknown_lang_item = definition of an unknown language item: `{$name}`
+    .label = definition of unknown language item `{$name}`
+
+passes_local_duplicate_lang_item = found duplicate lang item `{$name}`
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 7dbdee8a87ae..cd05784cd53b 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1,4 +1,5 @@
 use rustc_errors::{Applicability, MultiSpan};
+use rustc_hir::Target;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
@@ -682,3 +683,23 @@ pub struct MissingAllocErrorHandler;
 pub struct MissingLangItem {
     pub name: Symbol,
 }
+
+#[derive(Diagnostic)]
+#[diag(passes::lang_item_on_incorrect_target, code = "E0718")]
+pub struct LangItemOnIncorrectTarget {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub name: Symbol,
+    pub expected_target: Target,
+    pub actual_target: Target,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::unknown_lang_item, code = "E0522")]
+pub struct UnknownLangItem {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub name: Symbol,
+}
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 79900a90aed6..98ff625d0946 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -7,6 +7,7 @@
 //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
 //! * Functions called by the compiler itself.
 
+use crate::errors::{LangItemOnIncorrectTarget, UnknownLangItem};
 use crate::check_attr::target_from_impl_item;
 use crate::weak_lang_items;
 
@@ -42,34 +43,19 @@ impl<'tcx> LanguageItemCollector<'tcx> {
                 }
                 // Known lang item with attribute on incorrect target.
                 Some((_, expected_target)) => {
-                    struct_span_err!(
-                        self.tcx.sess,
+                    self.tcx.sess.emit_err(LangItemOnIncorrectTarget {
                         span,
-                        E0718,
-                        "`{}` language item must be applied to a {}",
-                        value,
+                        name: value,
                         expected_target,
-                    )
-                    .span_label(
-                        span,
-                        format!(
-                            "attribute should be applied to a {}, not a {}",
-                            expected_target, actual_target,
-                        ),
-                    )
-                    .emit();
+                        actual_target,
+                    });
                 }
                 // Unknown lang item.
                 _ => {
-                    struct_span_err!(
-                        self.tcx.sess,
+                    self.tcx.sess.emit_err(UnknownLangItem {
                         span,
-                        E0522,
-                        "definition of an unknown language item: `{}`",
-                        value
-                    )
-                    .span_label(span, format!("definition of unknown language item `{}`", value))
-                    .emit();
+                        name: value,
+                    });
                 }
             }
         }

From 0315d7c9dbc33164ce8d1a7ad0464fa695a59399 Mon Sep 17 00:00:00 2001
From: rdvdev2 
Date: Fri, 2 Sep 2022 04:54:42 +0200
Subject: [PATCH 114/175] Migrate derivable diagnostics in check_attr.rs

---
 .../rustc_error_messages/locales/en-US/passes.ftl  |  2 ++
 compiler/rustc_passes/src/check_attr.rs            | 14 ++++++--------
 compiler/rustc_passes/src/errors.rs                | 11 +++++++++++
 3 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 6512af1d14c8..9a3ea51c778d 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -217,6 +217,8 @@ passes_debug_visualizer_invalid = invalid argument
     .note_2 = OR
     .note_3 = expected: `gdb_script_file = "..."`
 
+passes_debug_visualizer_unreadable = couldn't read {$file}: {$error}
+
 passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn`
     .label = not a `const fn`
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 87433538512b..864ce751588f 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -4,7 +4,7 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use crate::errors;
+use crate::errors::{self, DebugVisualizerUnreadable};
 use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan};
@@ -1863,13 +1863,11 @@ impl CheckAttrVisitor<'_> {
         match std::fs::File::open(&file) {
             Ok(_) => true,
             Err(err) => {
-                self.tcx
-                    .sess
-                    .struct_span_err(
-                        meta_item.span,
-                        &format!("couldn't read {}: {}", file.display(), err),
-                    )
-                    .emit();
+                self.tcx.sess.emit_err(DebugVisualizerUnreadable {
+                    span: meta_item.span,
+                    file: &file,
+                    error: err,
+                } );
                 false
             }
         }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index cd05784cd53b..5730e9db6668 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1,3 +1,5 @@
+use std::{io::Error, path::Path};
+
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::Target;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -527,6 +529,15 @@ pub struct DebugVisualizerInvalid {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(passes::debug_visualizer_unreadable)]
+pub struct DebugVisualizerUnreadable<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub file: &'a Path,
+    pub error: Error,
+}
+
 #[derive(Diagnostic)]
 #[diag(passes::rustc_allow_const_fn_unstable)]
 pub struct RustcAllowConstFnUnstable {

From 2c3351c9a64caf76775c1335201a4762f5fdeaf8 Mon Sep 17 00:00:00 2001
From: rdvdev2 
Date: Fri, 2 Sep 2022 05:19:03 +0200
Subject: [PATCH 115/175] Migrate InvalidAttrAtCrateLevel

Co-authored-by: Nathan Stocks 
Co-authored-by: rdvdev2 
---
 .../locales/en-US/passes.ftl                  |  3 ++
 compiler/rustc_passes/src/check_attr.rs       | 28 ++++------------
 compiler/rustc_passes/src/errors.rs           | 32 ++++++++++++++++++-
 compiler/rustc_passes/src/lang_items.rs       |  7 ++--
 4 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 9a3ea51c778d..c1c2f379fa52 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -290,3 +290,6 @@ passes_unknown_lang_item = definition of an unknown language item: `{$name}`
     .label = definition of unknown language item `{$name}`
 
 passes_local_duplicate_lang_item = found duplicate lang item `{$name}`
+
+passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level
+    .suggestion = perhaps you meant to use an outer attribute
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 864ce751588f..2a9578e8ce32 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -4,7 +4,7 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use crate::errors::{self, DebugVisualizerUnreadable};
+use crate::errors::{self, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel};
 use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan};
@@ -1867,7 +1867,7 @@ impl CheckAttrVisitor<'_> {
                     span: meta_item.span,
                     file: &file,
                     error: err,
-                } );
+                });
                 false
             }
         }
@@ -2178,25 +2178,11 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
         if attr.style == AttrStyle::Inner {
             for attr_to_check in ATTRS_TO_CHECK {
                 if attr.has_name(*attr_to_check) {
-                    let mut err = tcx.sess.struct_span_err(
-                        attr.span,
-                        &format!(
-                            "`{}` attribute cannot be used at crate level",
-                            attr_to_check.to_ident_string()
-                        ),
-                    );
-                    // Only emit an error with a suggestion if we can create a
-                    // string out of the attribute span
-                    if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) {
-                        let replacement = src.replace("#!", "#");
-                        err.span_suggestion_verbose(
-                            attr.span,
-                            "perhaps you meant to use an outer attribute",
-                            replacement,
-                            rustc_errors::Applicability::MachineApplicable,
-                        );
-                    }
-                    err.emit();
+                    tcx.sess.emit_err(InvalidAttrAtCrateLevel {
+                        span: attr.span,
+                        snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(),
+                        name: *attr_to_check,
+                    });
                 }
             }
         }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 5730e9db6668..9b8eebd6be0b 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1,6 +1,6 @@
 use std::{io::Error, path::Path};
 
-use rustc_errors::{Applicability, MultiSpan};
+use rustc_errors::{Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan};
 use rustc_hir::Target;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
@@ -714,3 +714,33 @@ pub struct UnknownLangItem {
     pub span: Span,
     pub name: Symbol,
 }
+
+pub struct InvalidAttrAtCrateLevel {
+    pub span: Span,
+    pub snippet: Option,
+    pub name: Symbol,
+}
+
+impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
+    fn into_diagnostic(
+        self,
+        handler: &'_ rustc_errors::Handler,
+    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag =
+            handler.struct_err(rustc_errors::fluent::passes::invalid_attr_at_crate_level);
+        diag.set_span(self.span);
+        diag.set_arg("name", self.name);
+        // Only emit an error with a suggestion if we can create a string out
+        // of the attribute span
+        if let Some(src) = self.snippet {
+            let replacement = src.replace("#!", "#");
+            diag.span_suggestion_verbose(
+                self.span,
+                rustc_errors::fluent::passes::suggestion,
+                replacement,
+                rustc_errors::Applicability::MachineApplicable,
+            );
+        }
+        diag
+    }
+}
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 98ff625d0946..24657372486f 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -7,8 +7,8 @@
 //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
 //! * Functions called by the compiler itself.
 
-use crate::errors::{LangItemOnIncorrectTarget, UnknownLangItem};
 use crate::check_attr::target_from_impl_item;
+use crate::errors::{LangItemOnIncorrectTarget, UnknownLangItem};
 use crate::weak_lang_items;
 
 use rustc_errors::{pluralize, struct_span_err};
@@ -52,10 +52,7 @@ impl<'tcx> LanguageItemCollector<'tcx> {
                 }
                 // Unknown lang item.
                 _ => {
-                    self.tcx.sess.emit_err(UnknownLangItem {
-                        span,
-                        name: value,
-                    });
+                    self.tcx.sess.emit_err(UnknownLangItem { span, name: value });
                 }
             }
         }

From c24a87315af884680332f850753b3eeef18c22c8 Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Wed, 21 Sep 2022 14:05:15 -0600
Subject: [PATCH 116/175] always put ftl message on next line, resolve all but
 1 output comparison error

---
 .../locales/en-US/passes.ftl                  | 269 ++++++++++++------
 1 file changed, 180 insertions(+), 89 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index c1c2f379fa52..bd6a973e9163 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -10,88 +10,119 @@ passes_outer_crate_level_attr =
 passes_inner_crate_level_attr =
     crate-level attribute should be in the root module
 
-passes_ignored_attr_with_macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs
+passes_ignored_attr_with_macro =
+    `#[{$sym}]` is ignored on struct fields, match arms and macro defs
     .warn = {-passes_previously_accepted}
     .note = {-passes_see_issue(issue: "80564")}
 
-passes_ignored_attr = `#[{$sym}]` is ignored on struct fields and match arms
+passes_ignored_attr =
+    `#[{$sym}]` is ignored on struct fields and match arms
     .warn = {-passes_previously_accepted}
     .note = {-passes_see_issue(issue: "80564")}
 
-passes_inline_ignored_function_prototype = `#[inline]` is ignored on function prototypes
+passes_inline_ignored_function_prototype =
+    `#[inline]` is ignored on function prototypes
 
-passes_inline_ignored_constants = `#[inline]` is ignored on constants
+passes_inline_ignored_constants =
+    `#[inline]` is ignored on constants
     .warn = {-passes_previously_accepted}
     .note = {-passes_see_issue(issue: "65833")}
 
-passes_inline_not_fn_or_closure = attribute should be applied to function or closure
+passes_inline_not_fn_or_closure =
+    attribute should be applied to function or closure
     .label = not a function or closure
 
-passes_no_coverage_ignored_function_prototype = `#[no_coverage]` is ignored on function prototypes
+passes_no_coverage_ignored_function_prototype =
+    `#[no_coverage]` is ignored on function prototypes
 
 passes_no_coverage_propagate =
     `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
 
-passes_no_coverage_fn_defn = `#[no_coverage]` may only be applied to function definitions
+passes_no_coverage_fn_defn =
+    `#[no_coverage]` may only be applied to function definitions
 
-passes_no_coverage_not_coverable = `#[no_coverage]` must be applied to coverable code
+passes_no_coverage_not_coverable =
+    `#[no_coverage]` must be applied to coverable code
     .label = not coverable code
 
-passes_should_be_applied_to_fn = attribute should be applied to a function definition
+passes_should_be_applied_to_fn =
+    attribute should be applied to a function definition
     .label = not a function definition
 
-passes_naked_tracked_caller = cannot use `#[track_caller]` with `#[naked]`
+passes_naked_tracked_caller =
+    cannot use `#[track_caller]` with `#[naked]`
 
-passes_should_be_applied_to_struct_enum = attribute should be applied to a struct or enum
+passes_should_be_applied_to_struct_enum =
+    attribute should be applied to a struct or enum
     .label = not a struct or enum
 
-passes_should_be_applied_to_trait = attribute should be applied to a trait
+passes_should_be_applied_to_trait =
+    attribute should be applied to a trait
     .label = not a trait
 
-passes_target_feature_on_statement = {passes_should_be_applied_to_fn}
+passes_target_feature_on_statement =
+    {passes_should_be_applied_to_fn}
     .warn = {-passes_previously_accepted}
     .label = {passes_should_be_applied_to_fn.label}
 
-passes_should_be_applied_to_static = attribute should be applied to a static
+passes_should_be_applied_to_static =
+    attribute should be applied to a static
     .label = not a static
 
-passes_doc_expect_str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
+passes_doc_expect_str =
+    doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
 
-passes_doc_alias_empty = {$attr_str} attribute cannot have empty value
+passes_doc_alias_empty =
+    {$attr_str} attribute cannot have empty value
 
-passes_doc_alias_bad_char = {$char_} character isn't allowed in {$attr_str}
+passes_doc_alias_bad_char =
+    {$char_} character isn't allowed in {$attr_str}
 
-passes_doc_alias_start_end = {$attr_str} cannot start or end with ' '
+passes_doc_alias_start_end =
+    {$attr_str} cannot start or end with ' '
 
-passes_doc_alias_bad_location = {$attr_str} isn't allowed on {$location}
+passes_doc_alias_bad_location =
+    {$attr_str} isn't allowed on {$location}
 
-passes_doc_alias_not_an_alias = {$attr_str} is the same as the item's name
+passes_doc_alias_not_an_alias =
+    {$attr_str} is the same as the item's name
 
 passes_doc_alias_duplicated = doc alias is duplicated
     .label = first defined here
 
-passes_doc_alias_not_string_literal = `#[doc(alias("a"))]` expects string literals
+passes_doc_alias_not_string_literal =
+    `#[doc(alias("a"))]` expects string literals
 
 passes_doc_alias_malformed =
     doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
 
-passes_doc_keyword_empty_mod = `#[doc(keyword = "...")]` should be used on empty modules
+passes_doc_keyword_empty_mod =
+    `#[doc(keyword = "...")]` should be used on empty modules
 
-passes_doc_keyword_not_mod = `#[doc(keyword = "...")]` should be used on modules
+passes_doc_keyword_not_mod =
+    `#[doc(keyword = "...")]` should be used on modules
 
-passes_doc_keyword_invalid_ident = `{$doc_keyword}` is not a valid identifier
+passes_doc_keyword_invalid_ident =
+    `{$doc_keyword}` is not a valid identifier
 
 passes_doc_fake_variadic_not_valid =
     `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity
 
-passes_doc_keyword_only_impl = `#[doc(keyword = "...")]` should be used on impl blocks
+passes_doc_keyword_only_impl =
+    `#[doc(keyword = "...")]` should be used on impl blocks
 
-passes_doc_inline_conflict_first = this attribute...
-passes_doc_inline_conflict_second = ...conflicts with this attribute
-passes_doc_inline_conflict = conflicting doc inlining attributes
+passes_doc_inline_conflict_first =
+    this attribute...
+
+passes_doc_inline_conflict_second =
+    {"."}..conflicts with this attribute
+
+passes_doc_inline_conflict =
+    conflicting doc inlining attributes
     .help = remove one of the conflicting attributes
 
-passes_doc_inline_only_use = this attribute can only be applied to a `use` item
+passes_doc_inline_only_use =
+    this attribute can only be applied to a `use` item
     .label = only applicable on `use` items
     .not_a_use_item_label = not a `use` item
     .note = read  for more information
@@ -99,30 +130,39 @@ passes_doc_inline_only_use = this attribute can only be applied to a `use` item
 passes_doc_attr_not_crate_level =
     `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
 
-passes_attr_crate_level = this attribute can only be applied at the crate level
+passes_attr_crate_level =
+    this attribute can only be applied at the crate level
     .suggestion = to apply to the crate, use an inner attribute
     .help = to apply to the crate, use an inner attribute
     .note = read  for more information
 
-passes_doc_test_unknown = unknown `doc(test)` attribute `{$path}`
+passes_doc_test_unknown =
+    unknown `doc(test)` attribute `{$path}`
 
-passes_doc_test_takes_list = `#[doc(test(...)]` takes a list of attributes
+passes_doc_test_takes_list =
+    `#[doc(test(...)]` takes a list of attributes
 
-passes_doc_primitive = `doc(primitive)` should never have been stable
+passes_doc_primitive =
+    `doc(primitive)` should never have been stable
 
-passes_doc_test_unknown_any = unknown `doc` attribute `{$path}`
+passes_doc_test_unknown_any =
+    unknown `doc` attribute `{$path}`
 
-passes_doc_test_unknown_spotlight = unknown `doc` attribute `{$path}`
+passes_doc_test_unknown_spotlight =
+    unknown `doc` attribute `{$path}`
     .note = `doc(spotlight)` was renamed to `doc(notable_trait)`
     .suggestion = use `notable_trait` instead
     .no_op_note = `doc(spotlight)` is now a no-op
 
-passes_doc_test_unknown_include = unknown `doc` attribute `{$path}`
+passes_doc_test_unknown_include =
+    unknown `doc` attribute `{$path}`
     .suggestion = use `doc = include_str!` instead
 
-passes_doc_invalid = invalid `doc` attribute
+passes_doc_invalid =
+    invalid `doc` attribute
 
-passes_pass_by_value = `pass_by_value` attribute should be applied to a struct, enum or type alias
+passes_pass_by_value =
+    `pass_by_value` attribute should be applied to a struct, enum or type alias
     .label = is not a struct, enum or type alias
 
 passes_allow_incoherent_impl =
@@ -137,42 +177,54 @@ passes_must_use_async =
     `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
     .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use`
 
-passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target}
+passes_must_use_no_effect =
+    `#[must_use]` has no effect when applied to {$article} {$target}
 
-passes_must_not_suspend = `must_not_suspend` attribute should be applied to a struct, enum, or trait
+passes_must_not_suspend =
+    `must_not_suspend` attribute should be applied to a struct, enum, or trait
     .label = is not a struct, enum, or trait
 
-passes_cold = {passes_should_be_applied_to_fn}
+passes_cold =
+    {passes_should_be_applied_to_fn}
     .warn = {-passes_previously_accepted}
     .label = {passes_should_be_applied_to_fn.label}
 
-passes_link = attribute should be applied to an `extern` block with non-Rust ABI
+passes_link =
+    attribute should be applied to an `extern` block with non-Rust ABI
     .warn = {-passes_previously_accepted}
     .label = not an `extern` block
 
-passes_link_name = attribute should be applied to a foreign function or static
+passes_link_name =
+    attribute should be applied to a foreign function or static
     .warn = {-passes_previously_accepted}
     .label = not a foreign function or static
     .help = try `#[link(name = "{$value}")]` instead
 
-passes_no_link = attribute should be applied to an `extern crate` item
+passes_no_link =
+    attribute should be applied to an `extern crate` item
     .label = not an `extern crate` item
 
-passes_export_name = attribute should be applied to a free function, impl method or static
+passes_export_name =
+    attribute should be applied to a free function, impl method or static
     .label = not a free function, impl method or static
 
-passes_rustc_layout_scalar_valid_range_not_struct = attribute should be applied to a struct
+passes_rustc_layout_scalar_valid_range_not_struct =
+    attribute should be applied to a struct
     .label = not a struct
 
-passes_rustc_layout_scalar_valid_range_arg = expected exactly one integer literal argument
+passes_rustc_layout_scalar_valid_range_arg =
+    expected exactly one integer literal argument
 
-passes_rustc_legacy_const_generics_only = #[rustc_legacy_const_generics] functions must only have const generics
+passes_rustc_legacy_const_generics_only =
+    #[rustc_legacy_const_generics] functions must only have const generics
     .label = non-const generic parameter
 
-passes_rustc_legacy_const_generics_index = #[rustc_legacy_const_generics] must have one index for each generic parameter
+passes_rustc_legacy_const_generics_index =
+    #[rustc_legacy_const_generics] must have one index for each generic parameter
     .label = generic parameters
 
-passes_rustc_legacy_const_generics_index_exceed = index exceeds number of arguments
+passes_rustc_legacy_const_generics_index_exceed =
+    index exceeds number of arguments
     .label = there {$arg_count ->
         [one] is
         *[other] are
@@ -181,115 +233,154 @@ passes_rustc_legacy_const_generics_index_exceed = index exceeds number of argume
         *[other] arguments
     }
 
-passes_rustc_legacy_const_generics_index_negative = arguments should be non-negative integers
+passes_rustc_legacy_const_generics_index_negative =
+    arguments should be non-negative integers
 
-passes_rustc_dirty_clean = attribute requires -Z query-dep-graph to be enabled
+passes_rustc_dirty_clean =
+    attribute requires -Z query-dep-graph to be enabled
 
-passes_link_section = attribute should be applied to a function or static
+passes_link_section =
+    attribute should be applied to a function or static
     .warn = {-passes_previously_accepted}
     .label = not a function or static
 
-passes_no_mangle_foreign = `#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
+passes_no_mangle_foreign =
+    `#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
     .warn = {-passes_previously_accepted}
     .label = foreign {$foreign_item_kind}
     .note = symbol names in extern blocks are not mangled
     .suggestion = remove this attribute
 
-passes_no_mangle = attribute should be applied to a free function, impl method or static
+passes_no_mangle =
+    attribute should be applied to a free function, impl method or static
     .warn = {-passes_previously_accepted}
     .label = not a free function, impl method or static
 
-passes_repr_ident = meta item in `repr` must be an identifier
+passes_repr_ident =
+    meta item in `repr` must be an identifier
 
-passes_repr_conflicting = conflicting representation hints
+passes_repr_conflicting =
+    conflicting representation hints
 
-passes_used_static = attribute must be applied to a `static` variable
+passes_used_static =
+    attribute must be applied to a `static` variable
 
-passes_used_compiler_linker = `used(compiler)` and `used(linker)` can't be used together
+passes_used_compiler_linker =
+    `used(compiler)` and `used(linker)` can't be used together
 
-passes_allow_internal_unstable = attribute should be applied to a macro
+passes_allow_internal_unstable =
+    attribute should be applied to a macro
     .label = not a macro
 
-passes_debug_visualizer_placement = attribute should be applied to a module
+passes_debug_visualizer_placement =
+    attribute should be applied to a module
 
-passes_debug_visualizer_invalid = invalid argument
+passes_debug_visualizer_invalid =
+    invalid argument
     .note_1 = expected: `natvis_file = "..."`
     .note_2 = OR
     .note_3 = expected: `gdb_script_file = "..."`
 
-passes_debug_visualizer_unreadable = couldn't read {$file}: {$error}
+passes_debug_visualizer_unreadable =
+    couldn't read {$file}: {$error}
 
-passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn`
+passes_rustc_allow_const_fn_unstable =
+    attribute should be applied to `const fn`
     .label = not a `const fn`
 
-passes_rustc_std_internal_symbol = attribute should be applied to functions or statics
+passes_rustc_std_internal_symbol =
+    attribute should be applied to functions or statics
     .label = not a function or static
 
-passes_const_trait = attribute should be applied to a trait
+passes_const_trait =
+    attribute should be applied to a trait
 
-passes_stability_promotable = attribute cannot be applied to an expression
+passes_stability_promotable =
+    attribute cannot be applied to an expression
 
-passes_deprecated = attribute is ignored here
+passes_deprecated =
+    attribute is ignored here
 
-passes_macro_use = `#[{$name}]` only has an effect on `extern crate` and modules
+passes_macro_use =
+    `#[{$name}]` only has an effect on `extern crate` and modules
 
-passes_macro_export = `#[macro_export]` only has an effect on macro definitions
+passes_macro_export =
+    `#[macro_export]` only has an effect on macro definitions
 
-passes_plugin_registrar = `#[plugin_registrar]` only has an effect on functions
+passes_plugin_registrar =
+    `#[plugin_registrar]` only has an effect on functions
 
-passes_unused_empty_lints_note = attribute `{$name}` with an empty list has no effect
+passes_unused_empty_lints_note =
+    attribute `{$name}` with an empty list has no effect
 
-passes_unused_no_lints_note = attribute `{$name}` without any lints has no effect
+passes_unused_no_lints_note =
+    attribute `{$name}` without any lints has no effect
 
 passes_unused_default_method_body_const_note =
     `default_method_body_is_const` has been replaced with `#[const_trait]` on traits
 
-passes_unused = unused attribute
+passes_unused =
+    unused attribute
     .suggestion = remove this attribute
 
-passes_non_exported_macro_invalid_attrs = attribute should be applied to function or closure
+passes_non_exported_macro_invalid_attrs =
+    attribute should be applied to function or closure
     .label = not a function or closure
 
-passes_unused_duplicate = unused attribute
+passes_unused_duplicate =
+    unused attribute
     .suggestion = remove this attribute
     .note = attribute also specified here
     .warn = {-passes_previously_accepted}
 
-passes_unused_multiple = multiple `{$name}` attributes
+passes_unused_multiple =
+    multiple `{$name}` attributes
     .suggestion = remove this attribute
     .note = attribute also specified here
 
-passes_rustc_lint_opt_ty = `#[rustc_lint_opt_ty]` should be applied to a struct
+passes_rustc_lint_opt_ty =
+    `#[rustc_lint_opt_ty]` should be applied to a struct
     .label = not a struct
 
-passes_rustc_lint_opt_deny_field_access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field
+passes_rustc_lint_opt_deny_field_access =
+    `#[rustc_lint_opt_deny_field_access]` should be applied to a field
     .label = not a field
 
-passes_link_ordinal = attribute should be applied to a foreign function or static
+passes_link_ordinal =
+    attribute should be applied to a foreign function or static
     .label = not a foreign function or static
 
-passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to macro definitions
+passes_collapse_debuginfo =
+    `collapse_debuginfo` attribute should be applied to macro definitions
     .label = not a macro definition
 
-passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect
+passes_deprecated_annotation_has_no_effect =
+    this `#[deprecated]` annotation has no effect
     .suggestion = remove the unnecessary deprecation attribute
     
-passes_missing_panic_handler = `#[panic_handler]` function required, but not found
+passes_missing_panic_handler =
+    `#[panic_handler]` function required, but not found
 
-passes_missing_alloc_error_handler = `#[alloc_error_handler]` function required, but not found
+passes_missing_alloc_error_handler =
+    `#[alloc_error_handler]` function required, but not found
     .note = use `#![feature(default_alloc_error_handler)]` for a default error handler
 
-passes_missing_lang_item = language item required, but not found: `{$name}`
+passes_missing_lang_item =
+    language item required, but not found: `{$name}`
     .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
     .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config`
 
-passes_lang_item_on_incorrect_target = `{$name}` language item must be applied to a {$expected_target}
+passes_lang_item_on_incorrect_target =
+    `{$name}` language item must be applied to a {$expected_target}
     .label = attribute should be applied to a {$expected_target}, not a {$actual_target}
 
-passes_unknown_lang_item = definition of an unknown language item: `{$name}`
+passes_unknown_lang_item =
+    definition of an unknown language item: `{$name}`
     .label = definition of unknown language item `{$name}`
 
-passes_local_duplicate_lang_item = found duplicate lang item `{$name}`
+passes_local_duplicate_lang_item =
+    found duplicate lang item `{$name}`
 
-passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level
+passes_invalid_attr_at_crate_level =
+    `{$name}` attribute cannot be used at crate level
     .suggestion = perhaps you meant to use an outer attribute

From b8e03cfa55d6133f8fc1fd3a82a7e686a9cf006e Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Wed, 21 Sep 2022 22:30:14 -0600
Subject: [PATCH 117/175] use consistent names

---
 compiler/rustc_passes/src/check_attr.rs | 4 ++--
 compiler/rustc_passes/src/lang_items.rs | 8 ++++----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 2a9578e8ce32..18e1233fa84f 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1862,11 +1862,11 @@ impl CheckAttrVisitor<'_> {
 
         match std::fs::File::open(&file) {
             Ok(_) => true,
-            Err(err) => {
+            Err(error) => {
                 self.tcx.sess.emit_err(DebugVisualizerUnreadable {
                     span: meta_item.span,
                     file: &file,
-                    error: err,
+                    error,
                 });
                 false
             }
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 24657372486f..2b090e036fe9 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -35,8 +35,8 @@ impl<'tcx> LanguageItemCollector<'tcx> {
 
     fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
         let attrs = self.tcx.hir().attrs(hir_id);
-        if let Some((value, span)) = extract(&attrs) {
-            match ITEM_REFS.get(&value).cloned() {
+        if let Some((name, span)) = extract(&attrs) {
+            match ITEM_REFS.get(&name).cloned() {
                 // Known lang item with attribute on correct target.
                 Some((item_index, expected_target)) if actual_target == expected_target => {
                     self.collect_item_extended(item_index, hir_id, span);
@@ -45,14 +45,14 @@ impl<'tcx> LanguageItemCollector<'tcx> {
                 Some((_, expected_target)) => {
                     self.tcx.sess.emit_err(LangItemOnIncorrectTarget {
                         span,
-                        name: value,
+                        name,
                         expected_target,
                         actual_target,
                     });
                 }
                 // Unknown lang item.
                 _ => {
-                    self.tcx.sess.emit_err(UnknownLangItem { span, name: value });
+                    self.tcx.sess.emit_err(UnknownLangItem { span, name });
                 }
             }
         }

From 1222541cfd69386d0383c37042d8bbfd9f2ad0a3 Mon Sep 17 00:00:00 2001
From: Diego de Oliveira 
Date: Wed, 14 Sep 2022 15:03:12 -0300
Subject: [PATCH 118/175] resolve merge conflict from cherry-picking
 6a47326a0452cc8d5cb57676508b5469d648c67f

---
 compiler/rustc_error_messages/locales/en-US/passes.ftl | 3 +++
 compiler/rustc_passes/src/errors.rs                    | 7 +++++++
 2 files changed, 10 insertions(+)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index bd6a973e9163..0c98f567276b 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -384,3 +384,6 @@ passes_local_duplicate_lang_item =
 passes_invalid_attr_at_crate_level =
     `{$name}` attribute cannot be used at crate level
     .suggestion = perhaps you meant to use an outer attribute
+
+passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect
+    .suggestion = remove the unnecessary deprecation attribute
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 9b8eebd6be0b..10deb4db55ff 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -744,3 +744,10 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
         diag
     }
 }
+
+#[derive(LintDiagnostic)]
+#[diag(passes::deprecated_annotation_has_no_effect)]
+pub struct DeprecatedAnnotationHasNoEffect {
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    pub span: Span,
+}

From c103c3059f5481f60ae43465fce0646aa2c0dfa3 Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Wed, 21 Sep 2022 22:49:30 -0600
Subject: [PATCH 119/175] migrate the rest of weak_lang_items.rs to
 translateable diagnostics

---
 .../rustc_error_messages/locales/en-US/passes.ftl |  6 +++---
 compiler/rustc_passes/src/errors.rs               | 15 ++++++++-------
 compiler/rustc_passes/src/weak_lang_items.rs      | 14 ++++----------
 3 files changed, 15 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 0c98f567276b..7dddc6e10b65 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -358,6 +358,9 @@ passes_deprecated_annotation_has_no_effect =
     this `#[deprecated]` annotation has no effect
     .suggestion = remove the unnecessary deprecation attribute
     
+passes_unknown_external_lang_item =
+    unknown external lang item: `{$lang_item}`
+
 passes_missing_panic_handler =
     `#[panic_handler]` function required, but not found
 
@@ -384,6 +387,3 @@ passes_local_duplicate_lang_item =
 passes_invalid_attr_at_crate_level =
     `{$name}` attribute cannot be used at crate level
     .suggestion = perhaps you meant to use an outer attribute
-
-passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect
-    .suggestion = remove the unnecessary deprecation attribute
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 10deb4db55ff..0fabbb206cf9 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -678,6 +678,14 @@ pub struct DeprecatedAnnotationHasNoEffect {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(passes::unknown_external_lang_item, code = "E0264")]
+pub struct UnknownExternLangItem {
+    #[primary_span]
+    pub span: Span,
+    pub lang_item: Symbol,
+}
+
 #[derive(Diagnostic)]
 #[diag(passes::missing_panic_handler)]
 pub struct MissingPanicHandler;
@@ -744,10 +752,3 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
         diag
     }
 }
-
-#[derive(LintDiagnostic)]
-#[diag(passes::deprecated_annotation_has_no_effect)]
-pub struct DeprecatedAnnotationHasNoEffect {
-    #[suggestion(applicability = "machine-applicable", code = "")]
-    pub span: Span,
-}
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 2345de74bdfb..0d2745fb5f40 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -1,14 +1,15 @@
 //! Validity checking for weak lang items
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
 use rustc_hir::lang_items::{self, LangItem};
 use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
 use rustc_middle::middle::lang_items::required;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
 
-use crate::errors::{MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler};
+use crate::errors::{
+    MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler, UnknownExternLangItem,
+};
 
 /// Checks the crate for usage of weak lang items, returning a vector of all the
 /// language items required by this crate, but not defined yet.
@@ -33,14 +34,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem
                 }
             } else {
                 let span = tcx.def_span(id.def_id);
-                struct_span_err!(
-                    tcx.sess,
-                    span,
-                    E0264,
-                    "unknown external lang item: `{}`",
-                    lang_item
-                )
-                .emit();
+                tcx.sess.emit_err(UnknownExternLangItem { span, lang_item });
             }
         }
     }

From 1e86226e9d6720b5c60c51d75b0a3f038d8bc5f5 Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Wed, 21 Sep 2022 22:55:29 -0600
Subject: [PATCH 120/175] migrate debugger_visualizer.rs to translateable
 diagnostics

---
 compiler/rustc_passes/src/debugger_visualizer.rs | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index e08683fe23b2..253b0a88e48a 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -13,6 +13,8 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
 
 use std::sync::Arc;
 
+use crate::errors::DebugVisualizerUnreadable;
+
 fn check_for_debugger_visualizer<'tcx>(
     tcx: TyCtxt<'tcx>,
     hir_id: HirId,
@@ -54,13 +56,12 @@ fn check_for_debugger_visualizer<'tcx>(
                     debugger_visualizers
                         .insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type));
                 }
-                Err(err) => {
-                    tcx.sess
-                        .struct_span_err(
-                            meta_item.span,
-                            &format!("couldn't read {}: {}", file.display(), err),
-                        )
-                        .emit();
+                Err(error) => {
+                    tcx.sess.emit_err(DebugVisualizerUnreadable {
+                        span: meta_item.span,
+                        file: &file,
+                        error,
+                    });
                 }
             }
         }

From f8ebc72b4aa138772434039950126f2c7f07a3f4 Mon Sep 17 00:00:00 2001
From: David Wood 
Date: Thu, 1 Sep 2022 11:40:43 +0100
Subject: [PATCH 121/175] errors: add `emit_note`/`create_note`

Add `Noted` marker struct that implements `EmissionGuarantee` so that
`emit_note` and `create_note` can be implemented for struct diagnostics.

Signed-off-by: David Wood 
---
 .../rustc_errors/src/diagnostic_builder.rs    | 50 +++++++++++++++++++
 compiler/rustc_errors/src/lib.rs              |  8 ++-
 compiler/rustc_session/src/parse.rs           | 13 ++++-
 compiler/rustc_session/src/session.rs         | 11 +++-
 4 files changed, 78 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index bbe6435be59f..9b41234dcfb6 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -255,6 +255,56 @@ impl EmissionGuarantee for () {
     }
 }
 
+/// Marker type which enables implementation of `create_note` and `emit_note` functions for
+/// note-without-error struct diagnostics.
+#[derive(Copy, Clone)]
+pub struct Noted;
+
+impl<'a> DiagnosticBuilder<'a, Noted> {
+    /// Convenience function for internal use, clients should use one of the
+    /// `struct_*` methods on [`Handler`].
+    pub(crate) fn new_note(handler: &'a Handler, message: impl Into) -> Self {
+        let diagnostic = Diagnostic::new_with_code(Level::Note, None, message);
+        Self::new_diagnostic_note(handler, diagnostic)
+    }
+
+    /// Creates a new `DiagnosticBuilder` with an already constructed
+    /// diagnostic.
+    pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
+        debug!("Created new diagnostic");
+        Self {
+            inner: DiagnosticBuilderInner {
+                state: DiagnosticBuilderState::Emittable(handler),
+                diagnostic: Box::new(diagnostic),
+            },
+            _marker: PhantomData,
+        }
+    }
+}
+
+impl EmissionGuarantee for Noted {
+    fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
+        match db.inner.state {
+            // First `.emit()` call, the `&Handler` is still available.
+            DiagnosticBuilderState::Emittable(handler) => {
+                db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
+                handler.emit_diagnostic(&mut db.inner.diagnostic);
+            }
+            // `.emit()` was previously called, disallowed from repeating it.
+            DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
+        }
+
+        Noted
+    }
+
+    fn make_diagnostic_builder(
+        handler: &Handler,
+        msg: impl Into,
+    ) -> DiagnosticBuilder<'_, Self> {
+        DiagnosticBuilder::new_note(handler, msg)
+    }
+}
+
 impl<'a> DiagnosticBuilder<'a, !> {
     /// Convenience function for internal use, clients should use one of the
     /// `struct_*` methods on [`Handler`].
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 94a493992e59..a7fe280bc20e 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -374,7 +374,7 @@ pub use diagnostic::{
     AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay,
     DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
 };
-pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee};
+pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
 use std::backtrace::Backtrace;
 
 /// A handler deals with errors and other compiler output.
@@ -988,7 +988,11 @@ impl Handler {
     }
 
     pub fn has_errors(&self) -> Option {
-        if self.inner.borrow().has_errors() { Some(ErrorGuaranteed(())) } else { None }
+        if self.inner.borrow().has_errors() {
+            Some(ErrorGuaranteed(()))
+        } else {
+            None
+        }
     }
     pub fn has_errors_or_lint_errors(&self) -> Option {
         if self.inner.borrow().has_errors_or_lint_errors() {
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 2c3d8d5283b5..a199947ebed0 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
 use rustc_errors::{
     fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
-    EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, StashKey,
+    EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey,
 };
 use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
 use rustc_span::edition::Edition;
@@ -354,6 +354,17 @@ impl ParseSess {
         self.create_warning(warning).emit()
     }
 
+    pub fn create_note<'a>(
+        &'a self,
+        note: impl IntoDiagnostic<'a, Noted>,
+    ) -> DiagnosticBuilder<'a, Noted> {
+        note.into_diagnostic(&self.span_diagnostic)
+    }
+
+    pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
+        self.create_note(note).emit()
+    }
+
     pub fn create_fatal<'a>(
         &'a self,
         fatal: impl IntoDiagnostic<'a, !>,
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 5926cdc9dad9..beb22ab3eb95 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -28,7 +28,7 @@ use rustc_errors::json::JsonEmitter;
 use rustc_errors::registry::Registry;
 use rustc_errors::{
     error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
-    ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan,
+    ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
 };
 use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
@@ -489,6 +489,15 @@ impl Session {
     pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
         self.parse_sess.emit_warning(warning)
     }
+    pub fn create_note<'a>(
+        &'a self,
+        note: impl IntoDiagnostic<'a, Noted>,
+    ) -> DiagnosticBuilder<'a, Noted> {
+        self.parse_sess.create_note(note)
+    }
+    pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
+        self.parse_sess.emit_note(note)
+    }
     pub fn create_fatal<'a>(
         &'a self,
         fatal: impl IntoDiagnostic<'a, !>,

From 3a748330af35ec9da4b07f55b78e8f08f2af0888 Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Thu, 22 Sep 2022 10:15:51 -0600
Subject: [PATCH 122/175] use cherry-picked commit from #100754 to emit note
 without error

---
 compiler/rustc_error_messages/locales/en-US/passes.ftl | 6 ++++--
 compiler/rustc_passes/src/errors.rs                    | 5 ++++-
 compiler/rustc_passes/src/weak_lang_items.rs           | 6 ++++--
 3 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 7dddc6e10b65..49cd2ee17588 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -364,9 +364,11 @@ passes_unknown_external_lang_item =
 passes_missing_panic_handler =
     `#[panic_handler]` function required, but not found
 
-passes_missing_alloc_error_handler =
+passes_alloc_func_required =
     `#[alloc_error_handler]` function required, but not found
-    .note = use `#![feature(default_alloc_error_handler)]` for a default error handler
+
+passes_missing_alloc_error_handler =
+    use `#![feature(default_alloc_error_handler)]` for a default error handler
 
 passes_missing_lang_item =
     language item required, but not found: `{$name}`
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 0fabbb206cf9..26190af03587 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -690,9 +690,12 @@ pub struct UnknownExternLangItem {
 #[diag(passes::missing_panic_handler)]
 pub struct MissingPanicHandler;
 
+#[derive(Diagnostic)]
+#[diag(passes::alloc_func_required)]
+pub struct AllocFuncRequired;
+
 #[derive(Diagnostic)]
 #[diag(passes::missing_alloc_error_handler)]
-#[note]
 pub struct MissingAllocErrorHandler;
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 0d2745fb5f40..92024989a75e 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -8,7 +8,8 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
 
 use crate::errors::{
-    MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler, UnknownExternLangItem,
+    AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler,
+    UnknownExternLangItem,
 };
 
 /// Checks the crate for usage of weak lang items, returning a vector of all the
@@ -70,7 +71,8 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
                 tcx.sess.emit_err(MissingPanicHandler);
             } else if item == LangItem::Oom {
                 if !tcx.features().default_alloc_error_handler {
-                    tcx.sess.emit_err(MissingAllocErrorHandler);
+                    tcx.sess.emit_err(AllocFuncRequired);
+                    tcx.sess.emit_note(MissingAllocErrorHandler);
                 }
             } else {
                 tcx.sess.emit_err(MissingLangItem { name: *name });

From 0609c0f1da13c8b0aeb90b5ff66f527bb16d58bf Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Thu, 22 Sep 2022 18:23:05 -0600
Subject: [PATCH 123/175] migrate diagnostic_items.rs to translateable
 diagnostics

---
 .../locales/en-US/passes.ftl                  | 12 ++++++-
 compiler/rustc_passes/src/diagnostic_items.rs | 36 +++++++++----------
 compiler/rustc_passes/src/errors.rs           | 20 +++++++++++
 3 files changed, 49 insertions(+), 19 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 49cd2ee17588..04fd0a3a6ac2 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -357,7 +357,7 @@ passes_collapse_debuginfo =
 passes_deprecated_annotation_has_no_effect =
     this `#[deprecated]` annotation has no effect
     .suggestion = remove the unnecessary deprecation attribute
-    
+
 passes_unknown_external_lang_item =
     unknown external lang item: `{$lang_item}`
 
@@ -389,3 +389,13 @@ passes_local_duplicate_lang_item =
 passes_invalid_attr_at_crate_level =
     `{$name}` attribute cannot be used at crate level
     .suggestion = perhaps you meant to use an outer attribute
+
+passes_duplicate_diagnostic_item =
+    duplicate diagnostic item found: `{$name}`.
+
+passes_duplicate_diagnostic_item_in_crate =
+    duplicate diagnostic item in crate `{$crate_name}`: `{$name}`.
+
+passes_diagnostic_item_first_defined =
+    the diagnostic item is first defined here
+    .note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index e428d9293db1..c411a2471659 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -16,6 +16,8 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
 
+use crate::errors::{DuplicateDiagnosticItem, DuplicateDiagnosticItemInCrate};
+
 fn observe_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     diagnostic_items: &mut DiagnosticItems,
@@ -33,25 +35,23 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item
     items.id_to_name.insert(item_def_id, name);
     if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
         if original_def_id != item_def_id {
-            let mut err = match tcx.hir().span_if_local(item_def_id) {
-                Some(span) => tcx
-                    .sess
-                    .struct_span_err(span, &format!("duplicate diagnostic item found: `{name}`.")),
-                None => tcx.sess.struct_err(&format!(
-                    "duplicate diagnostic item in crate `{}`: `{}`.",
-                    tcx.crate_name(item_def_id.krate),
-                    name
-                )),
-            };
-            if let Some(span) = tcx.hir().span_if_local(original_def_id) {
-                err.span_note(span, "the diagnostic item is first defined here");
+            let orig_span = tcx.hir().span_if_local(original_def_id);
+            let orig_crate_name = if orig_span.is_some() {
+                None
             } else {
-                err.note(&format!(
-                    "the diagnostic item is first defined in crate `{}`.",
-                    tcx.crate_name(original_def_id.krate)
-                ));
-            }
-            err.emit();
+                Some(tcx.crate_name(original_def_id.krate))
+            };
+            match tcx.hir().span_if_local(item_def_id) {
+                Some(span) => tcx.sess.emit_err(DuplicateDiagnosticItem { span, name }),
+                None => tcx.sess.emit_err(DuplicateDiagnosticItemInCrate {
+                    span: orig_span,
+                    // FIXME: We should not provide `name` to `orig_crate_name`. How do you create a blank/empty symbol?
+                    orig_crate_name: orig_crate_name.unwrap_or(name),
+                    have_orig_crate_name: orig_crate_name.map(|_| ()),
+                    crate_name: tcx.crate_name(item_def_id.krate),
+                    name,
+                }),
+            };
         }
     }
 }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 26190af03587..a94cac8c7954 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -755,3 +755,23 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
         diag
     }
 }
+
+#[derive(Diagnostic)]
+#[diag(passes::duplicate_diagnostic_item)]
+pub struct DuplicateDiagnosticItem {
+    #[primary_span]
+    pub span: Span,
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::duplicate_diagnostic_item_in_crate)]
+pub struct DuplicateDiagnosticItemInCrate {
+    #[note(passes::diagnostic_item_first_defined)]
+    pub span: Option,
+    pub orig_crate_name: Symbol,
+    #[note]
+    pub have_orig_crate_name: Option<()>,
+    pub crate_name: Symbol,
+    pub name: Symbol,
+}

From 40d5f00e16230ce67c018bb05b8772f02634146c Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Fri, 23 Sep 2022 12:23:18 -0600
Subject: [PATCH 124/175] migrate layout_test.rs to translateable diagnostics

---
 .../locales/en-US/passes.ftl                  | 21 ++++++
 compiler/rustc_passes/src/errors.rs           | 57 +++++++++++++++
 compiler/rustc_passes/src/layout_test.rs      | 70 ++++++++++---------
 3 files changed, 115 insertions(+), 33 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 04fd0a3a6ac2..9493d95be5dc 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -399,3 +399,24 @@ passes_duplicate_diagnostic_item_in_crate =
 passes_diagnostic_item_first_defined =
     the diagnostic item is first defined here
     .note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
+
+passes_abi =
+    abi: {$abi}
+
+passes_align =
+    align: {$align}
+
+passes_size =
+    size: {$size}
+
+passes_homogeneous_aggregate =
+    homogeneous_aggregate: {$homogeneous_aggregate}
+
+passes_layout_of =
+    layout_of({$normalized_ty}) = {$ty_layout}
+
+passes_unrecognized_field =
+    unrecognized field name `{$name}`
+
+passes_layout =
+    layout error: {$layout_error}
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index a94cac8c7954..e7a592d5a474 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -775,3 +775,60 @@ pub struct DuplicateDiagnosticItemInCrate {
     pub crate_name: Symbol,
     pub name: Symbol,
 }
+
+#[derive(Diagnostic)]
+#[diag(passes::abi)]
+pub struct Abi {
+    #[primary_span]
+    pub span: Span,
+    pub abi: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::align)]
+pub struct Align {
+    #[primary_span]
+    pub span: Span,
+    pub align: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::size)]
+pub struct Size {
+    #[primary_span]
+    pub span: Span,
+    pub size: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::homogeneous_aggregate)]
+pub struct HomogeneousAggregate {
+    #[primary_span]
+    pub span: Span,
+    pub homogeneous_aggregate: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::layout_of)]
+pub struct LayoutOf {
+    #[primary_span]
+    pub span: Span,
+    pub normalized_ty: String,
+    pub ty_layout: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::unrecognized_field)]
+pub struct UnrecognizedField {
+    #[primary_span]
+    pub span: Span,
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::layout)]
+pub struct Layout {
+    #[primary_span]
+    pub span: Span,
+    pub layout_error: String,
+}
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 46c4a702fde9..7af1dda1ecbd 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -7,6 +7,8 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::abi::{HasDataLayout, TargetDataLayout};
 
+use crate::errors::{Abi, Align, HomogeneousAggregate, Layout, LayoutOf, Size, UnrecognizedField};
+
 pub fn test_layout(tcx: TyCtxt<'_>) {
     if tcx.features().rustc_attrs {
         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
@@ -35,62 +37,64 @@ fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attri
             for meta_item in meta_items {
                 match meta_item.name_or_empty() {
                     sym::abi => {
-                        tcx.sess.span_err(
-                            tcx.def_span(item_def_id.to_def_id()),
-                            &format!("abi: {:?}", ty_layout.abi),
-                        );
+                        tcx.sess.emit_err(Abi {
+                            span: tcx.def_span(item_def_id.to_def_id()),
+                            abi: format!("{:?}", ty_layout.abi),
+                        });
                     }
 
                     sym::align => {
-                        tcx.sess.span_err(
-                            tcx.def_span(item_def_id.to_def_id()),
-                            &format!("align: {:?}", ty_layout.align),
-                        );
+                        tcx.sess.emit_err(Align {
+                            span: tcx.def_span(item_def_id.to_def_id()),
+                            align: format!("{:?}", ty_layout.align),
+                        });
                     }
 
                     sym::size => {
-                        tcx.sess.span_err(
-                            tcx.def_span(item_def_id.to_def_id()),
-                            &format!("size: {:?}", ty_layout.size),
-                        );
+                        tcx.sess.emit_err(Size {
+                            span: tcx.def_span(item_def_id.to_def_id()),
+                            size: format!("{:?}", ty_layout.size),
+                        });
                     }
 
                     sym::homogeneous_aggregate => {
-                        tcx.sess.span_err(
-                            tcx.def_span(item_def_id.to_def_id()),
-                            &format!(
-                                "homogeneous_aggregate: {:?}",
-                                ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
+                        tcx.sess.emit_err(HomogeneousAggregate {
+                            span: tcx.def_span(item_def_id.to_def_id()),
+                            homogeneous_aggregate: format!(
+                                "{:?}",
+                                ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env })
                             ),
-                        );
+                        });
                     }
 
                     sym::debug => {
-                        let normalized_ty = tcx.normalize_erasing_regions(
-                            param_env.with_reveal_all_normalized(tcx),
-                            ty,
-                        );
-                        tcx.sess.span_err(
-                            tcx.def_span(item_def_id.to_def_id()),
-                            &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
+                        let normalized_ty = format!(
+                            "{:?}",
+                            tcx.normalize_erasing_regions(
+                                param_env.with_reveal_all_normalized(tcx),
+                                ty,
+                            )
                         );
+                        let ty_layout = format!("{:#?}", *ty_layout);
+                        tcx.sess.emit_err(LayoutOf {
+                            span: tcx.def_span(item_def_id.to_def_id()),
+                            normalized_ty,
+                            ty_layout,
+                        });
                     }
 
                     name => {
-                        tcx.sess.span_err(
-                            meta_item.span(),
-                            &format!("unrecognized field name `{}`", name),
-                        );
+                        tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
                     }
                 }
             }
         }
 
         Err(layout_error) => {
-            tcx.sess.span_err(
-                tcx.def_span(item_def_id.to_def_id()),
-                &format!("layout error: {:?}", layout_error),
-            );
+            tcx.sess.emit_err(Layout {
+                span: tcx.def_span(item_def_id.to_def_id()),
+                layout_error: format!("{:?}", layout_error),
+            });
         }
     }
 }

From c457abee2e913ebb6f46329c15c6b43fbcb8c703 Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Sat, 24 Sep 2022 12:21:58 -0600
Subject: [PATCH 125/175] migrate lib_features.rs to translateable diagnostics

---
 .../locales/en-US/passes.ftl                  |  6 ++++
 compiler/rustc_passes/src/errors.rs           | 20 +++++++++++
 compiler/rustc_passes/src/lib_features.rs     | 34 ++++++++-----------
 3 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 9493d95be5dc..b2c54aaccfe3 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -420,3 +420,9 @@ passes_unrecognized_field =
 
 passes_layout =
     layout error: {$layout_error}
+
+passes_feature_stable_twice =
+    feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since}
+
+passes_feature_previously_declared =
+    feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared}
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index e7a592d5a474..7c3a575242f3 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -832,3 +832,23 @@ pub struct Layout {
     pub span: Span,
     pub layout_error: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(passes::feature_stable_twice, code = "E0711")]
+pub struct FeatureStableTwice {
+    #[primary_span]
+    pub span: Span,
+    pub feature: Symbol,
+    pub since: Symbol,
+    pub prev_since: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::feature_previously_declared, code = "E0711")]
+pub struct FeaturePreviouslyDeclared<'a, 'b> {
+    #[primary_span]
+    pub span: Span,
+    pub feature: Symbol,
+    pub declared: &'a str,
+    pub prev_declared: &'b str,
+}
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 04173c792a97..b5843c0ae488 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -6,7 +6,6 @@
 
 use rustc_ast::{Attribute, MetaItemKind};
 use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
-use rustc_errors::struct_span_err;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::lib_features::LibFeatures;
@@ -15,6 +14,8 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::Symbol;
 use rustc_span::{sym, Span};
 
+use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice};
+
 fn new_lib_features() -> LibFeatures {
     LibFeatures { stable: Default::default(), unstable: Default::default() }
 }
@@ -92,14 +93,12 @@ impl<'tcx> LibFeatureCollector<'tcx> {
             (Some(since), _, false) => {
                 if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) {
                     if *prev_since != since {
-                        self.span_feature_error(
+                        self.tcx.sess.emit_err(FeatureStableTwice {
                             span,
-                            &format!(
-                                "feature `{}` is declared stable since {}, \
-                                 but was previously declared stable since {}",
-                                feature, since, prev_since,
-                            ),
-                        );
+                            feature,
+                            since,
+                            prev_since: *prev_since,
+                        });
                         return;
                     }
                 }
@@ -110,22 +109,17 @@ impl<'tcx> LibFeatureCollector<'tcx> {
                 self.lib_features.unstable.insert(feature, span);
             }
             (Some(_), _, true) | (None, true, _) => {
-                self.span_feature_error(
+                let declared = if since.is_some() { "stable" } else { "unstable" };
+                let prev_declared = if since.is_none() { "stable" } else { "unstable" };
+                self.tcx.sess.emit_err(FeaturePreviouslyDeclared {
                     span,
-                    &format!(
-                        "feature `{}` is declared {}, but was previously declared {}",
-                        feature,
-                        if since.is_some() { "stable" } else { "unstable" },
-                        if since.is_none() { "stable" } else { "unstable" },
-                    ),
-                );
+                    feature,
+                    declared,
+                    prev_declared,
+                });
             }
         }
     }
-
-    fn span_feature_error(&self, span: Span, msg: &str) {
-        struct_span_err!(self.tcx.sess, span, E0711, "{}", &msg).emit();
-    }
 }
 
 impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {

From 572f3414b782311a8ec4143c50bbe3b006594898 Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Sat, 24 Sep 2022 12:49:29 -0600
Subject: [PATCH 126/175] migrate check_const.rs to translateable diagnostics

---
 .../locales/en-US/passes.ftl                  |  7 ++++
 compiler/rustc_passes/src/check_const.rs      | 33 ++++++++++++++++---
 compiler/rustc_passes/src/errors.rs           | 18 ++++++++++
 3 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index b2c54aaccfe3..550096469bb0 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -426,3 +426,10 @@ passes_feature_stable_twice =
 
 passes_feature_previously_declared =
     feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared}
+
+passes_expr_not_allowed_in_context =
+    {$expr} is not allowed in a `{$context}`
+
+passes_const_impl_const_trait =
+    const `impl`s must be for traits marked with `#[const_trait]`
+    .note = this trait must be annotated with `#[const_trait]`
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index e502b9b54e30..0a509598ec51 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -8,7 +8,6 @@
 //! through, but errors for structured control flow in a `const` should be emitted here.
 
 use rustc_attr as attr;
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
@@ -18,6 +17,8 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
 use rustc_span::{sym, Span, Symbol};
 
+use crate::errors::{ConstImplConstTrait, ExprNotAllowedInContext};
+
 /// An expression that is not *always* legal in a const context.
 #[derive(Clone, Copy)]
 enum NonConstExpr {
@@ -133,18 +134,22 @@ impl<'tcx> CheckConstVisitor<'tcx> {
         let const_kind =
             const_kind.expect("`const_check_violated` may only be called inside a const context");
 
-        let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
-
         let required_gates = required_gates.unwrap_or(&[]);
         let missing_gates: Vec<_> =
             required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
 
         match missing_gates.as_slice() {
             [] => {
-                struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit();
+                tcx.sess.emit_err(ExprNotAllowedInContext {
+                    span,
+                    expr: expr.name(),
+                    context: const_kind.keyword_name(),
+                });
             }
 
             [missing_primary, ref missing_secondary @ ..] => {
+                let msg =
+                    format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
                 let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg);
 
                 // If multiple feature gates would be required to enable this expression, include
@@ -191,6 +196,26 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
         self.tcx.hir()
     }
 
+    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
+        let tcx = self.tcx;
+        if let hir::ItemKind::Impl(hir::Impl {
+            constness: hir::Constness::Const,
+            of_trait: Some(trait_ref),
+            ..
+        }) = item.kind
+            && let Some(def_id) = trait_ref.trait_def_id()
+        {
+            let source_map = tcx.sess.source_map();
+            if !tcx.has_attr(def_id, sym::const_trait) {
+                tcx.sess.emit_err(ConstImplConstTrait {
+                    span: source_map.guess_head_span(item.span),
+                    def_span: source_map.guess_head_span(tcx.def_span(def_id)),
+                });
+            }
+        }
+        intravisit::walk_item(self, item);
+    }
+
     fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
         let kind = Some(hir::ConstContext::Const);
         self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 7c3a575242f3..fe169c566f63 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -852,3 +852,21 @@ pub struct FeaturePreviouslyDeclared<'a, 'b> {
     pub declared: &'a str,
     pub prev_declared: &'b str,
 }
+
+#[derive(Diagnostic)]
+#[diag(passes::expr_not_allowed_in_context, code = "E0744")]
+pub struct ExprNotAllowedInContext<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub expr: String,
+    pub context: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes::const_impl_const_trait)]
+pub struct ConstImplConstTrait {
+    #[primary_span]
+    pub span: Span,
+    #[note]
+    pub def_span: Span,
+}

From 69766e4f167f4097e1f8975bd866c1f782fa26d5 Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Sun, 25 Sep 2022 22:52:19 -0600
Subject: [PATCH 127/175] migrate loops.rs to translateable diagnostics

---
 .../locales/en-US/passes.ftl                  |  34 ++++
 compiler/rustc_passes/src/errors.rs           | 121 ++++++++++++-
 compiler/rustc_passes/src/loops.rs            | 161 +++++-------------
 3 files changed, 198 insertions(+), 118 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 550096469bb0..3dc4204f986a 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -433,3 +433,37 @@ passes_expr_not_allowed_in_context =
 passes_const_impl_const_trait =
     const `impl`s must be for traits marked with `#[const_trait]`
     .note = this trait must be annotated with `#[const_trait]`
+
+passes_break_non_loop =
+    `break` with value from a `{$kind}` loop
+    .label = can only break with a value inside `loop` or breakable block
+    .label2 = you can't `break` with a value in a `{$kind}` loop
+    .suggestion = use `break` on its own without a value inside this `{$kind}` loop
+    .break_expr_suggestion = alternatively, you might have meant to use the available loop label
+
+passes_continue_labeled_block =
+    `continue` pointing to a labeled block
+    .label = labeled blocks cannot be `continue`'d
+    .block_label = labeled block the `continue` points to
+
+passes_break_inside_closure =
+    `{$name}` inside of a closure
+    .label = cannot `{$name}` inside of a closure
+    .closure_label = enclosing closure
+
+passes_break_inside_async_block =
+    `{$name}` inside of an `async` block
+    .label = cannot `{$name}` inside of an `async` block
+    .async_block_label = enclosing `async` block
+
+passes_outside_loop =
+    `{$name}` outside of a loop
+    .label = cannot `{$name}` outside of a loop
+
+passes_unlabeled_in_labeled_block =
+    unlabeled `{$cf_type}` inside of a labeled block
+    .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
+
+passes_unlabeled_cf_in_while_condition =
+    `break` or `continue` with no label in the condition of a `while` loop
+    .label = unlabeled `{$cf_type}` in the condition of a `while` loop
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index fe169c566f63..fcbcc298bd5b 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1,7 +1,8 @@
 use std::{io::Error, path::Path};
 
-use rustc_errors::{Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan};
-use rustc_hir::Target;
+use rustc_ast::Label;
+use rustc_errors::{error_code, Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan};
+use rustc_hir::{self as hir, ExprKind, Target};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
@@ -870,3 +871,119 @@ pub struct ConstImplConstTrait {
     #[note]
     pub def_span: Span,
 }
+
+pub struct BreakNonLoop<'a> {
+    pub span: Span,
+    pub head: Option,
+    pub kind: &'a str,
+    pub suggestion: String,
+    pub loop_label: Option` container.
@@ -308,244 +187,66 @@ assert-css: (
     {"color": "rgb(221, 221, 221)"},
 )
 
-// Checking the color of "keyword".
-assert-css: (
-    ".result-keyword .keyword",
-    {"color": "rgb(210, 153, 29)"},
-    ALL,
-)
-assert-css: (
-    ".result-keyword",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-keyword"
-assert-css: (
-    ".result-keyword:hover",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-keyword:hover .keyword",
-    {"color": "rgb(210, 153, 29)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-keyword"
-assert-css: (
-    ".result-keyword:focus",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-keyword:focus .keyword",
-    {"color": "rgb(210, 153, 29)"},
-)
+store-value: (entry_color, "rgb(221, 221, 221)") // color of the search entry
+store-value: (hover_entry_color, "rgb(221, 221, 221)") // color of the hovered/focused search entry
+store-value: (background_color, "rgba(0, 0, 0, 0)") // background color
+store-value: (hover_background_color, "rgb(97, 97, 97)") // hover background color
 
-// Check the color of "struct".
-assert-css: (
-    ".result-struct .struct",
-    {"color": "rgb(45, 191, 184)"},
-    ALL,
+call-function: (
+    "check-result-color", (
+        "keyword", // item kind
+        "rgb(210, 153, 29)", // color of item kind
+        "rgb(210, 153, 29)", // color of hovered/focused item kind
+    ),
 )
-assert-css: (
-    ".result-struct",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
+call-function: (
+    "check-result-color", (
+        "struct", // item kind
+        "rgb(45, 191, 184)", // color of item kind
+        "rgb(45, 191, 184)", // color of hovered/focused item kind
+    ),
 )
-move-cursor-to: ".result-struct"
-assert-css: (
-    ".result-struct:hover",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
+call-function: (
+    "check-result-color", (
+        "associatedtype", // item kind
+        "rgb(210, 153, 29)", // color of item kind
+        "rgb(210, 153, 29)", // color of hovered/focused item kind
+    ),
 )
-assert-css: (
-    ".result-struct:hover .struct",
-    {"color": "rgb(45, 191, 184)"},
+call-function: (
+    "check-result-color", (
+        "tymethod", // item kind
+        "rgb(43, 171, 99)", // color of item kind
+        "rgb(43, 171, 99)", // color of hovered/focused item kind
+    ),
 )
-move-cursor-to: ".search-input"
-focus: ".result-struct"
-assert-css: (
-    ".result-struct:focus",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
+call-function: (
+    "check-result-color", (
+        "method", // item kind
+        "rgb(43, 171, 99)", // color of item kind
+        "rgb(43, 171, 99)", // color of hovered/focused item kind
+    ),
 )
-assert-css: (
-    ".result-struct:focus .struct",
-    {"color": "rgb(45, 191, 184)"},
+call-function: (
+    "check-result-color", (
+        "structfield", // item kind
+        "rgb(221, 221, 221)", // color of item kind
+        "rgb(221, 221, 221)", // color of hovered/focused item kind
+    ),
 )
-
-// Check the color of "associated type".
-assert-css: (
-    ".result-associatedtype .associatedtype",
-    {"color": "rgb(210, 153, 29)"},
-    ALL,
+call-function: (
+    "check-result-color", (
+        "macro", // item kind
+        "rgb(9, 189, 0)", // color of item kind
+        "rgb(9, 189, 0)", // color of hovered/focused item kind
+    ),
 )
-assert-css: (
-    ".result-associatedtype",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-associatedtype"
-assert-css: (
-    ".result-associatedtype:hover",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-associatedtype:hover .associatedtype",
-    {"color": "rgb(210, 153, 29)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-associatedtype"
-assert-css: (
-    ".result-associatedtype:focus",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-associatedtype:focus .associatedtype",
-    {"color": "rgb(210, 153, 29)"},
-)
-
-// Check the color of "type method".
-assert-css: (
-    ".result-tymethod .tymethod",
-    {"color": "rgb(43, 171, 99)"},
-    ALL,
-)
-assert-css: (
-    ".result-tymethod",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-tymethod"
-assert-css: (
-    ".result-tymethod:hover",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-tymethod:hover .tymethod",
-    {"color": "rgb(43, 171, 99)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-tymethod"
-assert-css: (
-    ".result-tymethod:focus",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-tymethod:focus .tymethod",
-    {"color": "rgb(43, 171, 99)"},
-)
-
-// Check the color of "method".
-assert-css: (
-    ".result-method .method",
-    {"color": "rgb(43, 171, 99)"},
-    ALL,
-)
-assert-css: (
-    ".result-method",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-method"
-assert-css: (
-    ".result-method:hover",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-method:hover .method",
-    {"color": "rgb(43, 171, 99)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-method"
-assert-css: (
-    ".result-method:focus",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-method:focus .method",
-    {"color": "rgb(43, 171, 99)"},
-)
-
-// Check the color of "struct field".
-assert-css: (
-    ".result-structfield .structfield",
-    {"color": "rgb(221, 221, 221)"},
-    ALL,
-)
-assert-css: (
-    ".result-structfield",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-structfield"
-assert-css: (
-    ".result-structfield:hover",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-structfield:hover .structfield",
-    {"color": "rgb(221, 221, 221)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-structfield"
-assert-css: (
-    ".result-structfield:focus",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-structfield:focus .structfield",
-    {"color": "rgb(221, 221, 221)"},
-)
-
-// Check the color of "macro".
-assert-css: (
-    ".result-macro .macro",
-    {"color": "rgb(9, 189, 0)"},
-    ALL,
-)
-assert-css: (
-    ".result-macro",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-macro"
-assert-css: (
-    ".result-macro:hover",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-macro:hover .macro",
-    {"color": "rgb(9, 189, 0)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-macro"
-assert-css: (
-    ".result-macro:focus",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-macro:focus .macro",
-    {"color": "rgb(9, 189, 0)"},
-)
-
-// Check the color of "fn".
-assert-css: (
-    ".result-fn .fn",
-    {"color": "rgb(43, 171, 99)"},
-    ALL,
-)
-assert-css: (
-    ".result-fn",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-fn"
-assert-css: (
-    ".result-fn:hover",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-fn:hover .fn",
-    {"color": "rgb(43, 171, 99)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-fn"
-assert-css: (
-    ".result-fn:focus",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(97, 97, 97)"},
-)
-assert-css: (
-    ".result-fn:focus .fn",
-    {"color": "rgb(43, 171, 99)"},
+call-function: (
+    "check-result-color", (
+        "fn", // item kind
+        "rgb(43, 171, 99)", // color of item kind
+        "rgb(43, 171, 99)", // color of hovered/focused item kind
+    ),
 )
 
 // Checking the `` container.
@@ -577,244 +278,66 @@ assert-css: (
     {"color": "rgb(0, 0, 0)"},
 )
 
-// Checking the color of "keyword".
-assert-css: (
-    ".result-keyword .keyword",
-    {"color": "rgb(56, 115, 173)"},
-    ALL,
-)
-assert-css: (
-    ".result-keyword",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-keyword"
-assert-css: (
-    ".result-keyword:hover",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-keyword:hover .keyword",
-    {"color": "rgb(56, 115, 173)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-keyword"
-assert-css: (
-    ".result-keyword:focus",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-keyword:focus .keyword",
-    {"color": "rgb(56, 115, 173)"},
-)
+store-value: (entry_color, "rgb(0, 0, 0)") // color of the search entry
+store-value: (hover_entry_color, "rgb(0, 0, 0)") // color of the hovered/focused search entry
+store-value: (background_color, "rgba(0, 0, 0, 0)") // background color
+store-value: (hover_background_color, "rgb(204, 204, 204)") // hover background color
 
-// Check the color of "struct".
-assert-css: (
-    ".result-struct .struct",
-    {"color": "rgb(173, 55, 138)"},
-    ALL,
+call-function: (
+    "check-result-color", (
+        "keyword", // item kind
+        "rgb(56, 115, 173)", // color of item kind
+        "rgb(56, 115, 173)", // color of hovered/focused item kind
+    ),
 )
-assert-css: (
-    ".result-struct",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
+call-function: (
+    "check-result-color", (
+        "struct", // item kind
+        "rgb(173, 55, 138)", // color of item kind
+        "rgb(173, 55, 138)", // color of hovered/focused item kind
+    ),
 )
-move-cursor-to: ".result-struct"
-assert-css: (
-    ".result-struct:hover",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
+call-function: (
+    "check-result-color", (
+        "associatedtype", // item kind
+        "rgb(56, 115, 173)", // color of item kind
+        "rgb(56, 115, 173)", // color of hovered/focused item kind
+    ),
 )
-assert-css: (
-    ".result-struct:hover .struct",
-    {"color": "rgb(173, 55, 138)"},
+call-function: (
+    "check-result-color", (
+        "tymethod", // item kind
+        "rgb(173, 124, 55)", // color of item kind
+        "rgb(173, 124, 55)", // color of hovered/focused item kind
+    ),
 )
-move-cursor-to: ".search-input"
-focus: ".result-struct"
-assert-css: (
-    ".result-struct:focus",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
+call-function: (
+    "check-result-color", (
+        "method", // item kind
+        "rgb(173, 124, 55)", // color of item kind
+        "rgb(173, 124, 55)", // color of hovered/focused item kind
+    ),
 )
-assert-css: (
-    ".result-struct:focus .struct",
-    {"color": "rgb(173, 55, 138)"},
+call-function: (
+    "check-result-color", (
+        "structfield", // item kind
+        "rgb(0, 0, 0)", // color of item kind
+        "rgb(0, 0, 0)", // color of hovered/focused item kind
+    ),
 )
-
-// Check the color of "associated type".
-assert-css: (
-    ".result-associatedtype .associatedtype",
-    {"color": "rgb(56, 115, 173)"},
-    ALL,
+call-function: (
+    "check-result-color", (
+        "macro", // item kind
+        "rgb(6, 128, 0)", // color of item kind
+        "rgb(6, 128, 0)", // color of hovered/focused item kind
+    ),
 )
-assert-css: (
-    ".result-associatedtype",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-associatedtype"
-assert-css: (
-    ".result-associatedtype:hover",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-associatedtype:hover .associatedtype",
-    {"color": "rgb(56, 115, 173)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-associatedtype"
-assert-css: (
-    ".result-associatedtype:focus",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-associatedtype:focus .associatedtype",
-    {"color": "rgb(56, 115, 173)"},
-)
-
-// Check the color of "type method".
-assert-css: (
-    ".result-tymethod .tymethod",
-    {"color": "rgb(173, 124, 55)"},
-    ALL,
-)
-assert-css: (
-    ".result-tymethod",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-tymethod"
-assert-css: (
-    ".result-tymethod:hover",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-tymethod:hover .tymethod",
-    {"color": "rgb(173, 124, 55)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-tymethod"
-assert-css: (
-    ".result-tymethod:focus",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-tymethod:focus .tymethod",
-    {"color": "rgb(173, 124, 55)"},
-)
-
-// Check the color of "method".
-assert-css: (
-    ".result-method .method",
-    {"color": "rgb(173, 124, 55)"},
-    ALL,
-)
-assert-css: (
-    ".result-method",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-method"
-assert-css: (
-    ".result-method:hover",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-method:hover .method",
-    {"color": "rgb(173, 124, 55)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-method"
-assert-css: (
-    ".result-method:focus",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-method:focus .method",
-    {"color": "rgb(173, 124, 55)"},
-)
-
-// Check the color of "struct field".
-assert-css: (
-    ".result-structfield .structfield",
-    {"color": "rgb(0, 0, 0)"},
-    ALL,
-)
-assert-css: (
-    ".result-structfield",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-structfield"
-assert-css: (
-    ".result-structfield:hover",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-structfield:hover .structfield",
-    {"color": "rgb(0, 0, 0)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-structfield"
-assert-css: (
-    ".result-structfield:focus",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-structfield:focus .structfield",
-    {"color": "rgb(0, 0, 0)"},
-)
-
-// Check the color of "macro".
-assert-css: (
-    ".result-macro .macro",
-    {"color": "rgb(6, 128, 0)"},
-    ALL,
-)
-assert-css: (
-    ".result-macro",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-macro"
-assert-css: (
-    ".result-macro:hover",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-macro:hover .macro",
-    {"color": "rgb(6, 128, 0)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-macro"
-assert-css: (
-    ".result-macro:focus",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-macro:focus .macro",
-    {"color": "rgb(6, 128, 0)"},
-)
-
-// Check the color of "fn".
-assert-css: (
-    ".result-fn .fn",
-    {"color": "rgb(173, 124, 55)"},
-    ALL,
-)
-assert-css: (
-    ".result-fn",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".result-fn"
-assert-css: (
-    ".result-fn:hover",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-fn:hover .fn",
-    {"color": "rgb(173, 124, 55)"},
-)
-move-cursor-to: ".search-input"
-focus: ".result-fn"
-assert-css: (
-    ".result-fn:focus",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(204, 204, 204)"},
-)
-assert-css: (
-    ".result-fn:focus .fn",
-    {"color": "rgb(173, 124, 55)"},
+call-function: (
+    "check-result-color", (
+        "fn", // item kind
+        "rgb(173, 124, 55)", // color of item kind
+        "rgb(173, 124, 55)", // color of hovered/focused item kind
+    ),
 )
 
 // Checking the `` container.

From 5ef1c03bd80e40b3280f15b8285b73d5fc616776 Mon Sep 17 00:00:00 2001
From: Nathan Stocks 
Date: Mon, 10 Oct 2022 10:06:44 -0600
Subject: [PATCH 149/175] make up your mind, rustfmt

---
 compiler/rustc_passes/src/diagnostic_items.rs | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index 2516226f36cb..3f991cf65724 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -58,11 +58,7 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item
 /// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.
 fn extract(attrs: &[ast::Attribute]) -> Option {
     attrs.iter().find_map(|attr| {
-        if attr.has_name(sym::rustc_diagnostic_item) {
-            attr.value_str()
-        } else {
-            None
-        }
+        if attr.has_name(sym::rustc_diagnostic_item) { attr.value_str() } else { None }
     })
 }
 

From 6add6a1e1e5681d8d80f48326795b734c7966518 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Mon, 12 Sep 2022 15:02:45 +0200
Subject: [PATCH 150/175] Change default lint level of INVALID_HTML_TAGS to
 warning

---
 src/librustdoc/lint.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index e76c19a61c54..3aad97bc296f 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -148,7 +148,7 @@ declare_rustdoc_lint! {
     ///
     /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_html_tags
     INVALID_HTML_TAGS,
-    Allow,
+    Warn,
     "detects invalid HTML tags in doc comments"
 }
 

From c23ed655eb1244cf0fb5d51d7bdb4e473b540e15 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Tue, 13 Sep 2022 12:01:07 +0200
Subject: [PATCH 151/175] Update rustdoc tests

---
 .../intra-doc/malformed-generics.rs           |  9 ++
 .../intra-doc/malformed-generics.stderr       | 82 ++++++++++++++++---
 .../extern-crate-only-used-in-link.rs         |  2 +-
 3 files changed, 79 insertions(+), 14 deletions(-)

diff --git a/src/test/rustdoc-ui/intra-doc/malformed-generics.rs b/src/test/rustdoc-ui/intra-doc/malformed-generics.rs
index 15e02925ed90..161625ed28c2 100644
--- a/src/test/rustdoc-ui/intra-doc/malformed-generics.rs
+++ b/src/test/rustdoc-ui/intra-doc/malformed-generics.rs
@@ -3,17 +3,26 @@
 //! [Vec<] //~ ERROR
 //! [Vec] //~ ERROR
+//~^ WARN
 //! [Vec>>] //~ ERROR
+//~^ WARN
 //! [Vec>>] //~ ERROR
+//~^ WARN
 //! [] //~ ERROR
+//~^ WARN
 //! [] //~ ERROR
+//~^ WARN
 //! [Vec::new()] //~ ERROR
+//~^ WARN
 //! [Vec<>] //~ ERROR
+//~^ WARN
 //! [Vec<>] //~ ERROR
 //! [Vec<<>>] //~ ERROR
 
 // FIXME(#74563) support UFCS
 //! [::into_iter] //~ ERROR
+//~^ WARN
 //! [ as IntoIterator>::iter] //~ ERROR
+//~^ WARN
diff --git a/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr b/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr
index 5bc0f84e24d1..08349fef88d3 100644
--- a/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr
+++ b/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr
@@ -23,67 +23,67 @@ LL | //! [Vec]
    |      ^^^^^^^^^^ unbalanced angle brackets
 
 error: unresolved link to `Vec>>`
-  --> $DIR/malformed-generics.rs:6:6
+  --> $DIR/malformed-generics.rs:7:6
    |
 LL | //! [Vec>>]
    |      ^^^^^^^^^^^^ unbalanced angle brackets
 
 error: unresolved link to `Vec>>`
-  --> $DIR/malformed-generics.rs:7:6
+  --> $DIR/malformed-generics.rs:9:6
    |
 LL | //! [Vec>>]
    |      ^^^^^^^^ unbalanced angle brackets
 
 error: unresolved link to ` $DIR/malformed-generics.rs:8:6
+  --> $DIR/malformed-generics.rs:11:6
    |
 LL | //! [ $DIR/malformed-generics.rs:9:6
+  --> $DIR/malformed-generics.rs:12:6
    |
 LL | //! [Vec::<]
    |      ^^^^^^ unbalanced angle brackets
 
 error: unresolved link to ``
-  --> $DIR/malformed-generics.rs:10:6
+  --> $DIR/malformed-generics.rs:13:6
    |
 LL | //! []
    |      ^^^ missing type for generic parameters
 
 error: unresolved link to ``
-  --> $DIR/malformed-generics.rs:11:6
+  --> $DIR/malformed-generics.rs:15:6
    |
 LL | //! []
    |      ^^^^^^^^^^^^^^^^ missing type for generic parameters
 
 error: unresolved link to `Vec::new`
-  --> $DIR/malformed-generics.rs:12:6
+  --> $DIR/malformed-generics.rs:17:6
    |
 LL | //! [Vec::new()]
    |      ^^^^^^^^^^^^^ has invalid path separator
 
 error: unresolved link to `Vec<>`
-  --> $DIR/malformed-generics.rs:13:6
+  --> $DIR/malformed-generics.rs:19:6
    |
 LL | //! [Vec<>]
    |      ^^^^^^^^ too many angle brackets
 
 error: unresolved link to `Vec<>`
-  --> $DIR/malformed-generics.rs:14:6
+  --> $DIR/malformed-generics.rs:21:6
    |
 LL | //! [Vec<>]
    |      ^^^^^ empty angle brackets
 
 error: unresolved link to `Vec<<>>`
-  --> $DIR/malformed-generics.rs:15:6
+  --> $DIR/malformed-generics.rs:22:6
    |
 LL | //! [Vec<<>>]
    |      ^^^^^^^ too many angle brackets
 
 error: unresolved link to `::into_iter`
-  --> $DIR/malformed-generics.rs:18:6
+  --> $DIR/malformed-generics.rs:25:6
    |
 LL | //! [::into_iter]
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported
@@ -91,12 +91,68 @@ LL | //! [::into_iter]
    = note: see https://github.com/rust-lang/rust/issues/74563 for more information
 
 error: unresolved link to ` as IntoIterator>::iter`
-  --> $DIR/malformed-generics.rs:19:6
+  --> $DIR/malformed-generics.rs:27:6
    |
 LL | //! [ as IntoIterator>::iter]
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported
    |
    = note: see https://github.com/rust-lang/rust/issues/74563 for more information
 
-error: aborting due to 15 previous errors
+warning: unclosed HTML tag `T`
+  --> $DIR/malformed-generics.rs:5:13
+   |
+LL | //! [Vec]
+   |             ^^^
+   |
+   = note: `#[warn(rustdoc::invalid_html_tags)]` on by default
+
+warning: unclosed HTML tag `T`
+  --> $DIR/malformed-generics.rs:7:13
+   |
+LL | //! [Vec>>]
+   |             ^^^
+
+warning: unclosed HTML tag `T`
+  --> $DIR/malformed-generics.rs:9:9
+   |
+LL | //! [Vec>>]
+   |         ^^^
+
+warning: unclosed HTML tag `T`
+  --> $DIR/malformed-generics.rs:13:6
+   |
+LL | //! []
+   |      ^^^
+
+warning: unclosed HTML tag `invalid`
+  --> $DIR/malformed-generics.rs:15:6
+   |
+LL | //! []
+   |      ^^^^^^^^
+
+warning: unclosed HTML tag `T`
+  --> $DIR/malformed-generics.rs:17:10
+   |
+LL | //! [Vec::new()]
+   |          ^^^
+
+warning: unclosed HTML tag `T`
+  --> $DIR/malformed-generics.rs:19:10
+   |
+LL | //! [Vec<>]
+   |          ^^^
+
+warning: unclosed HTML tag `Vec`
+  --> $DIR/malformed-generics.rs:25:6
+   |
+LL | //! [::into_iter]
+   |      ^^^^
+
+warning: unclosed HTML tag `T`
+  --> $DIR/malformed-generics.rs:27:10
+   |
+LL | //! [ as IntoIterator>::iter]
+   |          ^^^
+
+error: aborting due to 15 previous errors; 9 warnings emitted
 
diff --git a/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs b/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs
index 5d8dcf8bc1d1..ad50887e9221 100644
--- a/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs
+++ b/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs
@@ -16,4 +16,4 @@
 //! [`empty`]
 
 // @has - '//a[@href="../empty2/index.html"]' 'empty2'
-//! [empty2]
+//! [`empty2`]

From d9570e0510c87d4e7ba938005e506eb5cc7fc91b Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Mon, 12 Sep 2022 12:07:43 +0200
Subject: [PATCH 152/175] Stabilize rustdoc CHECK_INVALID_HTML_TAGS check

---
 src/librustdoc/passes/html_tags.rs | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs
index 694b03161d92..67fc71665ccf 100644
--- a/src/librustdoc/passes/html_tags.rs
+++ b/src/librustdoc/passes/html_tags.rs
@@ -22,10 +22,8 @@ struct InvalidHtmlTagsLinter<'a, 'tcx> {
 }
 
 pub(crate) fn check_invalid_html_tags(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
-    if cx.tcx.sess.is_nightly_build() {
-        let mut coll = InvalidHtmlTagsLinter { cx };
-        coll.visit_crate(&krate);
-    }
+    let mut coll = InvalidHtmlTagsLinter { cx };
+    coll.visit_crate(&krate);
     krate
 }
 

From 3416fa1882a9ea5b4d7c32b62afccbe9d01fb79a Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Sat, 8 Oct 2022 14:42:38 +0200
Subject: [PATCH 153/175] Fix doc lint error

---
 compiler/rustc_errors/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 94a493992e59..2f6686f81965 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -411,7 +411,7 @@ struct HandlerInner {
     /// would be unnecessary repetition.
     taught_diagnostics: FxHashSet,
 
-    /// Used to suggest rustc --explain 
+    /// Used to suggest rustc --explain ``
     emitted_diagnostic_codes: FxIndexSet,
 
     /// This set contains a hash of every diagnostic that has been emitted by

From adc24d1b5efb768a8e81ec5a26133f2351c4dd3f Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Sun, 9 Oct 2022 16:15:23 +0200
Subject: [PATCH 154/175] Fix compiler docs

---
 compiler/rustc_hir_analysis/src/check/check.rs         |  4 +++-
 .../src/constrained_generic_params.rs                  | 10 +++++++---
 .../src/impl_wf_check/min_specialization.rs            |  8 ++++++++
 compiler/rustc_hir_analysis/src/mem_categorization.rs  |  2 +-
 compiler/rustc_middle/src/thir.rs                      |  2 +-
 compiler/rustc_middle/src/ty/adt.rs                    |  4 ++--
 compiler/rustc_parse/src/lib.rs                        |  3 ++-
 .../rustc_trait_selection/src/traits/auto_trait.rs     |  8 ++++----
 compiler/rustc_trait_selection/src/traits/project.rs   |  5 +++--
 .../rustc_trait_selection/src/traits/select/mod.rs     |  2 +-
 10 files changed, 32 insertions(+), 16 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index c92d8dfb6027..77ab27266b28 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -707,10 +707,12 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
 /// check those cases in the `param_env` of that function, which may have
 /// bounds not on this opaque type:
 ///
-/// type X = impl Clone
+/// ```ignore (illustrative)
+/// type X = impl Clone;
 /// fn f(t: T) -> X {
 ///     t
 /// }
+/// ```
 ///
 /// Without this check the above code is incorrectly accepted: we would ICE if
 /// some tried, for example, to clone an `Option>`.
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 8428e4664067..213b89fc7843 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -114,9 +114,9 @@ pub fn identify_constrained_generic_params<'tcx>(
 /// ```
 /// The impl's predicates are collected from left to right. Ignoring
 /// the implicit `Sized` bounds, these are
-///   * T: Debug
-///   * U: Iterator
-///   * ::Item = T -- a desugared ProjectionPredicate
+///   * `T: Debug`
+///   * `U: Iterator`
+///   * `::Item = T` -- a desugared ProjectionPredicate
 ///
 /// When we, for example, try to go over the trait-reference
 /// `IntoIter as Trait`, we substitute the impl parameters with fresh
@@ -132,12 +132,16 @@ pub fn identify_constrained_generic_params<'tcx>(
 ///
 /// We *do* have to be somewhat careful when projection targets contain
 /// projections themselves, for example in
+///
+/// ```ignore (illustrative)
 ///     impl Trait for U where
 /// /* 0 */   S: Iterator,
 /// /* - */   U: Iterator,
 /// /* 1 */   ::Item: ToOwned::Item)>
 /// /* 2 */   W: Iterator
 /// /* 3 */   V: Debug
+/// ```
+///
 /// we have to evaluate the projections in the order I wrote them:
 /// `V: Debug` requires `V` to be evaluated. The only projection that
 /// *determines* `V` is 2 (1 contains it, but *does not determine it*,
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index bfe5d4751e08..e806e94879d9 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -130,8 +130,10 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
 ///
 /// Example
 ///
+/// ```ignore (illustrative)
 /// impl Foo for B { /* impl2 */ }
 /// impl Foo> for C { /* impl1 */ }
+/// ```
 ///
 /// Would return `S1 = [C]` and `S2 = [Vec, C]`.
 fn get_impl_substs<'tcx>(
@@ -225,13 +227,17 @@ fn unconstrained_parent_impl_substs<'tcx>(
 ///
 /// For example forbid the following:
 ///
+/// ```ignore (illustrative)
 /// impl Tr for A { }
 /// impl Tr for (B, B) { }
+/// ```
 ///
 /// Note that only consider the unconstrained parameters of the base impl:
 ///
+/// ```ignore (illustrative)
 /// impl> Tr for I { }
 /// impl Tr for Vec { }
+/// ```
 ///
 /// The substs for the parent impl here are `[T, Vec]`, which repeats `T`,
 /// but `S` is constrained in the parent impl, so `parent_substs` is only
@@ -256,8 +262,10 @@ fn check_duplicate_params<'tcx>(
 ///
 /// For example forbid the following:
 ///
+/// ```ignore (illustrative)
 /// impl Tr for A { }
 /// impl Tr for &'static i32 { }
+/// ```
 fn check_static_lifetimes<'tcx>(
     tcx: TyCtxt<'tcx>,
     parent_substs: &Vec>,
diff --git a/compiler/rustc_hir_analysis/src/mem_categorization.rs b/compiler/rustc_hir_analysis/src/mem_categorization.rs
index a6880c7e77ac..b62c5b5e0778 100644
--- a/compiler/rustc_hir_analysis/src/mem_categorization.rs
+++ b/compiler/rustc_hir_analysis/src/mem_categorization.rs
@@ -184,7 +184,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     ///   modes #42640) may look like `Some(x)` but in fact have
     ///   implicit deref patterns attached (e.g., it is really
     ///   `&Some(x)`). In that case, we return the "outermost" type
-    ///   (e.g., `&Option).
+    ///   (e.g., `&Option`).
     pub(crate) fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult> {
         // Check for implicit `&` types wrapping the pattern; note
         // that these are never attached to binding patterns, so
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 84374a25ed85..f46f0ea4cabe 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -203,7 +203,7 @@ pub enum StmtKind<'tcx> {
         /// `let pat: ty = `
         initializer: Option,
 
-        /// `let pat: ty =  else {  }
+        /// `let pat: ty =  else {  }`
         else_block: Option,
 
         /// The lint level for this `let` statement.
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 80bbc8e630e0..26b6be7a1b89 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -332,13 +332,13 @@ impl<'tcx> AdtDef<'tcx> {
         self.flags().contains(AdtFlags::IS_PHANTOM_DATA)
     }
 
-    /// Returns `true` if this is Box.
+    /// Returns `true` if this is `Box`.
     #[inline]
     pub fn is_box(self) -> bool {
         self.flags().contains(AdtFlags::IS_BOX)
     }
 
-    /// Returns `true` if this is UnsafeCell.
+    /// Returns `true` if this is `UnsafeCell`.
     #[inline]
     pub fn is_unsafe_cell(self) -> bool {
         self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 0bdfe10359c0..3dcadb4c9115 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -39,7 +39,8 @@ mod errors;
 // uses a HOF to parse anything, and  includes file and
 // `source_str`.
 
-/// A variant of 'panictry!' that works on a Vec instead of a single DiagnosticBuilder.
+/// A variant of 'panictry!' that works on a `Vec` instead of a single
+/// `DiagnosticBuilder`.
 macro_rules! panictry_buffer {
     ($handler:expr, $e:expr) => {{
         use rustc_errors::FatalError;
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index c716c4b0be90..ed34ab95ad6c 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -66,13 +66,13 @@ impl<'tcx> AutoTraitFinder<'tcx> {
     /// struct Foo { data: Box }
     /// ```
     ///
-    /// then this might return that Foo: Send if T: Send (encoded in the AutoTraitResult type).
-    /// The analysis attempts to account for custom impls as well as other complex cases. This
-    /// result is intended for use by rustdoc and other such consumers.
+    /// then this might return that `Foo: Send` if `T: Send` (encoded in the AutoTraitResult
+    /// type). The analysis attempts to account for custom impls as well as other complex cases.
+    /// This result is intended for use by rustdoc and other such consumers.
     ///
     /// (Note that due to the coinductive nature of Send, the full and correct result is actually
     /// quite simple to generate. That is, when a type has no custom impl, it is Send iff its field
-    /// types are all Send. So, in our example, we might have that Foo: Send if Box: Send.
+    /// types are all Send. So, in our example, we might have that `Foo: Send` if `Box: Send`.
     /// But this is often not the best way to present to the user.)
     ///
     /// Warning: The API should be considered highly unstable, and it may be refactored or removed
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index e1485079487c..511646b0eaf2 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -62,7 +62,8 @@ enum ProjectionCandidate<'tcx> {
     /// From a where-clause in the env or object type
     ParamEnv(ty::PolyProjectionPredicate<'tcx>),
 
-    /// From the definition of `Trait` when you have something like <::B as Trait2>::C
+    /// From the definition of `Trait` when you have something like
+    /// `<::B as Trait2>::C`.
     TraitDef(ty::PolyProjectionPredicate<'tcx>),
 
     /// Bounds specified on an object type
@@ -1367,7 +1368,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
     );
 }
 
-/// In the case of a nested projection like <::FooT as Bar>::BarT, we may find
+/// In the case of a nested projection like `<::FooT as Bar>::BarT`, we may find
 /// that the definition of `Foo` has some clues:
 ///
 /// ```ignore (illustrative)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 3f445f9ca464..ddabea700d37 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -826,7 +826,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// must be met of course). One obvious case this comes up is
     /// marker traits like `Send`. Think of a linked list:
     ///
-    ///    struct List { data: T, next: Option>> }
+    ///     struct List { data: T, next: Option>> }
     ///
     /// `Box>` will be `Send` if `T` is `Send` and
     /// `Option>>` is `Send`, and in turn

From 14de94aec59bcd535f690e255a950ca76fcf2d5a Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Mon, 10 Oct 2022 18:29:17 +0200
Subject: [PATCH 155/175] Fix unclosed HTML tag in rustfmt doc

---
 src/tools/rustfmt/src/config/config_type.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/rustfmt/src/config/config_type.rs b/src/tools/rustfmt/src/config/config_type.rs
index e37ed798cb55..c5e61658ad1e 100644
--- a/src/tools/rustfmt/src/config/config_type.rs
+++ b/src/tools/rustfmt/src/config/config_type.rs
@@ -4,7 +4,7 @@ use crate::config::options::{IgnoreList, WidthHeuristics};
 /// Trait for types that can be used in `Config`.
 pub(crate) trait ConfigType: Sized {
     /// Returns hint text for use in `Config::print_docs()`. For enum types, this is a
-    /// pipe-separated list of variants; for other types it returns "".
+    /// pipe-separated list of variants; for other types it returns ``.
     fn doc_hint() -> String;
 }
 

From a474ec50b7010d289d103242a63c806ed6f01c2e Mon Sep 17 00:00:00 2001
From: Camille GILLOT 
Date: Sun, 9 Oct 2022 20:26:39 +0000
Subject: [PATCH 156/175] Move lifetime resolution module to
 rustc_hir_analysis.

---
 compiler/rustc_hir_analysis/src/collect.rs      |  2 ++
 .../src/collect}/lifetimes.rs                   | 17 +++--------------
 compiler/rustc_interface/src/passes.rs          |  1 -
 compiler/rustc_resolve/src/late.rs              |  1 -
 compiler/rustc_resolve/src/lib.rs               |  5 -----
 5 files changed, 5 insertions(+), 21 deletions(-)
 rename compiler/{rustc_resolve/src/late => rustc_hir_analysis/src/collect}/lifetimes.rs (99%)

diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 6976c5a0edbd..98bcdcf65201 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -46,6 +46,7 @@ use std::iter;
 
 mod generics_of;
 mod item_bounds;
+mod lifetimes;
 mod predicates_of;
 mod type_of;
 
@@ -57,6 +58,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
 }
 
 pub fn provide(providers: &mut Providers) {
+    lifetimes::provide(providers);
     *providers = Providers {
         opt_const_param_of: type_of::opt_const_param_of,
         type_of: type_of::type_of,
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
similarity index 99%
rename from compiler/rustc_resolve/src/late/lifetimes.rs
rename to compiler/rustc_hir_analysis/src/collect/lifetimes.rs
index c18d5d06d64b..c1214698cf77 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
@@ -32,8 +32,6 @@ trait RegionExt {
     fn id(&self) -> Option;
 
     fn shifted(self, amount: u32) -> Region;
-
-    fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region;
 }
 
 impl RegionExt for Region {
@@ -69,15 +67,6 @@ impl RegionExt for Region {
             _ => self,
         }
     }
-
-    fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region {
-        match self {
-            Region::LateBound(debruijn, index, id) => {
-                Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id)
-            }
-            _ => self,
-        }
-    }
 }
 
 /// Maps the id of each lifetime reference to the lifetime decl
@@ -101,8 +90,8 @@ struct NamedRegionMap {
     late_bound_vars: HirIdMap>,
 }
 
-pub(crate) struct LifetimeContext<'a, 'tcx> {
-    pub(crate) tcx: TyCtxt<'tcx>,
+struct LifetimeContext<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
     map: &'a mut NamedRegionMap,
     scope: ScopeRef<'a>,
 
@@ -234,7 +223,7 @@ type ScopeRef<'a> = &'a Scope<'a>;
 
 const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
 
-pub fn provide(providers: &mut ty::query::Providers) {
+pub(crate) fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         resolve_lifetimes_trait_definition,
         resolve_lifetimes,
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index ad3e020b581b..8fd4224ca38f 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -739,7 +739,6 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| {
     ty::provide(providers);
     traits::provide(providers);
     rustc_passes::provide(providers);
-    rustc_resolve::provide(providers);
     rustc_traits::provide(providers);
     rustc_ty_utils::provide(providers);
     rustc_metadata::provide(providers);
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 989a827ef7d9..c08f4a7204d8 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -34,7 +34,6 @@ use std::collections::{hash_map::Entry, BTreeSet};
 use std::mem::{replace, take};
 
 mod diagnostics;
-pub(crate) mod lifetimes;
 
 type Res = def::Res;
 
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 9173c3692ce6..095a57ae24fe 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -42,7 +42,6 @@ use rustc_metadata::creader::{CStore, CrateLoader};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::span_bug;
-use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::cstore::{CrateStore, CrateStoreDyn, MetadataLoaderDyn};
@@ -2082,7 +2081,3 @@ impl Finalize {
         Finalize { node_id, path_span, root_span, report_private: true }
     }
 }
-
-pub fn provide(providers: &mut Providers) {
-    late::lifetimes::provide(providers);
-}

From 68260289b5afa6728c32378c581e67c714ea4263 Mon Sep 17 00:00:00 2001
From: Takayuki Maeda 
Date: Tue, 11 Oct 2022 02:43:36 +0900
Subject: [PATCH 157/175] fix #102878

---
 compiler/rustc_error_messages/src/lib.rs     | 13 -----
 compiler/rustc_expand/src/mbe/macro_rules.rs | 23 ++++----
 src/test/ui/macros/issue-102878.rs           | 10 ++++
 src/test/ui/macros/issue-102878.stderr       | 60 ++++++++++++++++++++
 4 files changed, 83 insertions(+), 23 deletions(-)
 create mode 100644 src/test/ui/macros/issue-102878.rs
 create mode 100644 src/test/ui/macros/issue-102878.stderr

diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 18be60975e4e..9a7cb955f216 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -336,19 +336,6 @@ impl DiagnosticMessage {
             }
         }
     }
-
-    /// Returns the `String` contained within the `DiagnosticMessage::Str` variant, assuming that
-    /// this diagnostic message is of the legacy, non-translatable variety. Panics if this
-    /// assumption does not hold.
-    ///
-    /// Don't use this - it exists to support some places that do comparison with diagnostic
-    /// strings.
-    pub fn expect_str(&self) -> &str {
-        match self {
-            DiagnosticMessage::Str(s) => s,
-            _ => panic!("expected non-translatable diagnostic message"),
-        }
-    }
 }
 
 /// `From` impl that enables existing diagnostic calls to functions which now take
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 6d2c7aac6af4..30aa4f0fa348 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage};
 use rustc_feature::Features;
 use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
@@ -68,19 +68,22 @@ fn emit_frag_parse_err(
     kind: AstFragmentKind,
 ) {
     // FIXME(davidtwco): avoid depending on the error message text
-    if parser.token == token::Eof && e.message[0].0.expect_str().ends_with(", found ``") {
+    if parser.token == token::Eof
+        && let DiagnosticMessage::Str(message) = &e.message[0].0
+        && message.ends_with(", found ``")
+    {
+        let msg = &e.message[0];
+        e.message[0] = (
+            DiagnosticMessage::Str(format!(
+                "macro expansion ends with an incomplete expression: {}",
+                message.replace(", found ``", ""),
+            )),
+            msg.1,
+        );
         if !e.span.is_dummy() {
             // early end of macro arm (#52866)
             e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
         }
-        let msg = &e.message[0];
-        e.message[0] = (
-            rustc_errors::DiagnosticMessage::Str(format!(
-                "macro expansion ends with an incomplete expression: {}",
-                msg.0.expect_str().replace(", found ``", ""),
-            )),
-            msg.1,
-        );
     }
     if e.span.is_dummy() {
         // Get around lack of span in error (#30128)
diff --git a/src/test/ui/macros/issue-102878.rs b/src/test/ui/macros/issue-102878.rs
new file mode 100644
index 000000000000..aac5891939e0
--- /dev/null
+++ b/src/test/ui/macros/issue-102878.rs
@@ -0,0 +1,10 @@
+macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+//~^ ERROR mismatched closing delimiter: `)`
+//~| ERROR invalid fragment specifier `r`
+//~| ERROR expected identifier, found keyword `const`
+//~| ERROR expected identifier, found keyword `const`
+//~| ERROR expected identifier, found `:`
+
+fn s(){test!(1,i)}
+
+fn main() {}
diff --git a/src/test/ui/macros/issue-102878.stderr b/src/test/ui/macros/issue-102878.stderr
new file mode 100644
index 000000000000..e0b8855a38d0
--- /dev/null
+++ b/src/test/ui/macros/issue-102878.stderr
@@ -0,0 +1,60 @@
+error: mismatched closing delimiter: `)`
+  --> $DIR/issue-102878.rs:1:35
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+   |                                  -^         ^ mismatched closing delimiter
+   |                                  ||
+   |                                  |unclosed delimiter
+   |                                  closing delimiter possibly meant for this
+
+error: invalid fragment specifier `r`
+  --> $DIR/issue-102878.rs:1:27
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+   |                           ^^^^
+   |
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+
+error: expected identifier, found keyword `const`
+  --> $DIR/issue-102878.rs:1:36
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+   |                                    ^^^^^ expected identifier, found keyword
+...
+LL | fn s(){test!(1,i)}
+   |        ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: escape `const` to use it as an identifier
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({r#const:y y)}
+   |                                    ++
+
+error: expected identifier, found keyword `const`
+  --> $DIR/issue-102878.rs:1:36
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+   |                                    ^^^^^ expected identifier, found keyword
+...
+LL | fn s(){test!(1,i)}
+   |        ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: escape `const` to use it as an identifier
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({r#const:y y)}
+   |                                    ++
+
+error: expected identifier, found `:`
+  --> $DIR/issue-102878.rs:1:41
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+   |                                         ^ expected identifier
+...
+LL | fn s(){test!(1,i)}
+   |        ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 5 previous errors
+

From a52cde3da55535b6936b551cc4cf95dbeded78bb Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Mon, 10 Oct 2022 20:13:45 +0200
Subject: [PATCH 158/175] update compiler_builtins

---
 Cargo.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 3b8d0d87f2a9..0c57dea15d6d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -796,9 +796,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.79"
+version = "0.1.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f873ce2bd3550b0b565f878b3d04ea8253f4259dc3d20223af2e1ba86f5ecca"
+checksum = "18cd7635fea7bb481ea543b392789844c1ad581299da70184c7175ce3af76603"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",

From b63b02f8728259c3b67d1f6ca7d1845892b86a9e Mon Sep 17 00:00:00 2001
From: Michael Howell 
Date: Mon, 10 Oct 2022 11:37:19 -0700
Subject: [PATCH 159/175] rustdoc: remove unneeded `
` wrapper from sidebar DOM When this was added, the sidebar had a bit more complex style. It can be removed, now. --- src/librustdoc/html/render/mod.rs | 23 +++++----------- src/librustdoc/html/static/css/rustdoc.css | 5 ++-- src/librustdoc/html/static/js/main.js | 26 ++++++++----------- src/test/rustdoc-gui/headings.goml | 4 +-- src/test/rustdoc-gui/sidebar.goml | 20 +++++++------- .../strip-enum-variant.no-not-shown.html | 2 +- src/test/rustdoc/strip-enum-variant.rs | 2 +- 7 files changed, 35 insertions(+), 47 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 4bbb322d3701..5e4226042ec7 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1853,12 +1853,12 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { buffer.write_str("
"); if it.is_crate() { - write!(buffer, ""); + buffer.write_str(""); } match *it.kind { @@ -2259,7 +2259,7 @@ fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String } /// Don't call this function directly!!! Use `print_sidebar_title` or `print_sidebar_block` instead! -fn print_sidebar_title_inner(buf: &mut Buffer, id: &str, title: &str) { +fn print_sidebar_title(buf: &mut Buffer, id: &str, title: &str) { write!( buf, "

\ @@ -2269,25 +2269,18 @@ fn print_sidebar_title_inner(buf: &mut Buffer, id: &str, title: &str) { ); } -fn print_sidebar_title(buf: &mut Buffer, id: &str, title: &str) { - buf.push_str("
"); - print_sidebar_title_inner(buf, id, title); - buf.push_str("
"); -} - fn print_sidebar_block( buf: &mut Buffer, id: &str, title: &str, items: impl Iterator, ) { - buf.push_str("
"); - print_sidebar_title_inner(buf, id, title); - buf.push_str("
    "); + print_sidebar_title(buf, id, title); + buf.push_str("
      "); for item in items { write!(buf, "
    • {}
    • ", item); } - buf.push_str("
"); + buf.push_str(""); } fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { @@ -2676,9 +2669,7 @@ pub(crate) fn sidebar_module_like(buf: &mut Buffer, item_sections_in_use: FxHash write!( buf, "
\ -
\ -
    {}
\ -
\ +
    {}
\
", sidebar ); diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index eb64147d9067..386977c6f8e7 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -501,13 +501,14 @@ img { width: 100px; } -.block ul, .block li { +ul.block, .block li { padding: 0; margin: 0; list-style: none; } .block a, +.sidebar h3 a, h2.location a { display: block; padding: 0.25rem; @@ -769,7 +770,7 @@ h2.small-section-header > .anchor { text-decoration: underline; } -.block a.current.crate { font-weight: 500; } +.crate.block a.current { font-weight: 500; } /* In most contexts we use `overflow-wrap: anywhere` to ensure that we can wrap as much as needed on mobile (see diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 359dd41b13fe..0180c0ead8d3 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -442,12 +442,10 @@ function loadCss(cssFileName) { return; } - const div = document.createElement("div"); - div.className = "block " + shortty; const h3 = document.createElement("h3"); h3.innerHTML = `${longty}`; - div.appendChild(h3); const ul = document.createElement("ul"); + ul.className = "block " + shortty; for (const item of filtered) { const name = item[0]; @@ -473,8 +471,8 @@ function loadCss(cssFileName) { li.appendChild(link); ul.appendChild(li); } - div.appendChild(ul); - sidebar.appendChild(div); + sidebar.appendChild(h3); + sidebar.appendChild(ul); } if (sidebar) { @@ -592,27 +590,25 @@ function loadCss(cssFileName) { return; } // Draw a convenient sidebar of known crates if we have a listing - const div = document.createElement("div"); - div.className = "block crate"; - div.innerHTML = "

Crates

"; + const h3 = document.createElement("h3"); + h3.innerHTML = "Crates"; const ul = document.createElement("ul"); - div.appendChild(ul); + ul.className = "block crate"; for (const crate of window.ALL_CRATES) { - let klass = "crate"; - if (window.rootPath !== "./" && crate === window.currentCrate) { - klass += " current"; - } const link = document.createElement("a"); link.href = window.rootPath + crate + "/index.html"; - link.className = klass; + if (window.rootPath !== "./" && crate === window.currentCrate) { + link.className = "current"; + } link.textContent = crate; const li = document.createElement("li"); li.appendChild(link); ul.appendChild(li); } - sidebarElems.appendChild(div); + sidebarElems.appendChild(h3); + sidebarElems.appendChild(ul); } diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml index 3e97bb78c781..9a77d8bbd154 100644 --- a/src/test/rustdoc-gui/headings.goml +++ b/src/test/rustdoc-gui/headings.goml @@ -106,8 +106,8 @@ assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0 assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "14px"}) assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"}) -assert-text: (".sidebar .mod h3", "Modules") -assert-css: (".sidebar .mod h3", {"border-bottom-width": "0px"}, ALL) +assert-text: ("//ul[@class='block mod']/preceding-sibling::h3", "Modules") +assert-css: ("//ul[@class='block mod']/preceding-sibling::h3", {"border-bottom-width": "0px"}, ALL) goto: "file://" + |DOC_PATH| + "/test_docs/union.HeavilyDocumentedUnion.html" diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml index ad1fb6df89ae..54193234af9d 100644 --- a/src/test/rustdoc-gui/sidebar.goml +++ b/src/test/rustdoc-gui/sidebar.goml @@ -12,7 +12,7 @@ assert-count: (".sidebar .location", 1) assert-text: ("#all-types", "All Items") assert-css: ("#all-types", {"color": "rgb(53, 109, 164)"}) // We check that we have the crates list and that the "current" on is "test_docs". -assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs") +assert-text: (".sidebar-elems ul.crate > li > a.current", "test_docs") // And we're also supposed to have the list of items in the current module. assert-text: (".sidebar-elems section ul > li:nth-child(1)", "Re-exports") assert-text: (".sidebar-elems section ul > li:nth-child(2)", "Modules") @@ -41,21 +41,21 @@ assert-property: ("html", {"scrollTop": "0"}) // We now go back to the crate page to click on the "lib2" crate link. goto: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) -assert-css: (".sidebar-elems .crate > ul > li:first-child > a", {"color": "rgb(53, 109, 164)"}) -click: ".sidebar-elems .crate > ul > li:first-child > a" +assert-css: (".sidebar-elems ul.crate > li:first-child > a", {"color": "rgb(53, 109, 164)"}) +click: ".sidebar-elems ul.crate > li:first-child > a" // PAGE: lib2/index.html goto: "file://" + |DOC_PATH| + "/lib2/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) assert-text: (".sidebar > .location", "Crate lib2") // We check that we have the crates list and that the "current" on is now "lib2". -assert-text: (".sidebar-elems .crate > ul > li > a.current", "lib2") +assert-text: (".sidebar-elems ul.crate > li > a.current", "lib2") // We now go to the "foobar" function page. -assert-text: (".sidebar-elems > section .block ul > li:nth-child(1)", "Modules") -assert-text: (".sidebar-elems > section .block ul > li:nth-child(2)", "Structs") -assert-text: (".sidebar-elems > section .block ul > li:nth-child(3)", "Traits") -assert-text: (".sidebar-elems > section .block ul > li:nth-child(4)", "Functions") -assert-text: (".sidebar-elems > section .block ul > li:nth-child(5)", "Type Definitions") +assert-text: (".sidebar-elems > section ul.block > li:nth-child(1)", "Modules") +assert-text: (".sidebar-elems > section ul.block > li:nth-child(2)", "Structs") +assert-text: (".sidebar-elems > section ul.block > li:nth-child(3)", "Traits") +assert-text: (".sidebar-elems > section ul.block > li:nth-child(4)", "Functions") +assert-text: (".sidebar-elems > section ul.block > li:nth-child(5)", "Type Definitions") assert-text: ("#functions + .item-table .item-left > a", "foobar") click: "#functions + .item-table .item-left > a" @@ -90,7 +90,7 @@ assert-property: (".sidebar-elems section .block li > a", {"offsetHeight": 29}) // appropriate anchor in index.html. goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" assert-property: (".sidebar", {"clientWidth": "200"}) -click: ".block.mod h3 a" +click: "//ul[@class='block mod']/preceding-sibling::h3/a" // PAGE: index.html assert-css: ("#modules", {"background-color": "rgb(253, 255, 211)"}) diff --git a/src/test/rustdoc/strip-enum-variant.no-not-shown.html b/src/test/rustdoc/strip-enum-variant.no-not-shown.html index c4ee1a991143..782198956a0f 100644 --- a/src/test/rustdoc/strip-enum-variant.no-not-shown.html +++ b/src/test/rustdoc/strip-enum-variant.no-not-shown.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/test/rustdoc/strip-enum-variant.rs b/src/test/rustdoc/strip-enum-variant.rs index f82ffdfeda58..8753a7dc613a 100644 --- a/src/test/rustdoc/strip-enum-variant.rs +++ b/src/test/rustdoc/strip-enum-variant.rs @@ -3,7 +3,7 @@ // @!has - '//code' 'NotShown' // @has - '//code' '// some variants omitted' // Also check that `NotShown` isn't displayed in the sidebar. -// @snapshot no-not-shown - '//*[@class="sidebar-elems"]/section/*[@class="block"][1]/ul' +// @snapshot no-not-shown - '//*[@class="sidebar-elems"]/section/*[@class="block"][1]' pub enum MyThing { Shown, #[doc(hidden)] From d565200270d425ab2d72b06109314c786676f593 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 10 Oct 2022 20:45:04 +0200 Subject: [PATCH 160/175] Fix unclosed HTML tag in clippy doc --- src/tools/clippy/clippy_utils/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 42374fdd7baf..e7e3625c078a 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2064,9 +2064,9 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { } } -/// Returns Option where String is a textual representation of the type encapsulated in the -/// slice iff the given expression is a slice of primitives (as defined in the -/// `is_recursively_primitive_type` function) and None otherwise. +/// Returns `Option` where String is a textual representation of the type encapsulated in +/// the slice iff the given expression is a slice of primitives (as defined in the +/// `is_recursively_primitive_type` function) and `None` otherwise. pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let expr_type = cx.typeck_results().expr_ty_adjusted(expr); let expr_kind = expr_type.kind(); From d933092dc507b11a7e5013616128161a76c6f113 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 10 Oct 2022 11:22:41 -0500 Subject: [PATCH 161/175] Check representability in adt_sized_constraint --- .../rustc_hir_analysis/src/check/check.rs | 3 -- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 ++ compiler/rustc_middle/src/query/mod.rs | 10 +------ compiler/rustc_middle/src/ty/adt.rs | 5 +--- compiler/rustc_middle/src/ty/query.rs | 2 +- compiler/rustc_middle/src/values.rs | 14 +-------- compiler/rustc_ty_utils/src/ty.rs | 12 +++++--- ...finite-recursive-type-impl-trait-return.rs | 3 +- ...te-recursive-type-impl-trait-return.stderr | 17 ----------- .../infinite-recursive-type-impl-trait.rs | 4 ++- .../infinite-recursive-type-impl-trait.stderr | 17 ----------- src/test/ui/issues/issue-72554.rs | 1 - src/test/ui/issues/issue-72554.stderr | 20 ++----------- .../variance-regions-unused-indirect.rs | 1 + .../variance-regions-unused-indirect.stderr | 30 +++++++++++++++++-- 15 files changed, 50 insertions(+), 91 deletions(-) delete mode 100644 src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr delete mode 100644 src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index c92d8dfb6027..aa5017488836 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -380,7 +380,6 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); def.destructor(tcx); // force the destructor to be evaluated - let _ = tcx.representability(def_id); if def.repr().simd() { check_simd(tcx, span, def_id); @@ -394,7 +393,6 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); def.destructor(tcx); // force the destructor to be evaluated - let _ = tcx.representability(def_id); check_transparent(tcx, span, def); check_union_fields(tcx, span, def_id); check_packed(tcx, span, def); @@ -1487,7 +1485,6 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp); - let _ = tcx.representability(def_id); check_transparent(tcx, sp, def); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0bd45bb1c915..0a8a1bec9b8a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1041,6 +1041,8 @@ fn check_type_defn<'tcx, F>( ) where F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec>, { + let _ = tcx.representability(item.def_id.def_id); + enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| { let variants = lookup_fields(wfcx); let packed = tcx.adt_def(item.def_id).repr().packed(); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a175b1eb4673..06eb10c9137a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -613,16 +613,8 @@ rustc_queries! { separate_provide_extern } - // The cycle error here should be reported as an error by `check_representable`. - // We consider the type as Sized in the meanwhile to avoid - // further errors (done in impl Value for AdtSizedConstraint). - // Use `cycle_delay_bug` to delay the cycle error here to be emitted later - // in case we accidentally otherwise don't emit an error. - query adt_sized_constraint( - key: DefId - ) -> AdtSizedConstraint<'tcx> { + query adt_sized_constraint(key: DefId) -> &'tcx [Ty<'tcx>] { desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) } - cycle_delay_bug } query adt_dtorck_constraint( diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 80bbc8e630e0..cc22913c2de9 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -26,9 +26,6 @@ use super::{ Destructor, FieldDef, GenericPredicates, ReprOptions, Ty, TyCtxt, VariantDef, VariantDiscr, }; -#[derive(Copy, Clone, HashStable, Debug)] -pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]); - bitflags! { #[derive(HashStable, TyEncodable, TyDecodable)] pub struct AdtFlags: u32 { @@ -563,7 +560,7 @@ impl<'tcx> AdtDef<'tcx> { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer (e.g., issue #31299). pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> { - ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0) + ty::EarlyBinder(tcx.adt_sized_constraint(self.did())) } } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index b6cda34c51f6..ce1b69935f27 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -32,7 +32,7 @@ use crate::ty::layout::TyAndLayout; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::GeneratorDiagnosticData; -use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; +use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index bb89959b29de..f4b4c3fb05a7 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -3,7 +3,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::ty::Representability; -use rustc_middle::ty::{self, AdtSizedConstraint, DefIdTree, Ty, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc_query_system::query::QueryInfo; use rustc_query_system::Value; use rustc_span::def_id::LocalDefId; @@ -31,18 +31,6 @@ impl<'tcx> Value> for ty::SymbolName<'_> { } } -impl<'tcx> Value> for AdtSizedConstraint<'_> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self { - // SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`. - // FIXME: Represent the above fact in the trait system somehow. - unsafe { - std::mem::transmute::, AdtSizedConstraint<'_>>( - AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])), - ) - } - } -} - impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self { let err = tcx.ty_error(); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 30efbf661759..cd9d22964057 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -85,9 +85,13 @@ fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness { /// - a type parameter or projection whose Sizedness can't be known /// - a tuple of type parameters or projections, if there are multiple /// such. -/// - an Error, if a type contained itself. The representability -/// check should catch this case. -fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> { +/// - an Error, if a type is infinitely sized +fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] { + if let Some(def_id) = def_id.as_local() { + if matches!(tcx.representability(def_id), ty::Representability::Infinite) { + return tcx.intern_type_list(&[tcx.ty_error()]); + } + } let def = tcx.adt_def(def_id); let result = tcx.mk_type_list( @@ -99,7 +103,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain debug!("adt_sized_constraint: {:?} => {:?}", def, result); - ty::AdtSizedConstraint(result) + result } /// See `ParamEnv` struct definition for details. diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs index 2319de556836..4b1e04234c87 100644 --- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs +++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs @@ -1,11 +1,12 @@ +// check-pass // normalize-stderr-test: "`.*`" -> "`DEF_ID`" // normalize-stdout-test: "`.*`" -> "`DEF_ID`" // edition:2018 pub async fn f() -> impl std::fmt::Debug { + // rustdoc doesn't care that this is infinitely sized #[derive(Debug)] enum E { - //~^ ERROR recursive type `f::{closure#0}::E` has infinite size This(E), Unit, } diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr deleted file mode 100644 index e6ab67d59ce5..000000000000 --- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0072]: recursive type `DEF_ID` has infinite size - --> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5 - | -LL | enum E { - | ^^^^^^ -LL | -LL | This(E), - | - recursive without indirection - | -help: insert some indirection (e.g., a `DEF_ID`) to break the cycle - | -LL | This(Box), - | ++++ + - -error: aborting due to previous error - -For more information about this error, try `DEF_ID`. diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs index b3a7ee563130..ac79582fb3f0 100644 --- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs +++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs @@ -1,6 +1,8 @@ +// check-pass + fn f() -> impl Sized { + // rustdoc doesn't care that this is infinitely sized enum E { - //~^ ERROR recursive type `f::E` has infinite size V(E), } unimplemented!() diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr deleted file mode 100644 index 165ff6783724..000000000000 --- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0072]: recursive type `f::E` has infinite size - --> $DIR/infinite-recursive-type-impl-trait.rs:2:5 - | -LL | enum E { - | ^^^^^^ -LL | -LL | V(E), - | - recursive without indirection - | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle - | -LL | V(Box), - | ++++ + - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/issues/issue-72554.rs b/src/test/ui/issues/issue-72554.rs index 7287639c61dd..54f7e9ac592e 100644 --- a/src/test/ui/issues/issue-72554.rs +++ b/src/test/ui/issues/issue-72554.rs @@ -3,7 +3,6 @@ use std::collections::BTreeSet; #[derive(Hash)] pub enum ElemDerived { //~^ ERROR recursive type `ElemDerived` has infinite size - //~| ERROR cycle detected when computing drop-check constraints for `ElemDerived` A(ElemDerived) } diff --git a/src/test/ui/issues/issue-72554.stderr b/src/test/ui/issues/issue-72554.stderr index bc85cd7b18d5..d12be539f7c1 100644 --- a/src/test/ui/issues/issue-72554.stderr +++ b/src/test/ui/issues/issue-72554.stderr @@ -3,7 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size | LL | pub enum ElemDerived { | ^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | A(ElemDerived) | ----------- recursive without indirection | @@ -12,20 +12,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | A(Box) | ++++ + -error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived` - --> $DIR/issue-72554.rs:4:1 - | -LL | pub enum ElemDerived { - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: ...which immediately requires computing drop-check constraints for `ElemDerived` again -note: cycle used when computing drop-check constraints for `Elem` - --> $DIR/issue-72554.rs:11:1 - | -LL | pub enum Elem { - | ^^^^^^^^^^^^^ +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/variance/variance-regions-unused-indirect.rs b/src/test/ui/variance/variance-regions-unused-indirect.rs index 1514e39563e1..6c2c24ddbc72 100644 --- a/src/test/ui/variance/variance-regions-unused-indirect.rs +++ b/src/test/ui/variance/variance-regions-unused-indirect.rs @@ -1,6 +1,7 @@ // Test that disallow lifetime parameters that are unused. enum Foo<'a> { //~ ERROR parameter `'a` is never used + //~^ ERROR recursive types `Foo` and `Bar` have infinite size Foo1(Bar<'a>) } diff --git a/src/test/ui/variance/variance-regions-unused-indirect.stderr b/src/test/ui/variance/variance-regions-unused-indirect.stderr index 93710cc133aa..14fdd849294b 100644 --- a/src/test/ui/variance/variance-regions-unused-indirect.stderr +++ b/src/test/ui/variance/variance-regions-unused-indirect.stderr @@ -1,3 +1,26 @@ +error[E0072]: recursive types `Foo` and `Bar` have infinite size + --> $DIR/variance-regions-unused-indirect.rs:3:1 + | +LL | enum Foo<'a> { + | ^^^^^^^^^^^^ +LL | +LL | Foo1(Bar<'a>) + | ------- recursive without indirection +... +LL | enum Bar<'a> { + | ^^^^^^^^^^^^ +LL | Bar1(Foo<'a>) + | ------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL ~ Foo1(Box>) +LL | } +LL | +LL | enum Bar<'a> { +LL ~ Bar1(Box>) + | + error[E0392]: parameter `'a` is never used --> $DIR/variance-regions-unused-indirect.rs:3:10 | @@ -7,13 +30,14 @@ LL | enum Foo<'a> { = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `'a` is never used - --> $DIR/variance-regions-unused-indirect.rs:7:10 + --> $DIR/variance-regions-unused-indirect.rs:8:10 | LL | enum Bar<'a> { | ^^ unused parameter | = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0392`. +Some errors have detailed explanations: E0072, E0392. +For more information about an error, try `rustc --explain E0072`. From d1762d7a96adbeb4702bcb4486ebf47555bfd01b Mon Sep 17 00:00:00 2001 From: Ariel Davis Date: Mon, 10 Oct 2022 17:05:59 -0700 Subject: [PATCH 162/175] Do not alias for fs --- library/std/src/fs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 190608e43b92..c6c78dc3939e 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1670,7 +1670,6 @@ impl DirEntry { /// } /// ``` #[must_use] - #[doc(alias = "basename")] #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub fn file_name(&self) -> OsString { self.0.file_name() From 44f466cb08650a721d06dece85385506633d55fc Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 10 Oct 2022 17:53:27 -0700 Subject: [PATCH 163/175] Remove outdated comment --- src/librustdoc/html/render/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 5e4226042ec7..1e162bf314b8 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2258,7 +2258,6 @@ fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String } } -/// Don't call this function directly!!! Use `print_sidebar_title` or `print_sidebar_block` instead! fn print_sidebar_title(buf: &mut Buffer, id: &str, title: &str) { write!( buf, From 1a8f177772658a244e79a9aa2d48898a4e24c9ce Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 10 Oct 2022 19:21:35 +0400 Subject: [PATCH 164/175] rustc_hir: Less error-prone methods for accessing `PartialRes` resolution --- compiler/rustc_ast_lowering/src/asm.rs | 11 +++--- compiler/rustc_ast_lowering/src/expr.rs | 8 ++--- compiler/rustc_ast_lowering/src/item.rs | 9 +++-- compiler/rustc_ast_lowering/src/lib.rs | 24 +++++-------- compiler/rustc_ast_lowering/src/pat.rs | 2 +- compiler/rustc_ast_lowering/src/path.rs | 10 +++--- compiler/rustc_hir/src/def.rs | 10 ++++++ .../rustc_resolve/src/build_reduced_graph.rs | 2 +- compiler/rustc_resolve/src/late.rs | 28 ++++++++------- .../rustc_resolve/src/late/diagnostics.rs | 36 ++++++++----------- compiler/rustc_resolve/src/lib.rs | 16 +++------ compiler/rustc_resolve/src/macros.rs | 9 ++--- 12 files changed, 75 insertions(+), 90 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 85306d7184d8..54c83fb76046 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -205,13 +205,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let static_def_id = self .resolver .get_partial_res(sym.id) - .filter(|res| res.unresolved_segments() == 0) - .and_then(|res| { - if let Res::Def(DefKind::Static(_), def_id) = res.base_res() { - Some(def_id) - } else { - None - } + .and_then(|res| res.full_res()) + .and_then(|res| match res { + Res::Def(DefKind::Static(_), def_id) => Some(def_id), + _ => None, }); if let Some(def_id) = static_def_id { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 46886c518afd..c55b49063020 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1044,9 +1044,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if let ExprKind::Path(qself, path) = &expr.kind { // Does the path resolve to something disallowed in a tuple struct/variant pattern? if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { - if partial_res.unresolved_segments() == 0 - && !partial_res.base_res().expected_in_tuple_struct_pat() - { + if let Some(res) = partial_res.full_res() && !res.expected_in_tuple_struct_pat() { return None; } } @@ -1066,9 +1064,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if let ExprKind::Path(qself, path) = &expr.kind { // Does the path resolve to something disallowed in a unit struct/variant pattern? if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { - if partial_res.unresolved_segments() == 0 - && !partial_res.base_res().expected_in_unit_struct_pat() - { + if let Some(res) = partial_res.full_res() && !res.expected_in_unit_struct_pat() { return None; } } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 56d71aaa7d33..687d810ed4e3 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -947,7 +947,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } AssocItemKind::MacCall(..) => unimplemented!(), }, - trait_item_def_id: self.resolver.get_partial_res(i.id).map(|r| r.base_res().def_id()), + trait_item_def_id: self + .resolver + .get_partial_res(i.id) + .map(|r| r.expect_full_res().def_id()), } } @@ -1349,9 +1352,9 @@ impl<'hir> LoweringContext<'_, 'hir> { match self .resolver .get_partial_res(bound_pred.bounded_ty.id) - .map(|d| (d.base_res(), d.unresolved_segments())) + .and_then(|r| r.full_res()) { - Some((Res::Def(DefKind::TyParam, def_id), 0)) + Some(Res::Def(DefKind::TyParam, def_id)) if bound_pred.bound_generic_params.is_empty() => { generics diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8281164ab120..ce5893efa926 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -175,12 +175,7 @@ impl ResolverAstLoweringExt for ResolverAstLowering { return None; } - let partial_res = self.partial_res_map.get(&expr.id)?; - if partial_res.unresolved_segments() != 0 { - return None; - } - - if let Res::Def(DefKind::Fn, def_id) = partial_res.base_res() { + if let Res::Def(DefKind::Fn, def_id) = self.partial_res_map.get(&expr.id)?.full_res()? { // We only support cross-crate argument rewriting. Uses // within the same crate should be updated to use the new // const generics style. @@ -753,12 +748,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn expect_full_res(&mut self, id: NodeId) -> Res { - self.resolver.get_partial_res(id).map_or(Res::Err, |pr| { - if pr.unresolved_segments() != 0 { - panic!("path not fully resolved: {:?}", pr); - } - pr.base_res() - }) + self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res()) } fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator> { @@ -1138,8 +1128,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // type and value namespaces. If we resolved the path in the value namespace, we // transform it into a generic const argument. TyKind::Path(ref qself, ref path) => { - if let Some(partial_res) = self.resolver.get_partial_res(ty.id) { - let res = partial_res.base_res(); + if let Some(res) = self + .resolver + .get_partial_res(ty.id) + .and_then(|partial_res| partial_res.full_res()) + { if !res.matches_ns(Namespace::TypeNS) { debug!( "lower_generic_arg: Lowering type argument as const argument: {:?}", @@ -1206,8 +1199,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // by `ty_path`. if qself.is_none() && let Some(partial_res) = self.resolver.get_partial_res(t.id) - && partial_res.unresolved_segments() == 0 - && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res() + && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res() { let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| { let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 1ea76fdbfcbb..1af1633b5244 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -239,7 +239,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ident: Ident, lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>, ) -> hir::PatKind<'hir> { - match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) { + match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) { // `None` can occur in body-less function signatures res @ (None | Some(Res::Local(_))) => { let canonical_id = match res { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 6bb1bb9eace8..888776cccac2 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -29,11 +29,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let partial_res = self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); + let base_res = partial_res.base_res(); + let unresolved_segments = partial_res.unresolved_segments(); let path_span_lo = p.span.shrink_to_lo(); - let proj_start = p.segments.len() - partial_res.unresolved_segments(); + let proj_start = p.segments.len() - unresolved_segments; let path = self.arena.alloc(hir::Path { - res: self.lower_res(partial_res.base_res()), + res: self.lower_res(base_res), segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map( |(i, segment)| { let param_mode = match (qself_position, param_mode) { @@ -46,7 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => param_mode, }; - let parenthesized_generic_args = match partial_res.base_res() { + let parenthesized_generic_args = match base_res { // `a::b::Trait(Args)` Res::Def(DefKind::Trait, _) if i + 1 == proj_start => { ParenthesizedGenericArgs::Ok @@ -83,7 +85,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Simple case, either no projections, or only fully-qualified. // E.g., `std::mem::size_of` or `::Item`. - if partial_res.unresolved_segments() == 0 { + if unresolved_segments == 0 { return hir::QPath::Resolved(qself, path); } diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index f1f0c224bbdd..4ef4aad902c6 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -464,6 +464,16 @@ impl PartialRes { pub fn unresolved_segments(&self) -> usize { self.unresolved_segments } + + #[inline] + pub fn full_res(&self) -> Option> { + (self.unresolved_segments == 0).then_some(self.base_res) + } + + #[inline] + pub fn expect_full_res(&self) -> Res { + self.full_res().expect("unexpected unresolved segments") + } } /// Different kinds of symbols can coexist even if they share the same textual name. diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index c3d87b5b6af3..a17793ecd99b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -326,7 +326,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } PathResult::Module(..) => Err(VisResolutionError::ModuleOnly(path.span)), PathResult::NonModule(partial_res) => { - expected_found_error(partial_res.base_res()) + expected_found_error(partial_res.expect_full_res()) } PathResult::Failed { span, label, suggestion, .. } => { Err(VisResolutionError::FailedToResolve(span, label, suggestion)) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 989a827ef7d9..4ccc9db1bb64 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -642,8 +642,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // Check whether we should interpret this as a bare trait object. if qself.is_none() && let Some(partial_res) = self.r.partial_res_map.get(&ty.id) - && partial_res.unresolved_segments() == 0 - && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res() + && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res() { // This path is actually a bare trait object. In case of a bare `Fn`-trait // object with anonymous lifetimes, we need this rib to correctly place the @@ -1930,7 +1929,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { match ty.kind { TyKind::ImplicitSelf => true, TyKind::Path(None, _) => { - let path_res = self.r.partial_res_map[&ty.id].base_res(); + let path_res = self.r.partial_res_map[&ty.id].expect_full_res(); if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path_res { return true; } @@ -1971,7 +1970,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { None } }) - .map(|res| res.base_res()) + .map(|res| res.expect_full_res()) .filter(|res| { // Permit the types that unambiguously always // result in the same type constructor being used @@ -2531,7 +2530,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Finalize::new(trait_ref.ref_id, trait_ref.path.span), ); self.diagnostic_metadata.currently_processing_impl_trait = None; - if let Some(def_id) = res.base_res().opt_def_id() { + if let Some(def_id) = res.expect_full_res().opt_def_id() { new_id = Some(def_id); new_val = Some((self.r.expect_module(def_id), trait_ref.clone())); } @@ -2860,7 +2859,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } fn is_base_res_local(&self, nid: NodeId) -> bool { - matches!(self.r.partial_res_map.get(&nid).map(|res| res.base_res()), Some(Res::Local(..))) + matches!( + self.r.partial_res_map.get(&nid).map(|res| res.expect_full_res()), + Some(Res::Local(..)) + ) } /// Checks that all of the arms in an or-pattern have exactly the @@ -3347,12 +3349,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { source.defer_to_typeck(), finalize, ) { - Ok(Some(partial_res)) if partial_res.unresolved_segments() == 0 => { - if source.is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err - { + Ok(Some(partial_res)) if let Some(res) = partial_res.full_res() => { + if source.is_expected(res) || res == Res::Err { partial_res } else { - report_errors(self, Some(partial_res.base_res())) + report_errors(self, Some(res)) } } @@ -3560,20 +3561,21 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }; if path.len() > 1 - && result.base_res() != Res::Err + && let Some(res) = result.full_res() + && res != Res::Err && path[0].ident.name != kw::PathRoot && path[0].ident.name != kw::DollarCrate { let unqualified_result = { match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) { - PathResult::NonModule(path_res) => path_res.base_res(), + PathResult::NonModule(path_res) => path_res.expect_full_res(), PathResult::Module(ModuleOrUniformRoot::Module(module)) => { module.res().unwrap() } _ => return Ok(Some(result)), } }; - if result.base_res() == unqualified_result { + if res == unqualified_result { let lint = lint::builtin::UNUSED_QUALIFICATIONS; self.r.lint_buffer.buffer_lint( lint, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c05f89a65755..13cd7987e923 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -968,11 +968,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false; }; - if !(matches!( - partial_res.base_res(), - hir::def::Res::Def(hir::def::DefKind::AssocTy, _) - ) && partial_res.unresolved_segments() == 0) - { + if !matches!( + partial_res.full_res(), + Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _)) + ) { return false; } (ty, position, path) @@ -986,11 +985,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else { return false; }; - if !(matches!( - partial_res.base_res(), - hir::def::Res::Def(hir::def::DefKind::TyParam, _) - ) && partial_res.unresolved_segments() == 0) - { + if !matches!( + partial_res.full_res(), + Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _)) + ) { return false; } if let ( @@ -1518,20 +1516,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { { // Look for a field with the same name in the current self_type. if let Some(resolution) = self.r.partial_res_map.get(&node_id) { - match resolution.base_res() { - Res::Def(DefKind::Struct | DefKind::Union, did) - if resolution.unresolved_segments() == 0 => - { - if let Some(field_names) = self.r.field_names.get(&did) { - if field_names - .iter() - .any(|&field_name| ident.name == field_name.node) - { - return Some(AssocSuggestion::Field); - } + if let Some(Res::Def(DefKind::Struct | DefKind::Union, did)) = + resolution.full_res() + { + if let Some(field_names) = self.r.field_names.get(&did) { + if field_names.iter().any(|&field_name| ident.name == field_name.node) { + return Some(AssocSuggestion::Field); } } - _ => {} } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9173c3692ce6..bf9417261234 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1882,12 +1882,10 @@ impl<'a> Resolver<'a> { match self.maybe_resolve_path(&segments, Some(ns), &parent_scope) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()), - PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { - Some(path_res.base_res()) + PathResult::NonModule(path_res) => path_res.full_res(), + PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => { + None } - PathResult::Module(ModuleOrUniformRoot::ExternPrelude) - | PathResult::NonModule(..) - | PathResult::Failed { .. } => None, PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), } } @@ -1938,12 +1936,8 @@ impl<'a> Resolver<'a> { return None; } - let partial_res = self.partial_res_map.get(&expr.id)?; - if partial_res.unresolved_segments() != 0 { - return None; - } - - if let Res::Def(def::DefKind::Fn, def_id) = partial_res.base_res() { + let res = self.partial_res_map.get(&expr.id)?.full_res()?; + if let Res::Def(def::DefKind::Fn, def_id) = res { // We only support cross-crate argument rewriting. Uses // within the same crate should be updated to use the new // const generics style. diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index dafa10e9e002..f6f0b3c11391 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -590,9 +590,7 @@ impl<'a> Resolver<'a> { let res = if path.len() > 1 { let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) { - PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { - Ok(path_res.base_res()) - } + PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res), PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), PathResult::NonModule(..) | PathResult::Indeterminate @@ -692,9 +690,8 @@ impl<'a> Resolver<'a> { Some(Finalize::new(ast::CRATE_NODE_ID, path_span)), None, ) { - PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { - let res = path_res.base_res(); - check_consistency(self, &path, path_span, kind, initial_res, res); + PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => { + check_consistency(self, &path, path_span, kind, initial_res, res) } path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => { let (span, label) = if let PathResult::Failed { span, label, .. } = path_res { From 152cd6322655bb5173655cdf0781ca64c2a7602f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 10 Aug 2022 21:31:26 +0200 Subject: [PATCH 165/175] Report duplicate definitions in trait impls during resolution. --- .../rustc_hir_analysis/src/impl_wf_check.rs | 3 ++ compiler/rustc_resolve/src/diagnostics.rs | 13 ++++++ compiler/rustc_resolve/src/late.rs | 33 +++++++++++++-- compiler/rustc_resolve/src/lib.rs | 2 + .../associated-item-duplicate-names-3.rs | 1 + .../associated-item-duplicate-names-3.stderr | 18 +++++++-- .../associated-item-duplicate-names.stderr | 14 +++++-- src/test/ui/error-codes/E0201.stderr | 40 +++++++++++-------- src/test/ui/hygiene/impl_items-2.rs | 26 ++++++++++++ src/test/ui/hygiene/impl_items-2.stderr | 15 +++++++ src/test/ui/traits/issue-8153.stderr | 7 +++- 11 files changed, 142 insertions(+), 30 deletions(-) create mode 100644 src/test/ui/hygiene/impl_items-2.rs create mode 100644 src/test/ui/hygiene/impl_items-2.stderr diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index c499364056ff..69155a422b06 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -197,6 +197,9 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol /// Enforce that we do not have two items in an impl with the same name. fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { + if tcx.impl_trait_ref(impl_def_id).is_some() { + return; + } let mut seen_type_items = FxHashMap::default(); let mut seen_value_items = FxHashMap::default(); for &impl_item_ref in tcx.associated_item_def_ids(impl_def_id) { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 98982240af27..75c016af2f92 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1047,6 +1047,19 @@ impl<'a> Resolver<'a> { err.span_label(trait_item_span, "item in trait"); err } + ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => { + let mut err = struct_span_err!( + self.session, + span, + E0201, + "duplicate definitions with name `{}`:", + name, + ); + err.span_label(old_span, "previous definition here"); + err.span_label(trait_item_span, "item in trait"); + err.span_label(span, "duplicate definition"); + err + } ResolutionError::InvalidAsmSym => { let mut err = self.session.struct_span_err(span, "invalid `sym` operand"); err.span_label(span, "is a local variable"); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 431507e8e0f6..9fc8401fa07f 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2619,8 +2619,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.with_current_self_type(self_type, |this| { this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); + let mut seen_trait_items = Default::default(); for item in impl_items { - this.resolve_impl_item(&**item); + this.resolve_impl_item(&**item, &mut seen_trait_items); } }); }); @@ -2634,7 +2635,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); } - fn resolve_impl_item(&mut self, item: &'ast AssocItem) { + fn resolve_impl_item( + &mut self, + item: &'ast AssocItem, + seen_trait_items: &mut FxHashMap, + ) { use crate::ResolutionError::*; match &item.kind { AssocItemKind::Const(_, ty, default) => { @@ -2647,6 +2652,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &item.kind, ValueNS, item.span, + seen_trait_items, |i, s, c| ConstNotMemberOfTrait(i, s, c), ); @@ -2687,6 +2693,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &item.kind, ValueNS, item.span, + seen_trait_items, |i, s, c| MethodNotMemberOfTrait(i, s, c), ); @@ -2715,6 +2722,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &item.kind, TypeNS, item.span, + seen_trait_items, |i, s, c| TypeNotMemberOfTrait(i, s, c), ); @@ -2736,6 +2744,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { kind: &AssocItemKind, ns: Namespace, span: Span, + seen_trait_items: &mut FxHashMap, err: F, ) where F: FnOnce(Ident, String, Option) -> ResolutionError<'a>, @@ -2768,7 +2777,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }; let res = binding.res(); - let Res::Def(def_kind, _) = res else { bug!() }; + let Res::Def(def_kind, id_in_trait) = res else { bug!() }; + + match seen_trait_items.entry(id_in_trait) { + Entry::Occupied(entry) => { + self.report_error( + span, + ResolutionError::TraitImplDuplicate { + name: ident.name, + old_span: *entry.get(), + trait_item_span: binding.span, + }, + ); + return; + } + Entry::Vacant(entry) => { + entry.insert(span); + } + }; + match (def_kind, kind) { (DefKind::AssocTy, AssocItemKind::TyAlias(..)) | (DefKind::AssocFn, AssocItemKind::Fn(..)) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9173c3692ce6..4c9e14db3c43 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -236,6 +236,8 @@ enum ResolutionError<'a> { trait_item_span: Span, code: rustc_errors::DiagnosticId, }, + /// Error E0201: multiple impl items for the same trait item. + TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span }, /// Inline asm `sym` operand must refer to a `fn` or `static`. InvalidAsmSym, } diff --git a/src/test/ui/associated-item/associated-item-duplicate-names-3.rs b/src/test/ui/associated-item/associated-item-duplicate-names-3.rs index 6aa1b483eebd..3a70a2f943ff 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names-3.rs +++ b/src/test/ui/associated-item/associated-item-duplicate-names-3.rs @@ -16,4 +16,5 @@ impl Foo for Baz { fn main() { let x: Baz::Bar = 5; + //~^ ERROR ambiguous associated type } diff --git a/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr b/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr index 03782f663480..bf4bd634cf1d 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr @@ -1,11 +1,21 @@ error[E0201]: duplicate definitions with name `Bar`: --> $DIR/associated-item-duplicate-names-3.rs:14:5 | +LL | type Bar; + | --------- item in trait +... LL | type Bar = i16; - | -------- previous definition of `Bar` here + | --------------- previous definition here LL | type Bar = u16; - | ^^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^^ duplicate definition -error: aborting due to previous error +error[E0223]: ambiguous associated type + --> $DIR/associated-item-duplicate-names-3.rs:18:12 + | +LL | let x: Baz::Bar = 5; + | ^^^^^^^^ help: use fully-qualified syntax: `::Bar` -For more information about this error, try `rustc --explain E0201`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0201, E0223. +For more information about an error, try `rustc --explain E0201`. diff --git a/src/test/ui/associated-item/associated-item-duplicate-names.stderr b/src/test/ui/associated-item/associated-item-duplicate-names.stderr index c9119c102711..f89ea6e57cc4 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-names.stderr @@ -1,18 +1,24 @@ error[E0201]: duplicate definitions with name `Ty`: --> $DIR/associated-item-duplicate-names.rs:11:5 | +LL | type Ty; + | -------- item in trait +... LL | type Ty = (); - | ------- previous definition of `Ty` here + | ------------- previous definition here LL | type Ty = usize; - | ^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^^^ duplicate definition error[E0201]: duplicate definitions with name `BAR`: --> $DIR/associated-item-duplicate-names.rs:13:5 | +LL | const BAR: u32; + | --------------- item in trait +... LL | const BAR: u32 = 7; - | -------------- previous definition of `BAR` here + | ------------------- previous definition here LL | const BAR: u32 = 8; - | ^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^^^^^^ duplicate definition error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0201.stderr b/src/test/ui/error-codes/E0201.stderr index 94e06894144c..f72145a82447 100644 --- a/src/test/ui/error-codes/E0201.stderr +++ b/src/test/ui/error-codes/E0201.stderr @@ -1,3 +1,26 @@ +error[E0201]: duplicate definitions with name `baz`: + --> $DIR/E0201.rs:17:5 + | +LL | fn baz(&self) -> bool; + | ---------------------- item in trait +... +LL | fn baz(&self) -> bool { true } + | ------------------------------ previous definition here +LL | fn baz(&self) -> bool { self.0 > 5 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition + +error[E0201]: duplicate definitions with name `Quux`: + --> $DIR/E0201.rs:18:5 + | +LL | type Quux; + | ---------- item in trait +... +LL | type Quux = u32; + | ---------------- previous definition here +... +LL | type Quux = u32; + | ^^^^^^^^^^^^^^^^ duplicate definition + error[E0201]: duplicate definitions with name `bar`: --> $DIR/E0201.rs:5:5 | @@ -6,23 +29,6 @@ LL | fn bar(&self) -> bool { self.0 > 5 } LL | fn bar() {} | ^^^^^^^^ duplicate definition -error[E0201]: duplicate definitions with name `baz`: - --> $DIR/E0201.rs:17:5 - | -LL | fn baz(&self) -> bool { true } - | --------------------- previous definition of `baz` here -LL | fn baz(&self) -> bool { self.0 > 5 } - | ^^^^^^^^^^^^^^^^^^^^^ duplicate definition - -error[E0201]: duplicate definitions with name `Quux`: - --> $DIR/E0201.rs:18:5 - | -LL | type Quux = u32; - | --------- previous definition of `Quux` here -... -LL | type Quux = u32; - | ^^^^^^^^^ duplicate definition - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0201`. diff --git a/src/test/ui/hygiene/impl_items-2.rs b/src/test/ui/hygiene/impl_items-2.rs new file mode 100644 index 000000000000..465e444aedb6 --- /dev/null +++ b/src/test/ui/hygiene/impl_items-2.rs @@ -0,0 +1,26 @@ +#![feature(decl_macro)] + +trait Trait { + fn foo() {} +} + +macro trait_impl() { + fn foo() {} +} + +// Check that we error on multiple impl items that resolve to the same trait item. +impl Trait for i32 { + trait_impl!(); + fn foo() {} + //~^ ERROR duplicate definitions with name `foo`: [E0201] +} + +struct Type; + +// Check that we do not error with inherent impls. +impl Type { + trait_impl!(); + fn foo() {} +} + +fn main() {} diff --git a/src/test/ui/hygiene/impl_items-2.stderr b/src/test/ui/hygiene/impl_items-2.stderr new file mode 100644 index 000000000000..3c0ffeb10575 --- /dev/null +++ b/src/test/ui/hygiene/impl_items-2.stderr @@ -0,0 +1,15 @@ +error[E0201]: duplicate definitions with name `foo`: + --> $DIR/impl_items-2.rs:14:5 + | +LL | fn foo() {} + | ----------- item in trait +... +LL | fn foo() {} + | ----------- previous definition here +... +LL | fn foo() {} + | ^^^^^^^^^^^ duplicate definition + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0201`. diff --git a/src/test/ui/traits/issue-8153.stderr b/src/test/ui/traits/issue-8153.stderr index b76bbc0235fd..ae214bb9e9b4 100644 --- a/src/test/ui/traits/issue-8153.stderr +++ b/src/test/ui/traits/issue-8153.stderr @@ -1,10 +1,13 @@ error[E0201]: duplicate definitions with name `bar`: --> $DIR/issue-8153.rs:11:5 | +LL | fn bar(&self) -> isize; + | ----------------------- item in trait +... LL | fn bar(&self) -> isize {1} - | ---------------------- previous definition of `bar` here + | -------------------------- previous definition here LL | fn bar(&self) -> isize {2} - | ^^^^^^^^^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition error: aborting due to previous error From b5963f07e611cf2a09a310eb74c1a93adfaeb9de Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 11 Oct 2022 08:50:41 -0700 Subject: [PATCH 166/175] rustdoc: remove unused classes from sidebar Since 98f05a0282625a5fda6e90ebf3b05a4bd7608f65 removed separate colors from the currently-selected item, there's no need to have item classes on sidebar links. --- src/librustdoc/html/static/js/main.js | 8 +- src/test/rustdoc-gui/sidebar-links-color.goml | 126 +++++++++--------- .../rustdoc-gui/sidebar-macro-reexport.goml | 2 +- 3 files changed, 67 insertions(+), 69 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 0180c0ead8d3..dc5b8acdf53a 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -451,7 +451,6 @@ function loadCss(cssFileName) { const name = item[0]; const desc = item[1]; // can be null - let klass = shortty; let path; if (shortty === "mod") { path = name + "/index.html"; @@ -459,13 +458,12 @@ function loadCss(cssFileName) { path = shortty + "." + name + ".html"; } const current_page = document.location.href.split("/").pop(); - if (path === current_page) { - klass += " current"; - } const link = document.createElement("a"); link.href = path; link.title = desc; - link.className = klass; + if (path === current_page) { + link.className = "current"; + } link.textContent = name; const li = document.createElement("li"); li.appendChild(link); diff --git a/src/test/rustdoc-gui/sidebar-links-color.goml b/src/test/rustdoc-gui/sidebar-links-color.goml index 3f719c4c4dc3..18a1a3fadea5 100644 --- a/src/test/rustdoc-gui/sidebar-links-color.goml +++ b/src/test/rustdoc-gui/sidebar-links-color.goml @@ -13,72 +13,72 @@ reload: // Struct assert-css: ( - ".sidebar a.struct:not(.current)", + ".sidebar .block.struct a:not(.current)", {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.struct:not(.current)" +move-cursor-to: ".sidebar .block.struct a:not(.current)" assert-css: ( - ".sidebar a.struct:hover", + ".sidebar .block.struct a:hover", {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"}, ) // Enum assert-css: ( - ".sidebar a.enum", + ".sidebar .block.enum a", {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.enum" +move-cursor-to: ".sidebar .block.enum a" assert-css: ( - ".sidebar a.enum:hover", + ".sidebar .block.enum a:hover", {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"}, ) // Union assert-css: ( - ".sidebar a.union", + ".sidebar .block.union a", {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.union" +move-cursor-to: ".sidebar .block.union a" assert-css: ( - ".sidebar a.union:hover", + ".sidebar .block.union a:hover", {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"}, ) // Trait assert-css: ( - ".sidebar a.trait", + ".sidebar .block.trait a", {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.trait" +move-cursor-to: ".sidebar .block.trait a" assert-css: ( - ".sidebar a.trait:hover", + ".sidebar .block.trait a:hover", {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"}, ) // Function assert-css: ( - ".sidebar a.fn", + ".sidebar .block.fn a", {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.fn" +move-cursor-to: ".sidebar .block.fn a" assert-css: ( - ".sidebar a.fn:hover", + ".sidebar .block.fn a:hover", {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"}, ) // Type definition assert-css: ( - ".sidebar a.type", + ".sidebar .block.type a", {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.type" +move-cursor-to: ".sidebar .block.type a" assert-css: ( - ".sidebar a.type:hover", + ".sidebar .block.type a:hover", {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"}, ) // Keyword assert-css: ( - ".sidebar a.keyword", + ".sidebar .block.keyword a", {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.keyword" +move-cursor-to: ".sidebar .block.keyword a" assert-css: ( - ".sidebar a.keyword:hover", + ".sidebar .block.keyword a:hover", {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"}, ) @@ -88,72 +88,72 @@ reload: // Struct assert-css: ( - ".sidebar a.struct:not(.current)", + ".sidebar .block.struct a:not(.current)", {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.struct:not(.current)" +move-cursor-to: ".sidebar .block.struct a:not(.current)" assert-css: ( - ".sidebar a.struct:hover", + ".sidebar .block.struct a:hover", {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"}, ) // Enum assert-css: ( - ".sidebar a.enum", + ".sidebar .block.enum a", {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.enum" +move-cursor-to: ".sidebar .block.enum a" assert-css: ( - ".sidebar a.enum:hover", + ".sidebar .block.enum a:hover", {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"}, ) // Union assert-css: ( - ".sidebar a.union", + ".sidebar .block.union a", {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.union" +move-cursor-to: ".sidebar .block.union a" assert-css: ( - ".sidebar a.union:hover", + ".sidebar .block.union a:hover", {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"}, ) // Trait assert-css: ( - ".sidebar a.trait", + ".sidebar .block.trait a", {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.trait" +move-cursor-to: ".sidebar .block.trait a" assert-css: ( - ".sidebar a.trait:hover", + ".sidebar .block.trait a:hover", {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"}, ) // Function assert-css: ( - ".sidebar a.fn", + ".sidebar .block.fn a", {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.fn" +move-cursor-to: ".sidebar .block.fn a" assert-css: ( - ".sidebar a.fn:hover", + ".sidebar .block.fn a:hover", {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"}, ) // Type definition assert-css: ( - ".sidebar a.type", + ".sidebar .block.type a", {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.type" +move-cursor-to: ".sidebar .block.type a" assert-css: ( - ".sidebar a.type:hover", + ".sidebar .block.type a:hover", {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"}, ) // Keyword assert-css: ( - ".sidebar a.keyword", + ".sidebar .block.keyword a", {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.keyword" +move-cursor-to: ".sidebar .block.keyword a" assert-css: ( - ".sidebar a.keyword:hover", + ".sidebar .block.keyword a:hover", {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"}, ) @@ -163,71 +163,71 @@ reload: // Struct assert-css: ( - ".sidebar a.struct:not(.current)", + ".sidebar .block.struct a:not(.current)", {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.struct:not(.current)" +move-cursor-to: ".sidebar .block.struct a:not(.current)" assert-css: ( - ".sidebar a.struct:hover", + ".sidebar .block.struct a:hover", {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"}, ) // Enum assert-css: ( - ".sidebar a.enum", + ".sidebar .block.enum a", {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.enum" +move-cursor-to: ".sidebar .block.enum a" assert-css: ( - ".sidebar a.enum:hover", + ".sidebar .block.enum a:hover", {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"}, ) // Union assert-css: ( - ".sidebar a.union", + ".sidebar .block.union a", {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.union" +move-cursor-to: ".sidebar .block.union a" assert-css: ( - ".sidebar a.union:hover", + ".sidebar .block.union a:hover", {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"}, ) // Trait assert-css: ( - ".sidebar a.trait", + ".sidebar .block.trait a", {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.trait" +move-cursor-to: ".sidebar .block.trait a" assert-css: ( - ".sidebar a.trait:hover", + ".sidebar .block.trait a:hover", {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"}, ) // Function assert-css: ( - ".sidebar a.fn", + ".sidebar .block.fn a", {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.fn" +move-cursor-to: ".sidebar .block.fn a" assert-css: ( - ".sidebar a.fn:hover", + ".sidebar .block.fn a:hover", {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"}, ) // Type definition assert-css: ( - ".sidebar a.type", + ".sidebar .block.type a", {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.type" +move-cursor-to: ".sidebar .block.type a" assert-css: ( - ".sidebar a.type:hover", + ".sidebar .block.type a:hover", {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"}, ) // Keyword assert-css: ( - ".sidebar a.keyword", + ".sidebar .block.keyword a", {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"}, ) -move-cursor-to: ".sidebar a.keyword" +move-cursor-to: ".sidebar .block.keyword a" assert-css: ( - ".sidebar a.keyword:hover", + ".sidebar .block.keyword a:hover", {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"}, ) diff --git a/src/test/rustdoc-gui/sidebar-macro-reexport.goml b/src/test/rustdoc-gui/sidebar-macro-reexport.goml index 01282f2ffeb7..b5c1b6a4390b 100644 --- a/src/test/rustdoc-gui/sidebar-macro-reexport.goml +++ b/src/test/rustdoc-gui/sidebar-macro-reexport.goml @@ -1,5 +1,5 @@ // This test ensures that the reexport of a macro doesn't make the original macro // displayed twice in the sidebar. goto: "file://" + |DOC_PATH| + "/test_docs/macro.repro.html" -wait-for: ".sidebar-elems .macro .macro" +wait-for: ".sidebar-elems .block.macro a" assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[text()='repro']", 1) From 062284af6e2a5066e86562a9743c16dd7338d790 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 11 Oct 2022 09:22:40 -0700 Subject: [PATCH 167/175] rustdoc: remove unneeded `.content` selector from link colors Since 98f05a0282625a5fda6e90ebf3b05a4bd7608f65 and b5963f07e611cf2a09a310eb74c1a93adfaeb9de removed color classes from sidebar items, there's no need for the selectors to be so specific any more. This commit does have to change `h1.fqn a` to just be `h1 a`, so that the header link color selector is less specific than the typed link at the end. Since #89506 made docblocks start at `h2`, the main page link header should be the only h1 in the page now. --- src/librustdoc/html/static/css/rustdoc.css | 54 +++++++++---------- src/librustdoc/html/static/css/themes/ayu.css | 2 +- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 661aed71298d..f5b0d15d733a 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -218,55 +218,55 @@ pre.rust a, .sidebar h2 a, .sidebar h3 a, .mobile-topbar h2 a, -h1.fqn a, +h1 a, .search-results a, .module-item .stab, .import-item .stab, .result-name .primitive > i, .result-name .keyword > i, -.content .method .where, -.content .fn .where, -.content .where.fmt-newline { +.method .where, +.fn .where, +.where.fmt-newline { color: var(--main-color); } -.content span.enum, .content a.enum, -.content span.struct, .content a.struct, -.content span.union, .content a.union, -.content span.primitive, .content a.primitive, -.content span.type, .content a.type, -.content span.foreigntype, .content a.foreigntype { +span.enum, a.enum, +span.struct, a.struct, +span.union, a.union, +span.primitive, a.primitive, +span.type, a.type, +span.foreigntype, a.foreigntype { color: var(--type-link-color); } -.content span.trait, .content a.trait, -.content span.traitalias, .content a.traitalias { +span.trait, a.trait, +span.traitalias, a.traitalias { color: var(--trait-link-color); } -.content span.associatedtype, .content a.associatedtype, -.content span.constant, .content a.constant, -.content span.static, .content a.static { +span.associatedtype, a.associatedtype, +span.constant, a.constant, +span.static, a.static { color: var(--assoc-item-link-color); } -.content span.fn, .content a.fn, -.content .fnname, -.content span.method, .content a.method, -.content span.tymethod, .content a.tymethod { +span.fn, a.fn, +.fnname, +span.method, a.method, +span.tymethod, a.tymethod { color: var(--function-link-color); } -.content span.attr, .content a.attr, -.content span.derive, .content a.derive, -.content span.macro, .content a.macro { +span.attr, a.attr, +span.derive, a.derive, +span.macro, a.macro { color: var(--macro-link-color); } -.content span.mod, .content a.mod, .block a.current.mod { +span.mod, a.mod { color: var(--mod-link-color); } -.content span.keyword, .content a.keyword { +span.keyword, a.keyword { color: var(--keyword-link-color); } @@ -685,9 +685,9 @@ pre, .rustdoc.source .example-wrap { } /* Shift "where ..." part of method or fn definition down a line */ -.content .method .where, -.content .fn .where, -.content .where.fmt-newline { +.method .where, +.fn .where, +.where.fmt-newline { display: block; font-size: 0.875rem; } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 0975d497cb23..fc7713b98857 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -56,7 +56,7 @@ input:focus + .slider { h1, h2, h3, h4 { color: white; } -h1.fqn a { +h1 a { color: #fff; } h4 { From 2b50cd18772d3db523070d418dc0411b885a3ff4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Oct 2022 12:33:29 +0200 Subject: [PATCH 168/175] rename rustc_allocator_nounwind to rustc_nounwind --- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- library/alloc/src/alloc.rs | 12 ++++++++---- .../function_calls/exported_symbol_bad_unwind2.rs | 4 ++-- .../rust-analyzer/crates/hir-def/src/builtin_attr.rs | 2 +- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5ee6c9f23877..92d0fb1aec83 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -536,7 +536,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), - rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), + rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), rustc_attr!(rustc_reallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 98bcdcf65201..cf7fde2a0901 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1649,7 +1649,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { ) .emit(); } - } else if attr.has_name(sym::rustc_allocator_nounwind) { + } else if attr.has_name(sym::rustc_nounwind) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; } else if attr.has_name(sym::rustc_reallocator) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fe4fd33bdbac..c6711b603b68 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1231,7 +1231,6 @@ symbols! { rust_oom, rustc, rustc_allocator, - rustc_allocator_nounwind, rustc_allocator_zeroed, rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, @@ -1278,6 +1277,7 @@ symbols! { rustc_mir, rustc_must_implement_one_of, rustc_nonnull_optimization_guaranteed, + rustc_nounwind, rustc_object_lifetime_default, rustc_on_unimplemented, rustc_outlives, diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 80b067812ba7..8187517ccfbb 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -28,16 +28,20 @@ extern "Rust" { // The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them // like `malloc`, `realloc`, and `free`, respectively. #[rustc_allocator] - #[rustc_allocator_nounwind] + #[cfg_attr(not(bootstrap), rustc_nounwind)] + #[cfg_attr(bootstrap, rustc_allocator_nounwind)] fn __rust_alloc(size: usize, align: usize) -> *mut u8; #[rustc_deallocator] - #[rustc_allocator_nounwind] + #[cfg_attr(not(bootstrap), rustc_nounwind)] + #[cfg_attr(bootstrap, rustc_allocator_nounwind)] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_reallocator] - #[rustc_allocator_nounwind] + #[cfg_attr(not(bootstrap), rustc_nounwind)] + #[cfg_attr(bootstrap, rustc_allocator_nounwind)] fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8; #[rustc_allocator_zeroed] - #[rustc_allocator_nounwind] + #[cfg_attr(not(bootstrap), rustc_nounwind)] + #[cfg_attr(bootstrap, rustc_allocator_nounwind)] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; } diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs index d9aacdb8aea4..f85ad5ae5072 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs @@ -1,7 +1,7 @@ //@revisions: extern_block definition both #![feature(rustc_attrs, c_unwind)] -#[cfg_attr(any(definition, both), rustc_allocator_nounwind)] +#[cfg_attr(any(definition, both), rustc_nounwind)] #[no_mangle] extern "C-unwind" fn nounwind() { //[definition]~^ ERROR: abnormal termination: the program aborted execution @@ -11,7 +11,7 @@ extern "C-unwind" fn nounwind() { fn main() { extern "C-unwind" { - #[cfg_attr(any(extern_block, both), rustc_allocator_nounwind)] + #[cfg_attr(any(extern_block, both), rustc_nounwind)] fn nounwind(); } unsafe { nounwind() } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs index 0e7ce5f85f96..39581b33a8da 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs @@ -379,7 +379,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), - rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), + rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), gated!( alloc_error_handler, Normal, template!(Word), WarnFollowing, experimental!(alloc_error_handler) From 66282cb47d0f4c651fc58a6f458f1e93a2dc33b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Oct 2022 12:40:43 +0200 Subject: [PATCH 169/175] add panic_fmt_nounwind for panicing without unwinding, and use it for panic_no_unwind --- compiler/rustc_hir_analysis/src/collect.rs | 7 ------- library/core/src/panicking.rs | 22 +++++++++++++++++++--- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index cf7fde2a0901..5c76016c6625 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1582,13 +1582,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } - // The panic_no_unwind function called by TerminatorKind::Abort will never - // unwind. If the panic handler that it invokes unwind then it will simply - // call the panic handler again. - if Some(did.to_def_id()) == tcx.lang_items().panic_no_unwind() { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; - } - let supported_target_features = tcx.supported_target_features(LOCAL_CRATE); let mut inline_span = None; diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index d4afe0f5326a..68c8e8555d39 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -84,12 +84,27 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { panic!("index out of bounds: the len is {len} but the index is {index}") } -// This function is called directly by the codegen backend, and must not have -// any extra arguments (including those synthesized by track_caller). +/// Panic because we cannot unwind out of a function. +/// +/// This function is called directly by the codegen backend, and must not have +/// any extra arguments (including those synthesized by track_caller). #[cold] #[inline(never)] #[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function +#[cfg_attr(not(bootstrap), rustc_nounwind)] +#[cfg_attr(bootstrap, rustc_allocator_nounwind)] fn panic_no_unwind() -> ! { + panic_str_nounwind("panic in a function that cannot unwind") +} + +/// Like panic_fmt, but without unwinding and track_caller to reduce the impact on codesize. +/// Also just works on `str`, as a `fmt::Arguments` needs more space to be passed. +#[cold] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(bootstrap), rustc_nounwind)] +#[cfg_attr(bootstrap, rustc_allocator_nounwind)] +pub fn panic_str_nounwind(msg: &'static str) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() } @@ -102,7 +117,8 @@ fn panic_no_unwind() -> ! { } // PanicInfo with the `can_unwind` flag set to false forces an abort. - let fmt = format_args!("panic in a function that cannot unwind"); + let pieces = [msg]; + let fmt = fmt::Arguments::new_v1(&pieces, &[]); let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false); // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. From b61e742a394a79cd7fc58bb6b8bf9e502fd2a4cf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Oct 2022 12:40:56 +0200 Subject: [PATCH 170/175] use panic_fmt_nounwind for assert_unsafe_precondition --- library/core/src/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 15ee14398b67..2399262c05b4 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2210,8 +2210,8 @@ macro_rules! assert_unsafe_precondition { #[inline(always)] fn runtime$(<$($tt)*>)?($($i:$ty),*) { if !$e { - // abort instead of panicking to reduce impact on code size - ::core::intrinsics::abort(); + // don't unwind to reduce impact on code size + ::core::panicking::panic_str_nounwind("unsafe precondition violated"); } } #[allow(non_snake_case)] From 38c78a9ac17caefd4c5e6d0b332814b2ac2cf3a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Oct 2022 10:48:53 +0200 Subject: [PATCH 171/175] reorder panicking.rs to put main entry points at the top --- library/core/src/panicking.rs | 128 ++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 61 deletions(-) diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 68c8e8555d39..a9de7c94e5a1 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -29,6 +29,73 @@ use crate::fmt; use crate::panic::{Location, PanicInfo}; +// First we define the two main entry points that all panics go through. +// In the end both are just convenience wrappers around `panic_impl`. + +/// The entry point for panicking with a formatted message. +/// +/// This is designed to reduce the amount of code required at the call +/// site as much as possible (so that `panic!()` has as low an impact +/// on (e.g.) the inlining of other functions as possible), by moving +/// the actual formatting into this shared place. +#[cold] +// If panic_immediate_abort, inline the abort call, +// otherwise avoid inlining because of it is cold path. +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[track_caller] +#[lang = "panic_fmt"] // needed for const-evaluated panics +#[rustc_do_not_const_check] // hooked by const-eval +#[rustc_const_unstable(feature = "core_panic", issue = "none")] +pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { + if cfg!(feature = "panic_immediate_abort") { + super::intrinsics::abort() + } + + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call + // that gets resolved to the `#[panic_handler]` function. + extern "Rust" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo<'_>) -> !; + } + + let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true); + + // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. + unsafe { panic_impl(&pi) } +} + +/// Like panic_fmt, but without unwinding and track_caller to reduce the impact on codesize. +/// Also just works on `str`, as a `fmt::Arguments` needs more space to be passed. +#[cold] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(bootstrap), rustc_nounwind)] +#[cfg_attr(bootstrap, rustc_allocator_nounwind)] +pub fn panic_str_nounwind(msg: &'static str) -> ! { + if cfg!(feature = "panic_immediate_abort") { + super::intrinsics::abort() + } + + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call + // that gets resolved to the `#[panic_handler]` function. + extern "Rust" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo<'_>) -> !; + } + + // PanicInfo with the `can_unwind` flag set to false forces an abort. + let pieces = [msg]; + let fmt = fmt::Arguments::new_v1(&pieces, &[]); + let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false); + + // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. + unsafe { panic_impl(&pi) } +} + +// Next we define a bunch of higher-level wrappers that all bottom out in the two core functions +// above. + /// The underlying implementation of libcore's `panic!` macro when no formatting is used. #[cold] // never inline unless panic_immediate_abort to avoid code @@ -97,67 +164,6 @@ fn panic_no_unwind() -> ! { panic_str_nounwind("panic in a function that cannot unwind") } -/// Like panic_fmt, but without unwinding and track_caller to reduce the impact on codesize. -/// Also just works on `str`, as a `fmt::Arguments` needs more space to be passed. -#[cold] -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] -#[cfg_attr(not(bootstrap), rustc_nounwind)] -#[cfg_attr(bootstrap, rustc_allocator_nounwind)] -pub fn panic_str_nounwind(msg: &'static str) -> ! { - if cfg!(feature = "panic_immediate_abort") { - super::intrinsics::abort() - } - - // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call - // that gets resolved to the `#[panic_handler]` function. - extern "Rust" { - #[lang = "panic_impl"] - fn panic_impl(pi: &PanicInfo<'_>) -> !; - } - - // PanicInfo with the `can_unwind` flag set to false forces an abort. - let pieces = [msg]; - let fmt = fmt::Arguments::new_v1(&pieces, &[]); - let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false); - - // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. - unsafe { panic_impl(&pi) } -} - -/// The entry point for panicking with a formatted message. -/// -/// This is designed to reduce the amount of code required at the call -/// site as much as possible (so that `panic!()` has as low an impact -/// on (e.g.) the inlining of other functions as possible), by moving -/// the actual formatting into this shared place. -#[cold] -// If panic_immediate_abort, inline the abort call, -// otherwise avoid inlining because of it is cold path. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] -#[track_caller] -#[lang = "panic_fmt"] // needed for const-evaluated panics -#[rustc_do_not_const_check] // hooked by const-eval -#[rustc_const_unstable(feature = "core_panic", issue = "none")] -pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { - if cfg!(feature = "panic_immediate_abort") { - super::intrinsics::abort() - } - - // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call - // that gets resolved to the `#[panic_handler]` function. - extern "Rust" { - #[lang = "panic_impl"] - fn panic_impl(pi: &PanicInfo<'_>) -> !; - } - - let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true); - - // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. - unsafe { panic_impl(&pi) } -} - /// This function is used instead of panic_fmt in const eval. #[lang = "const_panic_fmt"] #[rustc_const_unstable(feature = "core_panic", issue = "none")] From 1ff4f521c7373a1c611f3f53dbdb62e6fb27aa8c Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 11 Oct 2022 21:52:56 +0100 Subject: [PATCH 172/175] Update cargo 9 commits in 3cdf1ab25dc4fe56f890e8c7330d53a23ad905d3..b8f30cb23c4e5f20854a4f683325782b7cff9837 2022-10-07 17:34:03 +0000 to 2022-10-10 19:16:06 +0000 - Add more doc comments for three modules (rust-lang/cargo#11207) - docs: fix (rust-lang/cargo#11208) - Add completions for `cargo remove` (rust-lang/cargo#11204) - Config file loaded via CLI takes priority over env vars (rust-lang/cargo#11077) - Use `#[default]` when possible (rust-lang/cargo#11197) - Implement RFC 3289: source replacement ambiguity (rust-lang/cargo#10907) - Use correct version of cargo in test (rust-lang/cargo#11193) - Check empty input for login (rust-lang/cargo#11145) - Add retry support to sparse registries (rust-lang/cargo#11069) --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 3cdf1ab25dc4..b8f30cb23c4e 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 3cdf1ab25dc4fe56f890e8c7330d53a23ad905d3 +Subproject commit b8f30cb23c4e5f20854a4f683325782b7cff9837 From a7f58af9fe53bbdbc7a4ca9de049f9647c29d16f Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Wed, 12 Oct 2022 08:46:52 +0800 Subject: [PATCH 173/175] unify `IsPattern` and `IsImport` enum --- compiler/rustc_resolve/src/diagnostics.rs | 68 +++++++++++------------ 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9a3eac2f8662..d4d9e5c56078 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -139,8 +139,7 @@ impl<'a> Resolver<'a> { &candidates, if instead { Instead::Yes } else { Instead::No }, found_use, - IsPattern::No, - IsImport::No, + DiagnosticMode::Normal, path, ); err.emit(); @@ -699,8 +698,7 @@ impl<'a> Resolver<'a> { &import_suggestions, Instead::No, FoundUse::Yes, - IsPattern::Yes, - IsImport::No, + DiagnosticMode::Pattern, vec![], ); } @@ -1483,8 +1481,7 @@ impl<'a> Resolver<'a> { &import_suggestions, Instead::No, FoundUse::Yes, - IsPattern::No, - IsImport::No, + DiagnosticMode::Normal, vec![], ); @@ -2445,18 +2442,13 @@ enum FoundUse { No, } -/// Whether a binding is part of a pattern or an expression. Used for diagnostics. -enum IsPattern { +/// Whether a binding is part of a pattern or a use statement. Used for diagnostics. +enum DiagnosticMode { + Normal, /// The binding is part of a pattern - Yes, - /// The binding is part of an expression - No, -} - -/// Whether a binding is part of a use statement. Used for diagnostics. -enum IsImport { - Yes, - No, + Pattern, + /// The binding is part of a use statement + Import, } pub(crate) fn import_candidates( @@ -2475,8 +2467,7 @@ pub(crate) fn import_candidates( candidates, Instead::Yes, FoundUse::Yes, - IsPattern::No, - IsImport::Yes, + DiagnosticMode::Import, vec![], ); } @@ -2493,8 +2484,7 @@ fn show_candidates( candidates: &[ImportSuggestion], instead: Instead, found_use: FoundUse, - is_pattern: IsPattern, - is_import: IsImport, + mode: DiagnosticMode, path: Vec, ) { if candidates.is_empty() { @@ -2529,7 +2519,7 @@ fn show_candidates( }; let instead = if let Instead::Yes = instead { " instead" } else { "" }; - let mut msg = if let IsPattern::Yes = is_pattern { + let mut msg = if let DiagnosticMode::Pattern = mode { format!( "if you meant to match on {}{}{}, use the full path in the pattern", kind, instead, name @@ -2542,19 +2532,24 @@ fn show_candidates( err.note(note); } - if let (IsPattern::Yes, Some(span)) = (is_pattern, use_placement_span) { - err.span_suggestions( - span, - &msg, - accessible_path_strings.into_iter().map(|a| a.0), - Applicability::MaybeIncorrect, - ); - } else if let Some(span) = use_placement_span { + if let Some(span) = use_placement_span { + let add_use = match mode { + DiagnosticMode::Pattern => { + err.span_suggestions( + span, + &msg, + accessible_path_strings.into_iter().map(|a| a.0), + Applicability::MaybeIncorrect, + ); + return; + } + DiagnosticMode::Import => "", + DiagnosticMode::Normal => "use ", + }; for candidate in &mut accessible_path_strings { // produce an additional newline to separate the new use statement // from the directly following item. let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" }; - let add_use = if let IsImport::Yes = is_import { "" } else { "use " }; candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline); } @@ -2585,11 +2580,14 @@ fn show_candidates( err.note(&msg); } - } else if matches!(is_import, IsImport::No) { + } else if !matches!(mode, DiagnosticMode::Import) { assert!(!inaccessible_path_strings.is_empty()); - let prefix = - if let IsPattern::Yes = is_pattern { "you might have meant to match on " } else { "" }; + let prefix = if let DiagnosticMode::Pattern = mode { + "you might have meant to match on " + } else { + "" + }; if inaccessible_path_strings.len() == 1 { let (name, descr, def_id, note) = &inaccessible_path_strings[0]; let msg = format!( @@ -2597,7 +2595,7 @@ fn show_candidates( prefix, descr, name, - if let IsPattern::Yes = is_pattern { ", which" } else { "" } + if let DiagnosticMode::Pattern = mode { ", which" } else { "" } ); if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) { From bf14e3196b4f340b5c2a57b902b01e07a7d7c3dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Oct 2022 19:06:34 +0200 Subject: [PATCH 174/175] interpret: remove an incorrect assertion --- compiler/rustc_const_eval/src/interpret/terminator.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 50a82aa0e72c..57e40e168fa4 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -35,7 +35,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_eq!(discr.layout.ty, switch_ty); // Branch to the `otherwise` case by default, if no match is found. - assert!(!targets.iter().is_empty()); let mut target_block = targets.otherwise(); for (const_int, target) in targets.iter() { From e67e01b321eab10667fd3b2ae575005d015e0b88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Oct 2022 19:54:33 +0200 Subject: [PATCH 175/175] rustup --- src/tools/miri/rust-version | 2 +- src/tools/miri/src/concurrency/weak_memory.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 89a02096550b..21e9d5a05df8 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -0265a3e93bf1b89d97cae113ed214954d5c35e22 +538f118da1409759ba198acc0ff62070bc6d2dce diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 9d7a49c0b430..f2a365729549 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -17,7 +17,7 @@ //! load to the first, as a result of C++20's coherence-ordered before rules. //! //! Rust follows the C++20 memory model (except for the Consume ordering and some operations not performable through C++'s -//! std::atomic API). It is therefore possible for this implementation to generate behaviours never observable when the +//! `std::atomic` API). It is therefore possible for this implementation to generate behaviours never observable when the //! same program is compiled and run natively. Unfortunately, no literature exists at the time of writing which proposes //! an implementable and C++20-compatible relaxed memory model that supports all atomic operation existing in Rust. The closest one is //! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. ()