From ba64c93a44c5bdd78b01ef868435dc427f0cf4d4 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Mon, 5 Sep 2022 22:43:26 +0900 Subject: [PATCH 01/90] 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 3b3297f7811c0..c4f91e49a6e1b 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 f2fed954444e2..35686af38854d 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 419d3feec3b6c..1626465502071 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 2d04a864a2cfd..f0382846a6aff 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 02/90] 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 94d7806cb6e8f..3ae7fb2a617cf 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 03/90] 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 b385b1cafaefd..c4f7685cd140a 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 10ffde87eef14..d351eb599ce46 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 3ead929098bcc..094e460dbf79b 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 f0382846a6aff..e3d6be23e6586 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 d765fee0e1f4e..f80fb39c1f84e 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 04/90] 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 faec99c7d33c1..c5cf6729d1199 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 05/90] 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 bf59fadc2c336..d301595bcd98a 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 4ea103e5d9ec3..e6ff0762caa50 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 6df29db4745d3..10386b5b7bcdd 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 06/90] 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 22f5fb9926638..484e2d7d7ddb2 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 32ebfda4fd926..4c44840e861df 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 8aa5973cac57b..070f6837133a3 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 6ecb6e6fd173e..e934fe1c3234c 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 dd5639f00d219..79c5c01ec65fa 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 161b19a739ce4..431ab949b4624 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 e37763e8ea7f0..63d0f1b01cf03 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 d2f13e4351c73..be5ece9c5c500 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 9c7558d191877..f825a72c0f58a 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 7dd891c86e8d6..258224a7584a4 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 616a406c72758..8432f0e7e013c 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 7deffe8e0f637..20ab474e80273 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 c5c50d88dd28a..cd63131e7a732 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 4b8b47783d126..f24dec25b6b99 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 07/90] 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 e934fe1c3234c..b47d7308941f9 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 08/90] 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 63d0f1b01cf03..c821a3786b9fe 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 258224a7584a4..1b06dbd908501 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 8432f0e7e013c..fd78decda4e64 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 cd63131e7a732..8ac268f24382a 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 09/90] 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 484e2d7d7ddb2..be1a9d11773d7 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 b47d7308941f9..efb17c4780ae1 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 c821a3786b9fe..285ec7520f405 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 8ac268f24382a..44291a1a88b90 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 f24dec25b6b99..b877e6e5c9fd5 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 10/90] 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 be1a9d11773d7..2dc7714bbb540 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 efb17c4780ae1..141652db73a7e 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 4a052851afd14..357d43d225317 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 1b06dbd908501..b656eaa74cad7 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 44291a1a88b90..486739628f2ac 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 b877e6e5c9fd5..362b9fa815d37 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 11/90] 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 141652db73a7e..11d93d19c3cfc 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 357d43d225317..b76506f6ebc2c 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 486739628f2ac..f7cdc9e5b2fda 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 362b9fa815d37..eb997e6fef830 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 12/90] 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 11d93d19c3cfc..965bf3f2c5b84 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 b656eaa74cad7..6bcbe62efa883 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 f7cdc9e5b2fda..4c429202e6f9a 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 13/90] 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 f2fed954444e2..9121fb50fd630 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 6bcbe62efa883..7d32aef8eb99d 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 4c429202e6f9a..8442e101b6f3c 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 14/90] 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 8442e101b6f3c..d109c0769194f 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 15/90] 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 3c96290fc537e..6c70517d965b2 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 16/90] 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 0000000000000..171e9214a4e61 --- /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 812d22efbd797..82bcc3dfa5d9a 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 3a696635afd27..d403f86c6d8c9 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 17/90] 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 837ea016193cd..32db42f1db75e 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 736d80041bd51..8e50fe878ae36 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(Default, Clone, Debug, PartialEq, Eq)] -pub struct CargoConfig { - /// Do not activate the `default` feature. - pub no_default_features: bool, +#[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, + }, +} - /// Activate all available features - pub all_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 { /// 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 b81b7432f6554..ce78ce85697af 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 1c39e9391af24..e1675a030c0f6 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 9ef79e6f38120..0d0e246029b16 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 18/90] 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 8e50fe878ae36..bd2bbadea239b 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 63d1d0ace96b9..5133a14d532bb 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 486cb143b80bd..3231361836634 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 3282719fef3d7..f0d76aa922f70 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 bea624bd54195..813f0a7ce9f1d 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 bc4ab45daeffc..c749a3b6566fd 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 80128e43fd3c5..81c393abdb347 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 88953096e2bcd..e07d905423739 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 79577bf78c8f9..748306ea57d4e 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 05c16bb39e351..2c29b3ee3a6f7 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 0d0e246029b16..5d99d2fb1193d 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 4cf5de46c485e..e7f7972e9abb1 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 996d4c023d7b2..a34f4d5093e3e 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 94b41c049bc30..f8eec9f62e529 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 19/90] 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 93fcd7cad7a18..08363d21e89b3 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 20/90] 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 285ec7520f405..7d1c98207586d 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 21/90] 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 4a5533c6487e4..ed97bd2da4f38 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 532544fee595c..e28c87dfa46b8 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 23e51a9c16a56..47cc3341e7076 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 22/90] 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 ba9a1cfb6b51c..87e22c2138b72 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 c749a3b6566fd..2c0af99940f97 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 23/90] 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 9395e914c43aa..e7d0a8be7f573 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 e07fd3925c784..9ed65fbc8548d 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 @@ 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 eef5baea98392..18045f1f55afd 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 @@ /// ```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 a97802cbbd0f9..9f2b1926b511d 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 @@ } 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 @@ 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 @@ 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 ced7d22f03e47..abcd80c280bf3 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 @@ .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 2d85fc8c925b7..f98e0b1cda6e9 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 @@
 

 #[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 c627bc9b09ab0..a626cda3fe8b4 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 @@
         () => (
             $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 0716bae7513b9..1992bdc6ae35f 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 @@
 }
 macro_rules! unsafe_deref {
     () => {
-        *(&() as *const ())
+        *(&() as *const ())
     };
 }
 static mut MUT_GLOBAL: Struct = Struct { field: 0 };
@@ -63,7 +63,7 @@
 
 struct Struct { field: i32 }
 impl Struct {
-    unsafe fn unsafe_method(&self) {}
+    unsafe fn unsafe_method(&self) {}
 }
 
 #[repr(packed)]
@@ -78,11 +78,11 @@
 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 24/90] 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 965bf3f2c5b84..2c0c6e0b8394f 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 25/90] 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 277135d6dc428..785095800604b 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 4c44840e861df..5c7aa72349f6e 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 e16530ecc1553..9ac5eaa74e94c 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 7d1c98207586d..85309d32335d6 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 389e07db336ac..7d25eee0c0b41 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 26/90] 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 85309d32335d6..2c6d503def1d3 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 27/90] 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 785095800604b..b093669e6a71a 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 9ac5eaa74e94c..72abcc2b4b602 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 2c6d503def1d3..daf1e2f0c6d3b 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 7d25eee0c0b41..1c48d2ff0817c 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 28/90] 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 b093669e6a71a..14f8629056faf 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 be5ece9c5c500..ebbc5410147c6 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 4ea103e5d9ec3..1757327b929d0 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 29/90] 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 171e9214a4e61..25c58d086e977 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 30/90] 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 d2f9c2b8b1e1d..71763430ea389 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 e6ff0762caa50..b42c5fe7fc41f 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 31/90] 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 808eb5d10bf4a..c9ff0b6c29e37 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 32/90] 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 b94b50004093c..c70e6fdccdcde 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 33/90] 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 97e5bd35ce0ee..ce00d37beb405 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 f57cd838d828cc2a73ac7e133df0e9641dcac9b5 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Fri, 23 Sep 2022 23:30:23 +0200
