Repository: rust-analyzer/rust-analyzer
Pull request #8421 (2021-04-08 14:21:34)

Reduce allocations in "Expand macro" formatter

lnicola: changelog fix

Patch:
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 0afc069061..13aaa408a2 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -59,8 +59,7 @@ use hir_ty::{
     traits::FnTrait,
     AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
     DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution,
-    TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind,
-    WhereClause,
+    TraitEnvironment, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause,
 };
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
@@ -1791,7 +1790,7 @@ impl Type {
             .build();
 
         let goal = Canonical {
-            value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(&Interner)),
+            value: hir_ty::InEnvironment::new(self.env.env.clone(), trait_ref.cast(&Interner)),
             binders: CanonicalVarKinds::empty(&Interner),
         };
 
@@ -1808,9 +1807,9 @@ impl Type {
             .push(self.ty.clone())
             .fill(args.iter().map(|t| t.ty.clone()))
             .build();
-        let goal = hir_ty::make_canonical(
+        let goal = Canonical::new(
             InEnvironment::new(
-                &self.env.env,
+                self.env.env.clone(),
                 AliasEq {
                     alias: AliasTy::Projection(projection),
                     ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index a7d0f5b1fc..75ec4196b6 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -490,7 +490,7 @@ fn env_expand(
         // unnecessary diagnostics for eg. `CARGO_PKG_NAME`.
         if key == "OUT_DIR" {
             err = Some(mbe::ExpandError::Other(
-                r#"`OUT_DIR` not set, enable "run build scripts" to fix"#.into(),
+                r#"`OUT_DIR` not set, enable "load out dirs from check" to fix"#.into(),
             ));
         }
 
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index 28ed3aac6d..8e8a1aa481 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -8,7 +8,7 @@ use hir_def::{
 use crate::{
     db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
     from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId,
-    CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause,
+    CallableSig, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause,
     Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
 };
 
@@ -34,9 +34,6 @@ pub trait TyExt {
 
     fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>;
     fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>;
-
-    /// FIXME: Get rid of this, it's not a good abstraction
-    fn equals_ctor(&self, other: &Ty) -> bool;
 }
 
 impl TyExt for Ty {
@@ -202,12 +199,12 @@ impl TyExt for Ty {
                             .map(|pred| pred.clone().substitute(&Interner, &substs))
                             .filter(|wc| match &wc.skip_binders() {
                                 WhereClause::Implemented(tr) => {
-                                    &tr.self_type_parameter(&Interner) == self
+                                    tr.self_type_parameter(&Interner) == self
                                 }
                                 WhereClause::AliasEq(AliasEq {
                                     alias: AliasTy::Projection(proj),
                                     ty: _,
-                                }) => &proj.self_type_parameter(&Interner) == self,
+                                }) => proj.self_type_parameter(&Interner) == self,
                                 _ => false,
                             })
                             .collect::<Vec<_>>();
@@ -241,36 +238,6 @@ impl TyExt for Ty {
             _ => None,
         }
     }
-
-    fn equals_ctor(&self, other: &Ty) -> bool {
-        match (self.kind(&Interner), other.kind(&Interner)) {
-            (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
-            (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => {
-                true
-            }
-            (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
-            (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
-            (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => {
-                ty_id == ty_id2
-            }
-            (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2,
-            (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2,
-            (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..))
-            | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => {
-                mutability == mutability2
-            }
-            (
-                TyKind::Function(FnPointer { num_binders, sig, .. }),
-                TyKind::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }),
-            ) => num_binders == num_binders2 && sig == sig2,
-            (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => {
-                cardinality == cardinality2
-            }
-            (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true,
-            (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2,
-            _ => false,
-        }
-    }
 }
 
 pub trait ProjectionTyExt {
@@ -293,13 +260,3 @@ impl ProjectionTyExt for ProjectionTy {
         }
     }
 }
-
-pub trait TraitRefExt {
-    fn hir_trait_id(&self) -> TraitId;
-}
-
-impl TraitRefExt for TraitRef {
-    fn hir_trait_id(&self) -> TraitId {
-        from_chalk_trait_id(self.trait_id)
-    }
-}
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index e0ca96c6d2..9e6bbcdf1e 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -24,7 +24,7 @@ use crate::{
     traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy, CallableDefId,
     CallableSig, Const, ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime,
     LifetimeData, LifetimeOutlives, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt,
-    QuantifiedWhereClause, Scalar, TraitRef, TraitRefExt, Ty, TyExt, TyKind, WhereClause,
+    QuantifiedWhereClause, Scalar, TraitRef, Ty, TyExt, TyKind, WhereClause,
 };
 
 pub struct HirFormatter<'a> {
@@ -616,12 +616,12 @@ impl HirDisplay for Ty {
                                 .map(|pred| pred.clone().substitute(&Interner, &substs))
                                 .filter(|wc| match &wc.skip_binders() {
                                     WhereClause::Implemented(tr) => {
-                                        &tr.self_type_parameter(&Interner) == self
+                                        tr.self_type_parameter(&Interner) == self
                                     }
                                     WhereClause::AliasEq(AliasEq {
                                         alias: AliasTy::Projection(proj),
                                         ty: _,
-                                    }) => &proj.self_type_parameter(&Interner) == self,
+                                    }) => proj.self_type_parameter(&Interner) == self,
                                     _ => false,
                                 })
                                 .collect::<Vec<_>>();
@@ -745,7 +745,7 @@ fn write_bounds_like_dyn_trait(
                 // existential) here, which is the only thing that's
                 // possible in actual Rust, and hence don't print it
                 write!(f, "{}", f.db.trait_data(trait_).name)?;
-                if let [_, params @ ..] = &*trait_ref.substitution.interned().as_slice() {
+                if let [_, params @ ..] = &*trait_ref.substitution.interned() {
                     if is_fn_trait {
                         if let Some(args) =
                             params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
@@ -792,29 +792,31 @@ fn write_bounds_like_dyn_trait(
     Ok(())
 }
 
-fn fmt_trait_ref(tr: &TraitRef, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
-    if f.should_truncate() {
-        return write!(f, "{}", TYPE_HINT_TRUNCATION);
-    }
+impl TraitRef {
+    fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
+        if f.should_truncate() {
+            return write!(f, "{}", TYPE_HINT_TRUNCATION);
+        }
 
-    tr.self_type_parameter(&Interner).hir_fmt(f)?;
-    if use_as {
-        write!(f, " as ")?;
-    } else {
-        write!(f, ": ")?;
-    }
-    write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
-    if tr.substitution.len(&Interner) > 1 {
-        write!(f, "<")?;
-        f.write_joined(&tr.substitution.interned()[1..], ", ")?;
-        write!(f, ">")?;
+        self.self_type_parameter(&Interner).hir_fmt(f)?;
+        if use_as {
+            write!(f, " as ")?;
+        } else {
+            write!(f, ": ")?;
+        }
+        write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
+        if self.substitution.len(&Interner) > 1 {
+            write!(f, "<")?;
+            f.write_joined(&self.substitution.interned()[1..], ", ")?;
+            write!(f, ">")?;
+        }
+        Ok(())
     }
-    Ok(())
 }
 
 impl HirDisplay for TraitRef {
     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        fmt_trait_ref(self, f, false)
+        self.hir_fmt_ext(f, false)
     }
 }
 
@@ -828,7 +830,7 @@ impl HirDisplay for WhereClause {
             WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
             WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
                 write!(f, "<")?;
-                fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?;
+                projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
                 write!(
                     f,
                     ">::{} = ",
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 531159e542..6af0c59b8d 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -336,7 +336,7 @@ impl<'a> InferenceContext<'a> {
         self.last_obligations_check = Some(self.table.revision);
         let obligations = mem::replace(&mut self.obligations, Vec::new());
         for obligation in obligations {
-            let in_env = InEnvironment::new(&self.trait_env.env, obligation.clone());
+            let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone());
             let canonicalized = self.canonicalizer().canonicalize_obligation(in_env);
             let solution =
                 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone());
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index fd679f4446..f1af2a0bdc 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -139,7 +139,7 @@ impl<'a> InferenceContext<'a> {
             b.push(from_ty.clone()).push(to_ty.clone()).build()
         };
 
-        let goal = InEnvironment::new(&self.trait_env.env, trait_ref.cast(&Interner));
+        let goal = InEnvironment::new(self.trait_env.env.clone(), trait_ref.cast(&Interner));
 
         let canonicalizer = self.canonicalizer();
         let canonicalized = canonicalizer.canonicalize_obligation(goal);
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index a41e8e1166..f88d5c5d34 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -122,7 +122,7 @@ impl<'a> InferenceContext<'a> {
         let ty = match &body[pat] {
             &Pat::Tuple { ref args, ellipsis } => {
                 let expectations = match expected.as_tuple() {
-                    Some(parameters) => &*parameters.interned().as_slice(),
+                    Some(parameters) => &*parameters.interned(),
                     _ => &[],
                 };
 
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index f8955aa324..b19d67bb1f 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -11,8 +11,7 @@ use hir_def::{
 use hir_expand::name::Name;
 
 use crate::{
-    method_resolution, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
-    ValueTyDefId,
+    method_resolution, Interner, Substitution, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
 };
 
 use super::{ExprOrPatId, InferenceContext, TraitRef};
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 2ea9dd9209..d717e33759 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -8,8 +8,7 @@ use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
 use super::{DomainGoal, InferenceContext};
 use crate::{
     AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSubst,
-    InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyExt, TyKind, TypeWalk,
-    WhereClause,
+    InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyKind, TypeWalk, WhereClause,
 };
 
 impl<'a> InferenceContext<'a> {
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 87f10e9d5a..84645c4355 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -41,7 +41,7 @@ use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
 
 pub use autoderef::autoderef;
 pub use builder::TyBuilder;
-pub use chalk_ext::*;
+pub use chalk_ext::{ProjectionTyExt, TyExt};
 pub use infer::{could_unify, InferenceResult};
 pub use lower::{
     associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
@@ -107,18 +107,22 @@ pub fn make_only_type_binders<T>(num_vars: usize, value: T) -> Binders<T> {
     )
 }
 
-// FIXME: get rid of this
-pub fn make_canonical<T>(
-    value: T,
-    kinds: impl IntoIterator<Item = TyVariableKind>,
-) -> Canonical<T> {
-    let kinds = kinds.into_iter().map(|tk| {
-        chalk_ir::CanonicalVarKind::new(
-            chalk_ir::VariableKind::Ty(tk),
-            chalk_ir::UniverseIndex::ROOT,
-        )
-    });
-    Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
+impl TraitRef {
+    pub fn hir_trait_id(&self) -> TraitId {
+        from_chalk_trait_id(self.trait_id)
+    }
+}
+
+impl<T> Canonical<T> {
+    pub fn new(value: T, kinds: impl IntoIterator<Item = TyVariableKind>) -> Self {
+        let kinds = kinds.into_iter().map(|tk| {
+            chalk_ir::CanonicalVarKind::new(
+                chalk_ir::VariableKind::Ty(tk),
+                chalk_ir::UniverseIndex::ROOT,
+            )
+        });
+        Self { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
+    }
 }
 
 /// A function signature as seen by type inference: Several parameter types and
@@ -164,7 +168,37 @@ impl CallableSig {
     }
 }
 
-impl Ty {}
+impl Ty {
+    pub fn equals_ctor(&self, other: &Ty) -> bool {
+        match (self.kind(&Interner), other.kind(&Interner)) {
+            (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
+            (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => {
+                true
+            }
+            (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
+            (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
+            (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => {
+                ty_id == ty_id2
+            }
+            (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2,
+            (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2,
+            (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..))
+            | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => {
+                mutability == mutability2
+            }
+            (
+                TyKind::Function(FnPointer { num_binders, sig, .. }),
+                TyKind::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }),
+            ) => num_binders == num_binders2 && sig == sig2,
+            (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => {
+                cardinality == cardinality2
+            }
+            (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true,
+            (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2,
+            _ => false,
+        }
+    }
+}
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 pub enum ImplTraitId {
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index e6903e189e..4ca6aa5385 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -35,7 +35,7 @@ use crate::{
     AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
     FnSubst, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
     QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
-    TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, TypeWalk, WhereClause,
+    TraitEnvironment, TraitRef, Ty, TyBuilder, TyKind, TypeWalk, WhereClause,
 };
 
 #[derive(Debug)]
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 7e09a1539d..c601f2d539 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -22,8 +22,8 @@ use crate::{
     static_lifetime,
     utils::all_super_traits,
     AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId,
-    InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder,
-    TyExt, TyKind, TypeWalk,
+    InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
+    TypeWalk,
 };
 
 /// This is used as a key for indexing impls.
@@ -845,7 +845,7 @@ fn generic_implements_goal(
     let obligation = trait_ref.cast(&Interner);
     Canonical {
         binders: CanonicalVarKinds::from_iter(&Interner, kinds),
-        value: InEnvironment::new(&env.env, obligation),
+        value: InEnvironment::new(env.env.clone(), obligation),
     }
 }
 
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index 7d87741b8e..3374532c34 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -9,7 +9,7 @@ use stdx::panic_context;
 
 use crate::{
     db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment,
-    Solution, TraitRefExt, Ty, TyKind, WhereClause,
+    Solution, Ty, TyKind, WhereClause,
 };
 
 use self::chalk::{from_chalk, Interner, ToChalk};
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index 090f6492b4..f03b92422f 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -22,7 +22,7 @@ use crate::{
     to_assoc_type_id, to_chalk_trait_id,
     utils::generics,
     AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution,
-    TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
+    TraitRef, Ty, TyBuilder, TyExt, TyKind, WhereClause,
 };
 use mapping::{
     convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index 701359e6f5..84abd99b29 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -10,9 +10,9 @@ use base_db::salsa::InternKey;
 use hir_def::{GenericDefId, TypeAliasId};
 
 use crate::{
-    db::HirDatabase, static_lifetime, AliasTy, CallableDefId, Canonical, ConstrainedSubst,
-    DomainGoal, FnPointer, GenericArg, InEnvironment, OpaqueTy, ProjectionTy, ProjectionTyExt,
-    QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
+    chalk_ext::ProjectionTyExt, db::HirDatabase, static_lifetime, AliasTy, CallableDefId,
+    Canonical, ConstrainedSubst, DomainGoal, FnPointer, GenericArg, InEnvironment, OpaqueTy,
+    ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
 };
 
 use super::interner::*;
@@ -509,7 +509,7 @@ pub(super) fn generic_predicate_to_inline_bound(
     let (pred, binders) = pred.as_ref().into_value_and_skipped_binders();
     match pred {
         WhereClause::Implemented(trait_ref) => {
-            if trait_ref.self_type_parameter(&Interner) != self_ty_shifted_in {
+            if trait_ref.self_type_parameter(&Interner) != &self_ty_shifted_in {
                 // we can only convert predicates back to type bounds if they
                 // have the expected self type
                 return None;
@@ -522,7 +522,7 @@ pub(super) fn generic_predicate_to_inline_bound(
             Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
         }
         WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
-            if projection_ty.self_type_parameter(&Interner) != self_ty_shifted_in {
+            if projection_ty.self_type_parameter(&Interner) != &self_ty_shifted_in {
                 return None;
             }
             let trait_ = projection_ty.trait_(db);
diff --git a/crates/hir_ty/src/types.rs b/crates/hir_ty/src/types.rs
index 89adad1084..c25bc2d6ab 100644
--- a/crates/hir_ty/src/types.rs
+++ b/crates/hir_ty/src/types.rs
@@ -30,8 +30,8 @@ pub struct ProjectionTy {
 }
 
 impl ProjectionTy {
-    pub fn self_type_parameter(&self, interner: &Interner) -> Ty {
-        self.substitution.interned()[0].assert_ty_ref(interner).clone()
+    pub fn self_type_parameter(&self, interner: &Interner) -> &Ty {
+        &self.substitution.interned()[0].assert_ty_ref(interner)
     }
 }
 
@@ -282,7 +282,7 @@ impl GenericArg {
 pub struct Substitution(SmallVec<[GenericArg; 2]>);
 
 impl Substitution {
-    pub fn interned(&self) -> &SmallVec<[GenericArg; 2]> {
+    pub fn interned(&self) -> &[GenericArg] {
         &self.0
     }
 
@@ -413,8 +413,8 @@ pub struct TraitRef {
 }
 
 impl TraitRef {
-    pub fn self_type_parameter(&self, interner: &Interner) -> Ty {
-        self.substitution.at(interner, 0).assert_ty_ref(interner).clone()
+    pub fn self_type_parameter(&self, interner: &Interner) -> &Ty {
+        &self.substitution.at(interner, 0).assert_ty_ref(interner)
     }
 }
 
@@ -470,8 +470,8 @@ pub struct InEnvironment<T> {
 }
 
 impl<T> InEnvironment<T> {
-    pub fn new(environment: &chalk_ir::Environment<Interner>, value: T) -> InEnvironment<T> {
-        InEnvironment { environment: environment.clone(), goal: value }
+    pub fn new(environment: chalk_ir::Environment<Interner>, value: T) -> InEnvironment<T> {
+        InEnvironment { environment, goal: value }
     }
 }
 
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 8d5d5cd733..0a424f607d 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -16,9 +16,7 @@ use hir_def::{
 };
 use hir_expand::name::{name, Name};
 
-use crate::{
-    db::HirDatabase, Interner, Substitution, TraitRef, TraitRefExt, TyKind, TypeWalk, WhereClause,
-};
+use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TyKind, TypeWalk, WhereClause};
 
 fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
     let resolver = trait_.resolver(db);
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index d5628e3df1..be0ee03bf8 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -1,3 +1,5 @@
+use std::iter;
+
 use hir::Semantics;
 use ide_db::RootDatabase;
 use syntax::{
@@ -91,27 +93,42 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
         let is_last =
             |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };
 
-        res += &match token.kind() {
-            k if is_text(k) && is_next(|it| !it.is_punct(), true) => token.text().to_string() + " ",
+        match token.kind() {
+            k if is_text(k) && is_next(|it| !it.is_punct(), true) => {
+                res.push_str(token.text());
+                res.push(' ');
+            }
             L_CURLY if is_next(|it| it != R_CURLY, true) => {
                 indent += 1;
-                let leading_space = if is_last(is_text, false) { " " } else { "" };
-                format!("{}{{\n{}", leading_space, "  ".repeat(indent))
+                if is_last(is_text, false) {
+                    res.push(' ');
+                }
+                res.push_str("{\n");
+                res.extend(iter::repeat(" ").take(2 * indent));
             }
             R_CURLY if is_last(|it| it != L_CURLY, true) => {
                 indent = indent.saturating_sub(1);
-                format!("\n{}}}", "  ".repeat(indent))
+                res.push('\n');
+                res.extend(iter::repeat(" ").take(2 * indent));
+                res.push_str("}");
+            }
+            R_CURLY => {
+                res.push_str("}\n");
+                res.extend(iter::repeat(" ").take(2 * indent));
             }
-            R_CURLY => format!("}}\n{}", "  ".repeat(indent)),
             LIFETIME_IDENT if is_next(|it| it == IDENT, true) => {
-                format!("{} ", token.text().to_string())
+                res.push_str(token.text());
+                res.push(' ');
             }
-            T![;] => format!(";\n{}", "  ".repeat(indent)),
-            T![->] => " -> ".to_string(),
-            T![=] => " = ".to_string(),
-            T![=>] => " => ".to_string(),
-            _ => token.text().to_string(),
-        };
+            T![;] => {
+                res.push_str(";\n");
+                res.extend(iter::repeat(" ").take(2 * indent));
+            }
+            T![->] => res.push_str(" -> "),
+            T![=] => res.push_str(" = "),
+            T![=>] => res.push_str(" => "),
+            _ => res.push_str(token.text()),
+        }
 
         last = Some(token.kind());
     }
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 2b9ed123c1..153726ce8b 100644
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -19,7 +19,6 @@ pub enum FoldKind {
     Region,
     Consts,
     Statics,
-    Array,
 }
 
 #[derive(Debug)]
@@ -120,7 +119,6 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
     match kind {
         COMMENT => Some(FoldKind::Comment),
         ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
-        ARRAY_EXPR => Some(FoldKind::Array),
         ASSOC_ITEM_LIST
         | RECORD_FIELD_LIST
         | RECORD_PAT_FIELD_LIST
@@ -271,7 +269,6 @@ mod tests {
                 FoldKind::Region => "region",
                 FoldKind::Consts => "consts",
                 FoldKind::Statics => "statics",
-                FoldKind::Array => "array",
             };
             assert_eq!(kind, &attr.unwrap());
         }
@@ -467,20 +464,6 @@ fn foo<fold arglist>(
         )
     }
 
-    #[test]
-    fn fold_multiline_array() {
-        check(
-            r#"
-const FOO: [usize; 4] = <fold array>[
-    1,
-    2,
-    3,
-    4,
-]</fold>;
-"#,
-        )
-    }
-
     #[test]
     fn fold_region() {
         check(
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index 1378048e51..11408d445a 100644
--- a/crates/ide/src/typing.rs
+++ b/crates/ide/src/typing.rs
@@ -22,19 +22,18 @@ use ide_db::{
 use syntax::{
     algo::find_node_at_offset,
     ast::{self, edit::IndentLevel, AstToken},
-    AstNode, Parse, SourceFile,
+    AstNode, SourceFile,
     SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR},
     TextRange, TextSize,
 };
 
-use text_edit::{Indel, TextEdit};
+use text_edit::TextEdit;
 
 use crate::SourceChange;
 
 pub(crate) use on_enter::on_enter;
 
-// Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
-pub(crate) const TRIGGER_CHARS: &str = ".=>{";
+pub(crate) const TRIGGER_CHARS: &str = ".=>";
 
 // Feature: On Typing Assists
 //
@@ -42,7 +41,6 @@ pub(crate) const TRIGGER_CHARS: &str = ".=>{";
 //
 // - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression
 // - typing `.` in a chain method call auto-indents
-// - typing `{` in front of an expression inserts a closing `}` after the expression
 //
 // VS Code::
 //
@@ -59,79 +57,28 @@ pub(crate) fn on_char_typed(
     position: FilePosition,
     char_typed: char,
 ) -> Option<SourceChange> {
-    if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
-        return None;
-    }
-    let file = &db.parse(position.file_id);
-    if !stdx::always!(file.tree().syntax().text().char_at(position.offset) == Some(char_typed)) {
-        return None;
-    }
+    assert!(TRIGGER_CHARS.contains(char_typed));
+    let file = &db.parse(position.file_id).tree();
+    assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed));
     let edit = on_char_typed_inner(file, position.offset, char_typed)?;
     Some(SourceChange::from_text_edit(position.file_id, edit))
 }
 
-fn on_char_typed_inner(
-    file: &Parse<SourceFile>,
-    offset: TextSize,
-    char_typed: char,
-) -> Option<TextEdit> {
-    if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
-        return None;
-    }
+fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> {
+    assert!(TRIGGER_CHARS.contains(char_typed));
     match char_typed {
-        '.' => on_dot_typed(&file.tree(), offset),
-        '=' => on_eq_typed(&file.tree(), offset),
-        '>' => on_arrow_typed(&file.tree(), offset),
-        '{' => on_opening_brace_typed(file, offset),
+        '.' => on_dot_typed(file, offset),
+        '=' => on_eq_typed(file, offset),
+        '>' => on_arrow_typed(file, offset),
         _ => unreachable!(),
     }
 }
 
-/// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a
-/// block.
-fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<TextEdit> {
-    if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some('{')) {
-        return None;
-    }
-
-    let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?;
-
-    // Remove the `{` to get a better parse tree, and reparse
-    let file = file.reparse(&Indel::delete(brace_token.text_range()));
-
-    let mut expr: ast::Expr = find_node_at_offset(file.tree().syntax(), offset)?;
-    if expr.syntax().text_range().start() != offset {
-        return None;
-    }
-
-    // Enclose the outermost expression starting at `offset`
-    while let Some(parent) = expr.syntax().parent() {
-        if parent.text_range().start() != expr.syntax().text_range().start() {
-            break;
-        }
-
-        match ast::Expr::cast(parent) {
-            Some(parent) => expr = parent,
-            None => break,
-        }
-    }
-
-    // If it's a statement in a block, we don't know how many statements should be included
-    if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) {
-        return None;
-    }
-
-    // Insert `}` right after the expression.
-    Some(TextEdit::insert(expr.syntax().text_range().end() + TextSize::of("{"), "}".to_string()))
-}
-
 /// Returns an edit which should be applied after `=` was typed. Primarily,
 /// this works when adding `let =`.
 // FIXME: use a snippet completion instead of this hack here.
 fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
-    if !stdx::always!(file.syntax().text().char_at(offset) == Some('=')) {
-        return None;
-    }
+    assert_eq!(file.syntax().text().char_at(offset), Some('='));
     let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
     if let_stmt.semicolon_token().is_some() {
         return None;
@@ -153,9 +100,7 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
 
 /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately.
 fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
-    if !stdx::always!(file.syntax().text().char_at(offset) == Some('.')) {
-        return None;
-    }
+    assert_eq!(file.syntax().text().char_at(offset), Some('.'));
     let whitespace =
         file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?;
 
@@ -184,9 +129,7 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
 /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }`
 fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
     let file_text = file.syntax().text();
-    if !stdx::always!(file_text.char_at(offset) == Some('>')) {
-        return None;
-    }
+    assert_eq!(file_text.char_at(offset), Some('>'));
     let after_arrow = offset + TextSize::of('>');
     if file_text.char_at(after_arrow) != Some('{') {
         return None;
@@ -209,7 +152,7 @@ mod tests {
         let edit = TextEdit::insert(offset, char_typed.to_string());
         edit.apply(&mut before);
         let parse = SourceFile::parse(&before);
-        on_char_typed_inner(&parse, offset, char_typed).map(|it| {
+        on_char_typed_inner(&parse.tree(), offset, char_typed).map(|it| {
             it.apply(&mut before);
             before.to_string()
         })
@@ -430,85 +373,4 @@ fn main() {
     fn adds_space_after_return_type() {
         type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }")
     }
-
-    #[test]
-    fn adds_closing_brace() {
-        type_char(
-            '{',
-            r#"
-fn f() { match () { _ => $0() } }
-            "#,
-            r#"
-fn f() { match () { _ => {()} } }
-            "#,
-        );
-        type_char(
-            '{',
-            r#"
-fn f() { $0() }
-            "#,
-            r#"
-fn f() { {()} }
-            "#,
-        );
-        type_char(
-            '{',
-            r#"
-fn f() { let x = $0(); }
-            "#,
-            r#"
-fn f() { let x = {()}; }
-            "#,
-        );
-        type_char(
-            '{',
-            r#"
-fn f() { let x = $0a.b(); }
-            "#,
-            r#"
-fn f() { let x = {a.b()}; }
-            "#,
-        );
-        type_char(
-            '{',
-            r#"
-const S: () = $0();
-fn f() {}
-            "#,
-            r#"
-const S: () = {()};
-fn f() {}
-            "#,
-        );
-        type_char(
-            '{',
-            r#"
-const S: () = $0a.b();
-fn f() {}
-            "#,
-            r#"
-const S: () = {a.b()};
-fn f() {}
-            "#,
-        );
-        type_char(
-            '{',
-            r#"
-fn f() {
-    match x {
-        0 => $0(),
-        1 => (),
-    }
-}
-            "#,
-            r#"
-fn f() {
-    match x {
-        0 => {()},
-        1 => (),
-    }
-}
-            "#,
-        );
-    }
 }
diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs
index 2862cfa9c2..6114091f24 100644
--- a/crates/ide_assists/src/handlers/remove_dbg.rs
+++ b/crates/ide_assists/src/handlers/remove_dbg.rs
@@ -1,5 +1,5 @@
 use syntax::{
-    ast::{self, AstNode, AstToken},
+    ast::{self, AstNode},
     match_ast, SyntaxElement, TextRange, TextSize, T,
 };
 
@@ -24,39 +24,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
     let new_contents = adjusted_macro_contents(&macro_call)?;
 
-    let parent = macro_call.syntax().parent();
-
-    let macro_text_range = if let Some(it) = parent.as_ref() {
-        if new_contents.is_empty() {
-            match_ast! {
-                match it {
-                    ast::BlockExpr(it) => {
-                        macro_call.syntax()
-                            .prev_sibling_or_token()
-                            .and_then(whitespace_start)
-                            .map(|start| TextRange::new(start, macro_call.syntax().text_range().end()))
-                            .unwrap_or(macro_call.syntax().text_range())
-                    },
-                    ast::ExprStmt(it) => {
-                        let start = it
-                            .syntax()
-                            .prev_sibling_or_token()
-                            .and_then(whitespace_start)
-                            .unwrap_or(it.syntax().text_range().start());
-                        let end = it.syntax().text_range().end();
-
-                        TextRange::new(start, end)
-                    },
-                    _ => macro_call.syntax().text_range()
-                }
-            }
-        } else {
-            macro_call.syntax().text_range()
-        }
-    } else {
-        macro_call.syntax().text_range()
-    };
-
+    let macro_text_range = macro_call.syntax().text_range();
     let macro_end = if macro_call.semicolon_token().is_some() {
         macro_text_range.end() - TextSize::of(';')
     } else {
@@ -68,22 +36,11 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
         "Remove dbg!()",
         macro_text_range,
         |builder| {
-            builder.replace(
-                TextRange::new(macro_text_range.start(), macro_end),
-                if new_contents.is_empty() && parent.and_then(ast::LetStmt::cast).is_some() {
-                    ast::make::expr_unit().to_string()
-                } else {
-                    new_contents
-                },
-            );
+            builder.replace(TextRange::new(macro_text_range.start(), macro_end), new_contents);
         },
     )
 }
 
-fn whitespace_start(it: SyntaxElement) -> Option<TextSize> {
-    Some(it.into_token().and_then(ast::Whitespace::cast)?.syntax().text_range().start())
-}
-
 fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> {
     let contents = get_valid_macrocall_contents(&macro_call, "dbg")?;
     let macro_text_with_brackets = macro_call.token_tree()?.syntax().text();
@@ -137,11 +94,15 @@ fn get_valid_macrocall_contents(
     let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>();
     let last_child = contents_between_brackets.pop()?;
 
-    match (first_child.kind(), last_child.kind()) {
-        (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
-            Some(contents_between_brackets)
+    if contents_between_brackets.is_empty() {
+        None
+    } else {
+        match (first_child.kind(), last_child.kind()) {
+            (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
+                Some(contents_between_brackets)
+            }
+            _ => None,
         }
-        _ => None,
     }
 }
 
@@ -454,50 +415,6 @@ fn main() {
 }"#,
             r#"fn foo() {
     match &x {}
-}"#,
-        );
-    }
-
-    #[test]
-    fn test_remove_empty_dbg() {
-        check_assist(remove_dbg, r#"fn foo() { $0dbg!(); }"#, r#"fn foo() { }"#);
-        check_assist(
-            remove_dbg,
-            r#"
-fn foo() {
-    $0dbg!();
-}
-"#,
-            r#"
-fn foo() {
-}
-"#,
-        );
-        check_assist(
-            remove_dbg,
-            r#"
-fn foo() {
-    let test = $0dbg!();
-}"#,
-            r#"
-fn foo() {
-    let test = ();
-}"#,
-        );
-        check_assist(
-            remove_dbg,
-            r#"
-fn foo() {
-    let t = {
-        println!("Hello, world");
-        $0dbg!()
-    };
-}"#,
-            r#"
-fn foo() {
-    let t = {
-        println!("Hello, world");
-    };
 }"#,
         );
     }
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index 3c87782f28..7a5bcb8c7f 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -57,7 +57,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
         document_range_formatting_provider: None,
         document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
             first_trigger_character: "=".to_string(),
-            more_trigger_character: Some(vec![".".to_string(), ">".to_string(), "{".to_string()]),
+            more_trigger_character: Some(vec![".".to_string(), ">".to_string()]),
         }),
         selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
         folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 31d8c487be..4d10a2eadc 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -231,6 +231,7 @@ pub(crate) fn handle_on_enter(
     Ok(Some(edit))
 }
 
+// Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`.
 pub(crate) fn handle_on_type_formatting(
     snap: GlobalStateSnapshot,
     params: lsp_types::DocumentOnTypeFormattingParams,
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 2ac31d981b..c3820944bc 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -497,8 +497,7 @@ pub(crate) fn folding_range(
         | FoldKind::Block
         | FoldKind::ArgList
         | FoldKind::Consts
-        | FoldKind::Statics
-        | FoldKind::Array => None,
+        | FoldKind::Statics => None,
     };
 
     let range = range(line_index, fold.range);


Test patch:
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index c1d3e998f3..faa1332970 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -143,7 +143,7 @@ fn f() {
   //^^^^^^^^^^^^^ could not convert tokens
 
     env!("OUT_DIR");
-  //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
+  //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix
 
     compile_error!("compile_error works");
   //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index 1ac88fc892..fefdadb225 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -233,7 +233,7 @@ fn good_out_dir_diagnostic() {
         macro_rules! concat { () => {} }
 
         include!(concat!(env!("OUT_DIR"), "/out.rs"));
-      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
+      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix
         "#,
     );
 }