Subject: [PATCH 34/90] 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 44712f419191b..243972b04997c 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 f7d3a30919e1c..2f854bc159548 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 3679bfc43c980..72a2dfe72d374 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 6339d56d01791..b46cdddcf6b10 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 f881fe86847d6..44b1b6588da0a 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 4cc46af1b17c5..3e3f1c162f52c 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 35/90] 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 5b1435e8f4424..bb13165257ba4 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 1c48d2ff0817c..9fcaac85bce00 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 87e22c2138b72..fa45e3c12eb00 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 36/90] 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 9fcaac85bce00..e1f69001e8002 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 73f6af54c105619f00c3e561c73b64c61b457ffc Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Sat, 24 Sep 2022 22:04:17 +0200
Subject: [PATCH 37/90] 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 e07d905423739..5dba545b87184 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 2ea770d067b186dac4be6fe22757efc8f8176eb2 Mon Sep 17 00:00:00 2001
From: David Carlier 
Date: Sat, 24 Sep 2022 09:08:56 +0100
Subject: [PATCH 38/90] 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 cc347e3586ae3..60545be71de17 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 39/90] 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 5392589186d1d..861753d6fb410 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 a84110d940bc7..e75867e2d81cf 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 40/90] 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 8e6e6a11abda8..5b7828a26996e 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 b388e47dee6e4..9ceaebb91e160 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 c1ef25b592b1b..7820b67142fe1 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 600a526300c76..852a8fd837616 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 2c0af99940f97..d9d3cab45614f 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 41/90] 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 813f0a7ce9f1d..e2444e24974a7 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 42/90] 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 9ceaebb91e160..e7f0c4ec29bf4 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 43/90] 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 3342d4db4aa64..570344596def8 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 7f2551e941871..077a1b619dd5a 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 34dd817fd130c..da1643152c2fe 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 9242b48c59319..5f0cf9c4ac896 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 ed7e920fd2b83..066142291981d 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 11c0a6764e9d8..2b27db0e95063 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 5edc16d8bce90..c5dc60f1ec5f9 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 04918891b254c..c22e25b0637de 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 449402e5f5b30..f4664f3aaeae3 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 70b54843dbaab..56d7c98d58a3e 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 44/90] 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 14f8629056faf..af8ca8571ba20 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 40b2f734b7117..93ffe29a1fe82 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 5f0cf9c4ac896..9ffc218818ca1 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 e1f69001e8002..d1c8fa59aef47 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 c22e25b0637de..f558b7256a4c6 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 45/90] 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 af8ca8571ba20..938db032fbc8b 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 631ae3cf11fa7..2dc69b00ace00 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 93ffe29a1fe82..431c8255497b6 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 46/90] 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 f4664f3aaeae3..449402e5f5b30 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 bb92c51e9a90e..fe82aa907222f 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 56d7c98d58a3e..70b54843dbaab 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 47/90] 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 3e3f1c162f52c..9032c21d096bc 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 48/90] 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 92df4d70fd902..55fa616d50703 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 49/90] 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 216cf51447fad..93b7f746e01bc 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 861753d6fb410..71566d5de6e6f 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 55fa616d50703..000ff88e458f6 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 3cfbc2e4e4503..c64d557a118f2 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 204d120d07c4a..b236b156cf99a 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 ce00d37beb405..b241561f9c0dd 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 1f3d447153bd0..e5f19be20b069 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 50/90] 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 258144bae3d08..a3bb66e379eb8 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 9d5e3a1f45a1f62e9826208b922cccf064d619c1 Mon Sep 17 00:00:00 2001
From: John Millikin 
Date: Sun, 18 Sep 2022 10:53:35 +0900
Subject: [PATCH 51/90] 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 21f80ec025a81..55e58c4e0baa5 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 52/90] 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 4ce21a57967c7..2679a1c360267 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 039824694ace0..25179afaca7ad 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 e3d6be23e6586..2643baf8a3299 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 21a86319763fc..555b6972fb71e 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 08363d21e89b3..34d8bf67a3016 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 53/90] 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 a180706e1cf0f..9c690fc15de4f 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 72ac897d4f178..d418965cd2f6b 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 3018d1c9125bf..ce803a18348bc 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 3caaf521240d2..09f3106dcfcdb 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 cda27beab300f..aced15646a2ac 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 54/90] 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 c64d557a118f2..15922dac651cc 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 55/90] 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 bfbe0db6e4b84..f994c284c713a 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 63fb322cea07e..0cadf125fecae 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 7820b67142fe1..77fe0dbf55658 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 7bdd34d1f093a..f2db9a2733497 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 1de801e23e5c8..5936454a7c546 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 56/90] 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 0e29c52ade683..27b2f445d73ca 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 57/90] 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 92b2fa79d717b..aa710d2ce6513 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 58/90] 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 fc128102f225a..a5b499fe8d9d4 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 416b6f58061da..119ec3210e175 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 785db6fde1d5a..e82cbfdcb8402 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 59/90] 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 9ef79e6f38120..5241aad327cfd 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 4cf5de46c485e..e403f36d57872 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 60/90] Add config for supplying sysroot path

---
 crates/project-model/src/cargo_workspace.rs   |  5 +--
 crates/project-model/src/sysroot.rs           | 42 +++++++++++++------
 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, 87 insertions(+), 40 deletions(-)

diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index bd2bbadea239b..8e690f1125a01 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 f0d76aa922f70..bc37e3d132a6c 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(
-    sysroot_path: &AbsPathBuf,
-    current_dir: &AbsPath,
-    extra_env: &FxHashMap,
-) -> Result {
+fn discover_sysroot_src_dir(sysroot_path: &AbsPathBuf) -> Option {
     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);
+        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");
         }
-        tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
     }
 
     get_rust_src(sysroot_path)
+}
+fn discover_sysroot_src_dir_or_add_component(
+    sysroot_path: &AbsPathBuf,
+    current_dir: &AbsPath,
+    extra_env: &FxHashMap,
+) -> Result {
+    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 d9d3cab45614f..72ddf809288aa 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 81c393abdb347..01fccc83e8227 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 dfef6f014ca5c..577a8640a4c00 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 9032c21d096bc..fa55f7d90c49d 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 4fa88c3c6da11..7257445dabe05 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 c7f152acc2669..4ac75b4bbfd96 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 a34f4d5093e3e..acf0aaea859a2 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 f8eec9f62e529..f1dd3aa79ff04 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 61/90] 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 72ddf809288aa..8c3e8681d9894 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 f8f5a5ea5788a846013545d63c9b46fd70cc4f7c Mon Sep 17 00:00:00 2001
From: Ryo Yoshida 
Date: Sun, 2 Oct 2022 18:39:42 +0900
Subject: [PATCH 62/90] 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 3ae7fb2a617cf..dd4f1f25a6911 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 ed97bd2da4f38..4f0e9dbf1e4e9 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 f580e09e91229..7bb79b519e1ca 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 e28c87dfa46b8..da19dab9f986f 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 d6638db028511..32ccd5fa43db3 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 63/90] 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 dd4f1f25a6911..c0052258ee037 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 da19dab9f986f..82128ae6586d1 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 32ccd5fa43db3..adcf142bc35f0 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 64/90] 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 344036dd8139d..02332ea80d883 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 c5cf6729d1199..3f3f8f7d0f2a2 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 a5058f71a4a6d..7f0baf49dadce 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 25179afaca7ad..31e56dec62593 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 2643baf8a3299..f56108b26c45b 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 7bb79b519e1ca..7a4754cdc7bb8 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 e77b55670b5e1..6ccd0b215c6e4 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 82128ae6586d1..0a4b1dfda1055 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),
+                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)
+                    }
                     ParamLoweringMode::Variable => {
-                        generics.bound_vars_subst(self.db, self.in_binders)
+                        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()
                     }
-                };
-                self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
+                }
             }
             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());
-
-                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));
-                    }
-                }
+            let defaults = self.db.generic_defaults(def);
+            assert_eq!(total_len, defaults.len());
+            let parent_from = item_len - substs.len();
+
+            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));
             }
-        }
 
-        // 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)))
-                }
-            }
+            // Keep parent's params as unknown.
+            let mut remaining_params = remaining_params;
+            substs.extend(remaining_params.drain(parent_from..));
+        } else {
+            substs.extend(remaining_params);
         }
-        // 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);
 
+        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 41fcef73d9be4..5998680dcd395 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 d1c8fa59aef47..e08dd8dadebc5 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 342912b678a1d..07bae2b38c796 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 65/90] 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 47cc3341e7076..16ba3dd6e3c97 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 adcf142bc35f0..e54bcb421a222 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 59168035551959e089eaf4778acc84978accb9c4 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 3 Oct 2022 14:03:54 +0200
Subject: [PATCH 66/90] 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 fdc03f4053a27..e8c63d410aa75 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 e0a161b2e3a9345fd92fd3617e49648ee43ada86 Mon Sep 17 00:00:00 2001
From: Ryo Yoshida 
Date: Tue, 4 Oct 2022 00:07:34 +0900
Subject: [PATCH 67/90] 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 c0052258ee037..9ae752556d890 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 0a4b1dfda1055..a77dd910ff714 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 68/90] 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 8c3e8681d9894..72ddf809288aa 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 ded3326a64c2ef220f3cec9af863f738749d6ce2 Mon Sep 17 00:00:00 2001
From: Ryo Yoshida 
Date: Wed, 5 Oct 2022 00:20:01 +0900
Subject: [PATCH 69/90] 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 a77dd910ff714..223d705b157b3 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 16ba3dd6e3c97..a155adcec6c33 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 8bda13367e4987937ddc2ba9bbe01b5f7a4cce3e Mon Sep 17 00:00:00 2001
From: Gary Guo 
Date: Wed, 5 Oct 2022 02:29:56 +0100
Subject: [PATCH 70/90] 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 8799137b78f98..27b50c13b77ca 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 8862fe6ff25c209ec4c027f0c253005ec3a9e3e0 Mon Sep 17 00:00:00 2001
From: Wildbook 
Date: Wed, 5 Oct 2022 17:45:32 +0200
Subject: [PATCH 71/90] 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 e08dd8dadebc5..f5324208c9a4e 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 1bdd626f1e834..540a115832d3e 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 a57ef6b0b17b1cbeac14789908b62df6ffef4079 Mon Sep 17 00:00:00 2001
From: Maybe Waffle 
Date: Thu, 6 Oct 2022 06:10:28 +0000
Subject: [PATCH 72/90] 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 36a648fe4a8ea..7d8ef7ab9dc2f 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 1c0ec9f0c84e59cb6eda77fcb082f26c77566685 Mon Sep 17 00:00:00 2001
From: Maybe Waffle 
Date: Fri, 7 Oct 2022 09:04:41 +0000
Subject: [PATCH 73/90] 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 92ce26b422e1d..d96827326cfd8 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 7d8ef7ab9dc2f..f86ea61d1586f 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 b0b072d7477a2d10ac7bee77b84ec33151f8eb65 Mon Sep 17 00:00:00 2001
From: Jhonny Bill Mena 
Date: Tue, 4 Oct 2022 13:23:53 -0400
Subject: [PATCH 74/90] 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 0000000000000..170b7983dbe5f
--- /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 3ef9a634e1857..e62b6f342b2e9 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 0000000000000..deba0dc6f9954
--- /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 18be60975e4eb..10f8efdffa8b6 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 75/90] 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 c71d332475a5f..60547acc95661 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 170b7983dbe5f..718ad5c7bf566 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 deba0dc6f9954..597f3488fc1be 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 76/90] 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 60547acc95661..e9335e53125f3 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 718ad5c7bf566..13d9c1a7b6b8d 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 597f3488fc1be..d84a774710ac1 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 77/90] 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 e9335e53125f3..debcffcd326f6 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 13d9c1a7b6b8d..05d89b32618e7 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 d84a774710ac1..090a4dc9510b6 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 78/90] 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 6188094bbbdd4..125b231b27486 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 05d89b32618e7..2ae5e659d2dac 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 090a4dc9510b6..0d021edc4f76c 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 79/90] 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 2ae5e659d2dac..8c09aa96c8ef2 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 80/90] 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 125b231b27486..1f577e9f3524f 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 81/90] 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 8c09aa96c8ef2..cf98cb2468ab7 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 0d021edc4f76c..4d43b2eb0b696 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 82/90] 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 9a0c379b4e44d..ac2a8f969df00 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 cf98cb2468ab7..6bd1dc2e03f66 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 e62b6f342b2e9..ceebe4d417f7d 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 4d43b2eb0b696..d996a096a892e 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 83/90] 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      | 42 ++++---------------
 .../locales/en-US/codegen_ssa.ftl             |  6 ---
 compiler/rustc_error_messages/src/lib.rs      |  4 +-
 5 files changed, 15 insertions(+), 53 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index ac2a8f969df00..e798fb421df31 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 debcffcd326f6..bad22ccb1fedd 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 6bd1dc2e03f66..bd399ffb5a6f9 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,
+
+    #[diag(codegen_ssa::rlib_only_rmeta_found)]
     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_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 d996a096a892e..99ddf6842dab8 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 10f8efdffa8b6..77f87d5b007e3 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 84/90] 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 e798fb421df31..95e72184ff037 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 bd399ffb5a6f9..0ffe887202261 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 99ddf6842dab8..0d0388a039e2d 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 39fa8b5c39c3f259043364d4b7ab6bf3dfc54356 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov 
Date: Sat, 8 Oct 2022 15:35:07 +0100
Subject: [PATCH 85/90] internal: :arrow_up: xflags

The main change here should be that flags are not inhereted, so

   $ rust-analyzer analysis-stats . -v -v

would do what it should do

We also no longer Don\'t
---
 Cargo.lock                            |  8 +++----
 crates/rust-analyzer/Cargo.toml       |  2 +-
 crates/rust-analyzer/src/bin/main.rs  | 11 +++-------
 crates/rust-analyzer/src/cli/flags.rs | 31 +++++++++++++--------------
 xtask/Cargo.toml                      |  2 +-
 xtask/src/flags.rs                    | 19 ++++++----------
 xtask/src/main.rs                     |  7 ++----
 7 files changed, 32 insertions(+), 48 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 93b7f746e01bc..e45cde6838813 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2082,18 +2082,18 @@ checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3"
 
 [[package]]
 name = "xflags"
-version = "0.2.4"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f14fe1ed41a5a2b5ef3f565586c4a8a559ee55d3953faab360a771135bdee00"
+checksum = "cbf19f5031a1a812e96fede16f8161218883079946cea87619d3613db1efd268"
 dependencies = [
  "xflags-macros",
 ]
 
 [[package]]
 name = "xflags-macros"
-version = "0.2.4"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45d11d5fc2a97287eded8b170ca80533b3c42646dd7fa386a5eb045817921022"
+checksum = "2afbd7f2039bb6cad2dd45f0c5dff49c0d4e26118398768b7a605524d4251809"
 
 [[package]]
 name = "xshell"
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 71566d5de6e6f..a4e6550984ee8 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -25,7 +25,7 @@ itertools = "0.10.3"
 scip = "0.1.1"
 lsp-types = { version = "0.93.1", features = ["proposed"] }
 parking_lot = "0.12.1"
-xflags = "0.2.4"
+xflags = "0.3.0"
 oorandom = "11.1.3"
 rustc-hash = "1.1.0"
 serde = { version = "1.0.137", features = ["derive"] }
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index f6a6802972525..eabfcf1944dfd 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -37,16 +37,15 @@ fn main() {
         process::exit(code);
     }
 
-    if let Err(err) = try_main() {
+    let flags = flags::RustAnalyzer::from_env_or_exit();
+    if let Err(err) = try_main(flags) {
         tracing::error!("Unexpected error: {}", err);
         eprintln!("{}", err);
         process::exit(101);
     }
 }
 
-fn try_main() -> Result<()> {
-    let flags = flags::RustAnalyzer::from_env()?;
-
+fn try_main(flags: flags::RustAnalyzer) -> Result<()> {
     #[cfg(debug_assertions)]
     if flags.wait_dbg || env::var("RA_WAIT_DBG").is_ok() {
         #[allow(unused_mut)]
@@ -76,10 +75,6 @@ fn try_main() -> Result<()> {
                 println!("rust-analyzer {}", rust_analyzer::version());
                 return Ok(());
             }
-            if cmd.help {
-                println!("{}", flags::RustAnalyzer::HELP);
-                return Ok(());
-            }
             with_extra_thread("LspServer", run_server)?;
         }
         flags::RustAnalyzerCmd::ProcMacro(flags::ProcMacro) => {
diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs
index aa32654fbdca1..5bcc97e226122 100644
--- a/crates/rust-analyzer/src/cli/flags.rs
+++ b/crates/rust-analyzer/src/cli/flags.rs
@@ -31,8 +31,6 @@ xflags::xflags! {
         default cmd lsp-server {
             /// Print version.
             optional --version
-            /// Print help.
-            optional -h, --help
 
             /// Dump a LSP config JSON schema.
             optional --print-config-schema
@@ -54,10 +52,10 @@ xflags::xflags! {
         }
 
         /// Batch typecheck project and print summary statistics
-        cmd analysis-stats
+        cmd analysis-stats {
             /// Directory with Cargo.toml.
             required path: PathBuf
-        {
+
             optional --output format: OutputFormat
 
             /// Randomize order in which crates, modules, and items are processed.
@@ -84,38 +82,37 @@ xflags::xflags! {
             optional --skip-inference
         }
 
-        cmd diagnostics
+        cmd diagnostics {
             /// Directory with Cargo.toml.
             required path: PathBuf
-        {
+
             /// Don't run build scripts or load `OUT_DIR` values by running `cargo check` before analysis.
             optional --disable-build-scripts
             /// Don't use expand proc macros.
             optional --disable-proc-macros
         }
 
-        cmd ssr
+        cmd ssr {
             /// A structured search replace rule (`$a.foo($b) ==> bar($a, $b)`)
             repeated rule: SsrRule
-        {}
+        }
 
-        cmd search
+        cmd search {
             /// A structured search replace pattern (`$a.foo($b)`)
             repeated pattern: SsrPattern
-        {
             /// Prints debug information for any nodes with source exactly equal to snippet.
             optional --debug snippet: String
         }
 
         cmd proc-macro {}
 
-        cmd lsif
+        cmd lsif {
             required path: PathBuf
-        {}
+        }
 
-        cmd scip
+        cmd scip {
             required path: PathBuf
-        {}
+        }
     }
 }
 
@@ -150,7 +147,6 @@ pub enum RustAnalyzerCmd {
 #[derive(Debug)]
 pub struct LspServer {
     pub version: bool,
-    pub help: bool,
     pub print_config_schema: bool,
 }
 
@@ -218,7 +214,10 @@ pub struct Scip {
 }
 
 impl RustAnalyzer {
-    pub const HELP: &'static str = Self::HELP_;
+    #[allow(dead_code)]
+    pub fn from_env_or_exit() -> Self {
+        Self::from_env_or_exit_()
+    }
 
     #[allow(dead_code)]
     pub fn from_env() -> xflags::Result {
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index 95d44e9b9d09f..14816912b720d 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -11,5 +11,5 @@ anyhow = "1.0.57"
 flate2 = "1.0.24"
 write-json = "0.1.2"
 xshell = "0.2.2"
-xflags = "0.2.4"
+xflags = "0.3.0"
 # Avoid adding more dependencies to this crate
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index 993c64cceaf01..0fce48898349a 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -7,10 +7,6 @@ xflags::xflags! {
 
     /// Run custom build command.
     cmd xtask {
-        default cmd help {
-            /// Print help information.
-            optional -h, --help
-        }
 
         /// Install rust-analyzer server or editor plugin.
         cmd install {
@@ -42,9 +38,9 @@ xflags::xflags! {
             optional --dry-run
         }
         /// Builds a benchmark version of rust-analyzer and puts it into `./target`.
-        cmd bb
+        cmd bb {
             required suffix: String
-        {}
+        }
     }
 }
 
@@ -58,7 +54,6 @@ pub struct Xtask {
 
 #[derive(Debug)]
 pub enum XtaskCmd {
-    Help(Help),
     Install(Install),
     FuzzTests(FuzzTests),
     Release(Release),
@@ -68,11 +63,6 @@ pub enum XtaskCmd {
     Bb(Bb),
 }
 
-#[derive(Debug)]
-pub struct Help {
-    pub help: bool,
-}
-
 #[derive(Debug)]
 pub struct Install {
     pub client: bool,
@@ -111,7 +101,10 @@ pub struct Bb {
 }
 
 impl Xtask {
-    pub const HELP: &'static str = Self::HELP_;
+    #[allow(dead_code)]
+    pub fn from_env_or_exit() -> Self {
+        Self::from_env_or_exit_()
+    }
 
     #[allow(dead_code)]
     pub fn from_env() -> xflags::Result {
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 335ac324a574f..a37f469adcb60 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -25,15 +25,12 @@ use std::{
 use xshell::{cmd, Shell};
 
 fn main() -> anyhow::Result<()> {
+    let flags = flags::Xtask::from_env_or_exit();
+
     let sh = &Shell::new()?;
     sh.change_dir(project_root());
 
-    let flags = flags::Xtask::from_env()?;
     match flags.subcommand {
-        flags::XtaskCmd::Help(_) => {
-            println!("{}", flags::Xtask::HELP);
-            Ok(())
-        }
         flags::XtaskCmd::Install(cmd) => cmd.run(sh),
         flags::XtaskCmd::FuzzTests(_) => run_fuzzer(sh),
         flags::XtaskCmd::Release(cmd) => cmd.run(sh),

From 61519b8cf1c768fd3683f38a8fcfa96dc0138cdb Mon Sep 17 00:00:00 2001
From: Ariel Davis 
Date: Sun, 9 Oct 2022 21:44:44 -0700
Subject: [PATCH 86/90] Add basename and dirname aliases

---
 library/std/src/fs.rs   | 1 +
 library/std/src/path.rs | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index c6c78dc3939e7..190608e43b92b 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1670,6 +1670,7 @@ 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()
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 4f9dff1ef0353..9d63281627d66 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2158,6 +2158,7 @@ impl Path {
     /// assert_eq!(grand_parent.parent(), None);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[doc(alias = "dirname")]
     #[must_use]
     pub fn parent(&self) -> Option<&Path> {
         let mut comps = self.components();
@@ -2225,6 +2226,7 @@ impl Path {
     /// assert_eq!(None, Path::new("/").file_name());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[doc(alias = "basename")]
     #[must_use]
     pub fn file_name(&self) -> Option<&OsStr> {
         self.components().next_back().and_then(|p| match p {

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

---
 compiler/rustc_error_messages/src/lib.rs     | 13 -----
 compiler/rustc_expand/src/mbe/macro_rules.rs | 19 ++++---
 src/test/ui/macros/issue-102878.rs           | 10 ++++
 src/test/ui/macros/issue-102878.stderr       | 60 ++++++++++++++++++++
 4 files changed, 81 insertions(+), 21 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 18be60975e4eb..9a7cb955f216f 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 6d2c7aac6af49..30aa4f0fa3482 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 !e.span.is_dummy() {
-            // early end of macro arm (#52866)
-            e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
-        }
+    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] = (
-            rustc_errors::DiagnosticMessage::Str(format!(
+            DiagnosticMessage::Str(format!(
                 "macro expansion ends with an incomplete expression: {}",
-                msg.0.expect_str().replace(", found ``", ""),
+                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));
+        }
     }
     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 0000000000000..aac5891939e0c
--- /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 0000000000000..e0b8855a38d05
--- /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 d1762d7a96adbeb4702bcb4486ebf47555bfd01b Mon Sep 17 00:00:00 2001
From: Ariel Davis 
Date: Mon, 10 Oct 2022 17:05:59 -0700
Subject: [PATCH 88/90] 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 190608e43b92b..c6c78dc3939e7 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 1a8f177772658a244e79a9aa2d48898a4e24c9ce Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Mon, 10 Oct 2022 19:21:35 +0400
Subject: [PATCH 89/90] 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 85306d7184d89..54c83fb760460 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 46886c518afd5..c55b490630200 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 56d71aaa7d332..687d810ed4e31 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 8281164ab1207..ce5893efa926d 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 1ea76fdbfcbbb..1af1633b5244b 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 6bb1bb9eace8b..888776cccac2d 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 f1f0c224bbdd1..4ef4aad902c68 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 c3d87b5b6af3c..a17793ecd99bd 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 989a827ef7d9f..4ccc9db1bb64e 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 c05f89a65755f..13cd7987e923d 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 9173c3692ce6c..bf94172612343 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 dafa10e9e0026..f6f0b3c11391b 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 90/90] 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          | 30 ++++++++++-------
 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, 137 insertions(+), 25 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 c499364056ff9..69155a422b062 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 98982240af27f..75c016af2f92f 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 431507e8e0f63..9fc8401fa07f5 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 9173c3692ce6c..4c9e14db3c43a 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 6aa1b483eebdd..3a70a2f943ffd 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 03782f6634800..bf4bd634cf1d4 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`
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0201`.
+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 c9119c1027111..f89ea6e57cc43 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 94e06894144ca..f72145a82447b 100644
--- a/src/test/ui/error-codes/E0201.stderr
+++ b/src/test/ui/error-codes/E0201.stderr
@@ -1,27 +1,33 @@
-error[E0201]: duplicate definitions with name `bar`:
-  --> $DIR/E0201.rs:5:5
-   |
-LL |     fn bar(&self) -> bool { self.0 > 5 }
-   |     --------------------- previous definition of `bar` here
-LL |     fn bar() {}
-   |     ^^^^^^^^ duplicate definition
-
 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 of `baz` here
+   |     ------------------------------ previous definition here
 LL |     fn baz(&self) -> bool { self.0 > 5 }
-   |     ^^^^^^^^^^^^^^^^^^^^^ duplicate definition
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 of `Quux` here
+   |     ---------------- previous definition here
 ...
 LL |     type Quux = u32;
-   |     ^^^^^^^^^ duplicate definition
+   |     ^^^^^^^^^^^^^^^^ duplicate definition
+
+error[E0201]: duplicate definitions with name `bar`:
+  --> $DIR/E0201.rs:5:5
+   |
+LL |     fn bar(&self) -> bool { self.0 > 5 }
+   |     --------------------- previous definition of `bar` here
+LL |     fn bar() {}
+   |     ^^^^^^^^ duplicate definition
 
 error: aborting due to 3 previous errors
 
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 0000000000000..465e444aedb6b
--- /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 0000000000000..3c0ffeb105752
--- /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 b76bbc0235fde..ae214bb9e9b4f 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