Repository: rust-lang/rust-analyzer
Pull request #12005 (2022-04-15 19:45:32)

internal: Remove frequent `Arc<Body>` clones in type checking
bors r+


Patch:
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 8b565ef1fa..246b93723b 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -208,16 +208,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.descend_into_macros(token)
     }
 
-    /// Descend the token into macrocalls to all its mapped counterparts.
-    ///
-    /// Returns the original non descended token if none of the mapped counterparts have the same syntax kind.
-    pub fn descend_into_macros_with_same_kind(
-        &self,
-        token: SyntaxToken,
-    ) -> SmallVec<[SyntaxToken; 1]> {
-        self.imp.descend_into_macros_with_same_kind(token)
-    }
-
     /// Maps a node down by mapping its first and last token down.
     pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
         self.imp.descend_node_into_attributes(node)
@@ -609,19 +599,25 @@ impl<'db> SemanticsImpl<'db> {
         };
 
         if first == last {
-            self.descend_into_macros_impl(first, &mut |InFile { value, .. }| {
-                if let Some(node) = value.ancestors().find_map(N::cast) {
-                    res.push(node)
-                }
-                false
-            });
+            self.descend_into_macros_impl(
+                first,
+                &mut |InFile { value, .. }| {
+                    if let Some(node) = value.ancestors().find_map(N::cast) {
+                        res.push(node)
+                    }
+                },
+                false,
+            );
         } else {
             // Descend first and last token, then zip them to look for the node they belong to
             let mut scratch: SmallVec<[_; 1]> = smallvec![];
-            self.descend_into_macros_impl(first, &mut |token| {
-                scratch.push(token);
-                false
-            });
+            self.descend_into_macros_impl(
+                first,
+                &mut |token| {
+                    scratch.push(token);
+                },
+                false,
+            );
 
             let mut scratch = scratch.into_iter();
             self.descend_into_macros_impl(
@@ -642,8 +638,8 @@ impl<'db> SemanticsImpl<'db> {
                             }
                         }
                     }
-                    false
                 },
+                false,
             );
         }
         res
@@ -651,41 +647,21 @@ impl<'db> SemanticsImpl<'db> {
 
     fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
         let mut res = smallvec![];
-        self.descend_into_macros_impl(token, &mut |InFile { value, .. }| {
-            res.push(value);
-            false
-        });
-        res
-    }
-
-    fn descend_into_macros_with_same_kind(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
-        let kind = token.kind();
-        let mut res = smallvec![];
-        self.descend_into_macros_impl(token.clone(), &mut |InFile { value, .. }| {
-            if value.kind() == kind {
-                res.push(value);
-            }
-            false
-        });
-        if res.is_empty() {
-            res.push(token);
-        }
+        self.descend_into_macros_impl(token, &mut |InFile { value, .. }| res.push(value), false);
         res
     }
 
     fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
         let mut res = token.clone();
-        self.descend_into_macros_impl(token, &mut |InFile { value, .. }| {
-            res = value;
-            true
-        });
+        self.descend_into_macros_impl(token, &mut |InFile { value, .. }| res = value, true);
         res
     }
 
     fn descend_into_macros_impl(
         &self,
         token: SyntaxToken,
-        f: &mut dyn FnMut(InFile<SyntaxToken>) -> bool,
+        f: &mut dyn FnMut(InFile<SyntaxToken>),
+        single: bool,
     ) {
         let _p = profile::span("descend_into_macros");
         let parent = match token.parent() {
@@ -712,11 +688,16 @@ impl<'db> SemanticsImpl<'db> {
                     self.cache(value, file_id);
                 }
 
-                let mapped_tokens = expansion_info.map_token_down(self.db.upcast(), item, token)?;
-                let len = stack.len();
+                let mut mapped_tokens =
+                    expansion_info.map_token_down(self.db.upcast(), item, token)?;
 
+                let len = stack.len();
                 // requeue the tokens we got from mapping our current token down
-                stack.extend(mapped_tokens);
+                if single {
+                    stack.extend(mapped_tokens.next());
+                } else {
+                    stack.extend(mapped_tokens);
+                }
                 // if the length changed we have found a mapping for the token
                 (stack.len() != len).then(|| ())
             };
@@ -806,8 +787,8 @@ impl<'db> SemanticsImpl<'db> {
             })()
             .is_none();
 
-            if was_not_remapped && f(token) {
-                break;
+            if was_not_remapped {
+                f(token)
             }
         }
     }
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index eca6b3a076..1892e30a42 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -59,7 +59,8 @@ mod closure;
 pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
     let _p = profile::span("infer_query");
     let resolver = def.resolver(db.upcast());
-    let mut ctx = InferenceContext::new(db, def, resolver);
+    let body = db.body(def);
+    let mut ctx = InferenceContext::new(db, def, &body, resolver);
 
     match def {
         DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
@@ -360,7 +361,7 @@ impl Index<PatId> for InferenceResult {
 pub(crate) struct InferenceContext<'a> {
     pub(crate) db: &'a dyn HirDatabase,
     pub(crate) owner: DefWithBodyId,
-    pub(crate) body: Arc<Body>,
+    pub(crate) body: &'a Body,
     pub(crate) resolver: Resolver,
     table: unify::InferenceTable<'a>,
     trait_env: Arc<TraitEnvironment>,
@@ -394,7 +395,12 @@ fn find_breakable<'c>(
 }
 
 impl<'a> InferenceContext<'a> {
-    fn new(db: &'a dyn HirDatabase, owner: DefWithBodyId, resolver: Resolver) -> Self {
+    fn new(
+        db: &'a dyn HirDatabase,
+        owner: DefWithBodyId,
+        body: &'a Body,
+        resolver: Resolver,
+    ) -> Self {
         let krate = owner.module(db.upcast()).krate();
         let trait_env = owner
             .as_generic_def_id()
@@ -406,46 +412,76 @@ impl<'a> InferenceContext<'a> {
             return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
             db,
             owner,
-            body: db.body(owner),
+            body,
             resolver,
             diverges: Diverges::Maybe,
             breakables: Vec::new(),
         }
     }
 
-    fn err_ty(&self) -> Ty {
-        self.result.standard_types.unknown.clone()
-    }
+    fn resolve_all(self) -> InferenceResult {
+        let InferenceContext { mut table, mut result, .. } = self;
 
-    fn resolve_all(mut self) -> InferenceResult {
         // FIXME resolve obligations as well (use Guidance if necessary)
-        self.table.resolve_obligations_as_possible();
+        table.resolve_obligations_as_possible();
 
         // make sure diverging type variables are marked as such
-        self.table.propagate_diverging_flag();
-        let mut result = std::mem::take(&mut self.result);
+        table.propagate_diverging_flag();
         for ty in result.type_of_expr.values_mut() {
-            *ty = self.table.resolve_completely(ty.clone());
+            *ty = table.resolve_completely(ty.clone());
         }
         for ty in result.type_of_pat.values_mut() {
-            *ty = self.table.resolve_completely(ty.clone());
+            *ty = table.resolve_completely(ty.clone());
         }
         for mismatch in result.type_mismatches.values_mut() {
-            mismatch.expected = self.table.resolve_completely(mismatch.expected.clone());
-            mismatch.actual = self.table.resolve_completely(mismatch.actual.clone());
+            mismatch.expected = table.resolve_completely(mismatch.expected.clone());
+            mismatch.actual = table.resolve_completely(mismatch.actual.clone());
         }
         for (_, subst) in result.method_resolutions.values_mut() {
-            *subst = self.table.resolve_completely(subst.clone());
+            *subst = table.resolve_completely(subst.clone());
         }
         for adjustment in result.expr_adjustments.values_mut().flatten() {
-            adjustment.target = self.table.resolve_completely(adjustment.target.clone());
+            adjustment.target = table.resolve_completely(adjustment.target.clone());
         }
         for adjustment in result.pat_adjustments.values_mut().flatten() {
-            adjustment.target = self.table.resolve_completely(adjustment.target.clone());
+            adjustment.target = table.resolve_completely(adjustment.target.clone());
         }
         result
     }
 
+    fn collect_const(&mut self, data: &ConstData) {
+        self.return_ty = self.make_ty(&data.type_ref);
+    }
+
+    fn collect_static(&mut self, data: &StaticData) {
+        self.return_ty = self.make_ty(&data.type_ref);
+    }
+
+    fn collect_fn(&mut self, data: &FunctionData) {
+        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
+            .with_impl_trait_mode(ImplTraitLoweringMode::Param);
+        let param_tys =
+            data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
+        for (ty, pat) in param_tys.into_iter().zip(self.body.params.iter()) {
+            let ty = self.insert_type_vars(ty);
+            let ty = self.normalize_associated_types_in(ty);
+
+            self.infer_pat(*pat, &ty, BindingMode::default());
+        }
+        let error_ty = &TypeRef::Error;
+        let return_ty = if data.has_async_kw() {
+            data.async_ret_type.as_deref().unwrap_or(error_ty)
+        } else {
+            &*data.ret_type
+        };
+        let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Disallowed); // FIXME implement RPIT
+        self.return_ty = return_ty;
+    }
+
+    fn infer_body(&mut self) {
+        self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone()));
+    }
+
     fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) {
         self.result.type_of_expr.insert(expr, ty);
     }
@@ -491,6 +527,10 @@ impl<'a> InferenceContext<'a> {
         self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
     }
 
+    fn err_ty(&self) -> Ty {
+        self.result.standard_types.unknown.clone()
+    }
+
     /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
     fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
         let data = c.data(Interner);
@@ -544,6 +584,16 @@ impl<'a> InferenceContext<'a> {
         self.table.unify(ty1, ty2)
     }
 
+    /// Recurses through the given type, normalizing associated types mentioned
+    /// in it by replacing them by type variables and registering obligations to
+    /// resolve later. This should be done once for every type we get from some
+    /// type annotation (e.g. from a let type annotation, field type or function
+    /// call). `make_ty` handles this already, but e.g. for field types we need
+    /// to do it as well.
+    fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
+        self.table.normalize_associated_types_in(ty)
+    }
+
     fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
         self.resolve_obligations_as_possible();
         self.table.resolve_ty_shallow(ty)
@@ -586,16 +636,6 @@ impl<'a> InferenceContext<'a> {
         }
     }
 
-    /// Recurses through the given type, normalizing associated types mentioned
-    /// in it by replacing them by type variables and registering obligations to
-    /// resolve later. This should be done once for every type we get from some
-    /// type annotation (e.g. from a let type annotation, field type or function
-    /// call). `make_ty` handles this already, but e.g. for field types we need
-    /// to do it as well.
-    fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
-        self.table.normalize_associated_types_in(ty)
-    }
-
     fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Option<VariantId>) {
         let path = match path {
             Some(path) => path,
@@ -727,40 +767,6 @@ impl<'a> InferenceContext<'a> {
         }
     }
 
-    fn collect_const(&mut self, data: &ConstData) {
-        self.return_ty = self.make_ty(&data.type_ref);
-    }
-
-    fn collect_static(&mut self, data: &StaticData) {
-        self.return_ty = self.make_ty(&data.type_ref);
-    }
-
-    fn collect_fn(&mut self, data: &FunctionData) {
-        let body = Arc::clone(&self.body); // avoid borrow checker problem
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
-            .with_impl_trait_mode(ImplTraitLoweringMode::Param);
-        let param_tys =
-            data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
-        for (ty, pat) in param_tys.into_iter().zip(body.params.iter()) {
-            let ty = self.insert_type_vars(ty);
-            let ty = self.normalize_associated_types_in(ty);
-
-            self.infer_pat(*pat, &ty, BindingMode::default());
-        }
-        let error_ty = &TypeRef::Error;
-        let return_ty = if data.has_async_kw() {
-            data.async_ret_type.as_deref().unwrap_or(error_ty)
-        } else {
-            &*data.ret_type
-        };
-        let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Disallowed); // FIXME implement RPIT
-        self.return_ty = return_ty;
-    }
-
-    fn infer_body(&mut self) {
-        self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone()));
-    }
-
     fn resolve_lang_item(&self, name: Name) -> Option<LangItemTarget> {
         let krate = self.resolver.krate();
         self.db.lang_item(krate, name.to_smol_str())
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 7426a22e6a..fef02e63b7 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -4,7 +4,6 @@ use std::{
     collections::hash_map::Entry,
     iter::{repeat, repeat_with},
     mem,
-    sync::Arc,
 };
 
 use chalk_ir::{
@@ -80,8 +79,7 @@ impl<'a> InferenceContext<'a> {
     fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
         self.db.unwind_if_cancelled();
 
-        let body = Arc::clone(&self.body); // avoid borrow checker problem
-        let ty = match &body[tgt_expr] {
+        let ty = match &self.body[tgt_expr] {
             Expr::Missing => self.err_ty(),
             &Expr::If { condition, then_branch, else_branch } => {
                 self.infer_expr(
@@ -560,17 +558,7 @@ impl<'a> InferenceContext<'a> {
                 }
                 .intern(Interner)
             }
-            Expr::Box { expr } => {
-                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
-                if let Some(box_) = self.resolve_boxed_box() {
-                    TyBuilder::adt(self.db, box_)
-                        .push(inner_ty)
-                        .fill_with_defaults(self.db, || self.table.new_type_var())
-                        .build()
-                } else {
-                    self.err_ty()
-                }
-            }
+            &Expr::Box { expr } => self.infer_expr_box(expr),
             Expr::UnaryOp { expr, op } => {
                 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
                 let inner_ty = self.resolve_ty_shallow(&inner_ty);
@@ -798,6 +786,18 @@ impl<'a> InferenceContext<'a> {
         ty
     }
 
+    fn infer_expr_box(&mut self, inner_expr: ExprId) -> chalk_ir::Ty<Interner> {
+        let inner_ty = self.infer_expr_inner(inner_expr, &Expectation::none());
+        if let Some(box_) = self.resolve_boxed_box() {
+            TyBuilder::adt(self.db, box_)
+                .push(inner_ty)
+                .fill_with_defaults(self.db, || self.table.new_type_var())
+                .build()
+        } else {
+            self.err_ty()
+        }
+    }
+
     fn infer_overloadable_binop(
         &mut self,
         lhs: ExprId,
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index 9821815ca3..600b82ca41 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -1,6 +1,6 @@
 //! Type inference for patterns.
 
-use std::{iter::repeat, sync::Arc};
+use std::iter::repeat;
 
 use chalk_ir::Mutability;
 use hir_def::{
@@ -100,10 +100,9 @@ impl<'a> InferenceContext<'a> {
         expected: &Ty,
         mut default_bm: BindingMode,
     ) -> Ty {
-        let body = Arc::clone(&self.body); // avoid borrow checker problem
         let mut expected = self.resolve_ty_shallow(expected);
 
-        if is_non_ref_pat(&body, pat) {
+        if is_non_ref_pat(&self.body, pat) {
             let mut pat_adjustments = Vec::new();
             while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
                 pat_adjustments.push(Adjustment {
@@ -122,7 +121,7 @@ impl<'a> InferenceContext<'a> {
                 pat_adjustments.shrink_to_fit();
                 self.result.pat_adjustments.insert(pat, pat_adjustments);
             }
-        } else if let Pat::Ref { .. } = &body[pat] {
+        } else if let Pat::Ref { .. } = &self.body[pat] {
             cov_mark::hit!(match_ergonomics_ref);
             // When you encounter a `&pat` pattern, reset to Move.
             // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
@@ -133,7 +132,7 @@ impl<'a> InferenceContext<'a> {
         let default_bm = default_bm;
         let expected = expected;
 
-        let ty = match &body[pat] {
+        let ty = match &self.body[pat] {
             Pat::Tuple { args, ellipsis } => {
                 let expectations = match expected.as_tuple() {
                     Some(parameters) => &*parameters.as_slice(Interner),
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index fe9c5bd785..73f736dffe 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -20,9 +20,7 @@ use rustc_hash::FxHashMap;
 use syntax::{
     algo::find_node_at_offset,
     ast::{self, HasName},
-    match_ast, AstNode,
-    SyntaxKind::*,
-    SyntaxNode, TextRange, TextSize, T,
+    match_ast, AstNode, SyntaxNode, TextRange, TextSize, T,
 };
 
 use crate::{FilePosition, NavigationTarget, TryToNav};
@@ -106,7 +104,7 @@ pub(crate) fn find_all_refs(
         }
         None => {
             let search = make_searcher(false);
-            Some(find_defs(sema, &syntax, position.offset)?.into_iter().map(search).collect())
+            Some(find_defs(sema, &syntax, position.offset).into_iter().map(search).collect())
         }
     }
 }
@@ -115,47 +113,31 @@ pub(crate) fn find_defs<'a>(
     sema: &'a Semantics<RootDatabase>,
     syntax: &SyntaxNode,
     offset: TextSize,
-) -> Option<impl Iterator<Item = Definition> + 'a> {
-    let token = syntax.token_at_offset(offset).find(|t| {
-        matches!(
-            t.kind(),
-            IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
-        )
-    });
-    token.map(|token| {
-        sema.descend_into_macros_with_same_kind(token)
-            .into_iter()
-            .filter_map(|it| ast::NameLike::cast(it.parent()?))
-            .filter_map(move |name_like| {
-                let def = match name_like {
-                    ast::NameLike::NameRef(name_ref) => {
-                        match NameRefClass::classify(sema, &name_ref)? {
-                            NameRefClass::Definition(def) => def,
-                            NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
-                                Definition::Local(local_ref)
-                            }
-                        }
-                    }
-                    ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
-                        NameClass::Definition(it) | NameClass::ConstReference(it) => it,
-                        NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
-                            Definition::Local(local_def)
-                        }
-                    },
-                    ast::NameLike::Lifetime(lifetime) => {
-                        NameRefClass::classify_lifetime(sema, &lifetime)
-                            .and_then(|class| match class {
-                                NameRefClass::Definition(it) => Some(it),
-                                _ => None,
-                            })
-                            .or_else(|| {
-                                NameClass::classify_lifetime(sema, &lifetime)
-                                    .and_then(NameClass::defined)
-                            })?
-                    }
-                };
-                Some(def)
-            })
+) -> impl Iterator<Item = Definition> + 'a {
+    sema.find_nodes_at_offset_with_descend(syntax, offset).filter_map(move |name_like| {
+        let def = match name_like {
+            ast::NameLike::NameRef(name_ref) => match NameRefClass::classify(sema, &name_ref)? {
+                NameRefClass::Definition(def) => def,
+                NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
+                    Definition::Local(local_ref)
+                }
+            },
+            ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
+                NameClass::Definition(it) | NameClass::ConstReference(it) => it,
+                NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
+                    Definition::Local(local_def)
+                }
+            },
+            ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
+                .and_then(|class| match class {
+                    NameRefClass::Definition(it) => Some(it),
+                    _ => None,
+                })
+                .or_else(|| {
+                    NameClass::classify_lifetime(sema, &lifetime).and_then(NameClass::defined)
+                })?,
+        };
+        Some(def)
     })
 }
 
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 88e17fadac..1c455c5f30 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -226,11 +226,7 @@ fn find_related_tests(
     search_scope: Option<SearchScope>,
     tests: &mut FxHashSet<Runnable>,
 ) {
-    // FIXME: why is this using references::find_defs, this should use ide_db::search
-    let defs = match references::find_defs(sema, syntax, position.offset) {
-        Some(defs) => defs,
-        None => return,
-    };
+    let defs = references::find_defs(sema, syntax, position.offset);
     for def in defs {
         let defs = def
             .usages(sema)
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 3fd0748172..866bba7d1b 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -98,7 +98,7 @@ fn punctuation(sema: &Semantics<RootDatabase>, token: SyntaxToken, kind: SyntaxK
             }
         }
         (T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.], _) => HlOperator::Other.into(),
-        (T![!], MACRO_CALL | MACRO_RULES) => HlPunct::MacroBang.into(),
+        (T![!], MACRO_CALL) => HlPunct::MacroBang.into(),
         (T![!], NEVER_TYPE) => HlTag::BuiltinType.into(),
         (T![!], PREFIX_EXPR) => HlOperator::Logical.into(),
         (T![*], PTR_TYPE) => HlTag::Keyword.into(),
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 9fc3e30199..8b47ef0283 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -180,7 +180,7 @@ impl GlobalState {
         // A file was added or deleted
         let mut has_structure_changes = false;
 
-        let (change, changed_files) = {
+        let change = {
             let mut change = Change::new();
             let (vfs, line_endings_map) = &mut *self.vfs.write();
             let changed_files = vfs.take_changes();
@@ -188,7 +188,17 @@ impl GlobalState {
                 return false;
             }
 
-            for file in &changed_files {
+            for file in changed_files {
+                if !file.is_created_or_deleted() {
+                    // FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/11357
+                    let crates = self.analysis_host.raw_database().relevant_crates(file.file_id);
+                    let crate_graph = self.analysis_host.raw_database().crate_graph();
+
+                    if crates.iter().any(|&krate| !crate_graph[krate].proc_macro.is_empty()) {
+                        self.proc_macro_changed = true;
+                    }
+                }
+
                 if let Some(path) = vfs.file_path(file.file_id).as_path() {
                     let path = path.to_path_buf();
                     if reload::should_refresh_for_change(&path, file.change_kind) {
@@ -202,11 +212,14 @@ impl GlobalState {
 
                 let text = if file.exists() {
                     let bytes = vfs.file_contents(file.file_id).to_vec();
-                    String::from_utf8(bytes).ok().and_then(|text| {
-                        let (text, line_endings) = LineEndings::normalize(text);
-                        line_endings_map.insert(file.file_id, line_endings);
-                        Some(Arc::new(text))
-                    })
+                    match String::from_utf8(bytes).ok() {
+                        Some(text) => {
+                            let (text, line_endings) = LineEndings::normalize(text);
+                            line_endings_map.insert(file.file_id, line_endings);
+                            Some(Arc::new(text))
+                        }
+                        None => None,
+                    }
                 } else {
                     None
                 };
@@ -216,19 +229,10 @@ impl GlobalState {
                 let roots = self.source_root_config.partition(vfs);
                 change.set_roots(roots);
             }
-            (change, changed_files)
+            change
         };
 
         self.analysis_host.apply_change(change);
-
-        let raw_database = &self.analysis_host.raw_database();
-        self.proc_macro_changed =
-            changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
-                let crates = raw_database.relevant_crates(file.file_id);
-                let crate_graph = raw_database.crate_graph();
-
-                crates.iter().any(|&krate| !crate_graph[krate].is_proc_macro)
-            });
         true
     }
 
diff --git a/editors/code/README.md b/editors/code/README.md
index a5593e1110..46c6f6f2aa 100644
--- a/editors/code/README.md
+++ b/editors/code/README.md
@@ -1,31 +1,34 @@
 # rust-analyzer
 
-This extension proves support for the [Rust programming language](https://www.rust-lang.org/).
+Provides support for rust-analyzer: novel LSP server for the Rust programming language.
+
+**Note** the extension may cause conflicts with the official Rust extension. It is recommended to disable the Rust extension when using the rust-analyzer extension.
 
 ## Features
 
-- [code completion] with [imports insertion]
-- go to [definition], [implementation], [type definition]
-- [find all references], [workspace symbol search], [symbol renaming]
+- [code completion], [imports insertion]
+- [go to definition], [implementation], [type definition]
+- [find all references], [workspace symbol search], [rename]
 - [types and documentation on hover]
-- [inlay hints] for types and parameter names
+- [inlay hints]
 - [semantic syntax highlighting]
-- a lot of [assists(code actions)]
+- a lot of [assist(code actions)]
 - apply suggestions from errors
 - ... and many more, checkout the [manual] to see them all
 
 [code completion]: https://rust-analyzer.github.io/manual.html#magic-completions
-[imports insertion]: https://rust-analyzer.github.io/manual.html#completion-with-autoimport
-[definition]: https://rust-analyzer.github.io/manual.html#go-to-definition
+[imports insertion]: https://rust-analyzer.github.io/manual.html#auto-import
+[go to definition]: https://rust-analyzer.github.io/manual.html#go-to-definition
 [implementation]: https://rust-analyzer.github.io/manual.html#go-to-implementation
 [type definition]: https://rust-analyzer.github.io/manual.html#go-to-type-definition
 [find all references]: https://rust-analyzer.github.io/manual.html#find-all-references
 [workspace symbol search]: https://rust-analyzer.github.io/manual.html#workspace-symbol
-[symbol renaming]: https://rust-analyzer.github.io/manual.html#rename
+[rename]: https://rust-analyzer.github.io/manual.html#rename
 [types and documentation on hover]: https://rust-analyzer.github.io/manual.html#hover
 [inlay hints]: https://rust-analyzer.github.io/manual.html#inlay-hints
 [semantic syntax highlighting]: https://rust-analyzer.github.io/manual.html#semantic-syntax-highlighting
-[assists(code actions)]: https://rust-analyzer.github.io/manual.html#assists-code-actions
+[assist(code actions)]: https://rust-analyzer.github.io/manual.html#assists-code-actions
+
 [manual]: https://rust-analyzer.github.io/manual.html
 
 ## Quick start
diff --git a/editors/code/package.json b/editors/code/package.json
index 60c827e31a..7860d18758 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -27,7 +27,7 @@
     "scripts": {
         "vscode:prepublish": "npm run build-base -- --minify",
         "package": "vsce package -o rust-analyzer.vsix",
-        "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16",
+        "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node14",
         "build": "npm run build-base -- --sourcemap",
         "watch": "npm run build-base -- --sourcemap --watch",
         "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src ./tests",
diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json
index e2ba2f231a..7c4fbd21eb 100644
--- a/editors/code/tsconfig.json
+++ b/editors/code/tsconfig.json
@@ -1,10 +1,10 @@
 {
     "compilerOptions": {
         "module": "commonjs",
-        "target": "es2021",
+        "target": "es2019",
         "outDir": "out",
         "lib": [
-            "es2021"
+            "es2019"
         ],
         "sourceMap": true,
         "rootDir": ".",


Test patch:
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 a747b4bc1f..36e9ec6333 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -144,10 +144,10 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="brace">}</span>
 
 <span class="comment documentation">/// ```</span>
-<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">macro_rules</span><span class="macro_bang injected">!</span><span class="none injected"> </span><span class="macro declaration injected">noop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="punctuation injected">$</span><span class="none injected">expr</span><span class="colon injected">:</span><span class="none injected">expr</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">=</span><span class="angle injected">&gt;</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="punctuation injected">$</span><span class="none injected">expr </span><span class="brace injected">}</span><span class="brace injected">}</span>
+<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">macro_rules</span><span class="punctuation injected">!</span><span class="none injected"> </span><span class="macro declaration injected">noop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="punctuation injected">$</span><span class="none injected">expr</span><span class="colon injected">:</span><span class="none injected">expr</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">=</span><span class="angle injected">&gt;</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="punctuation injected">$</span><span class="none injected">expr </span><span class="brace injected">}</span><span class="brace injected">}</span>
 <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="macro injected">noop</span><span class="macro_bang injected">!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
 <span class="comment documentation">/// ```</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
         <span class="punctuation">$</span>expr
     <span class="brace">}</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
index ba62b68e9d..7cd6a5a72d 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
@@ -50,7 +50,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword">use</span> <span class="keyword crate_root">super</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">void</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 <span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="keyword">Self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
index b725c80565..71add7e495 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
@@ -48,7 +48,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         <span class="comma">,</span><span class="builtin_type">i32</span> <span class="colon">:</span><span class="field declaration public">y</span> <span class="keyword">pub</span>
     <span class="brace">}</span> <span class="struct declaration">Foo</span> <span class="keyword">struct</span>
 <span class="brace">}</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">def_fn</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">def_fn</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="brace">}</span>
 <span class="brace">}</span>
 
@@ -58,17 +58,17 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">dont_color_me_braces</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">dont_color_me_braces</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="numeric_literal">0</span><span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
         <span class="punctuation">$</span>expr
     <span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">keyword_frag</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">keyword_frag</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span>
 <span class="brace">}</span>
 
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 60bc290121..29a0a9f066 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -42,20 +42,20 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">println</span> <span class="brace">{</span>
+<pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">println</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="brace">{</span>
         <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="brace">}</span><span class="parenthesis">)</span>
 <span class="brace">}</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">format_args</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">const_format_args</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">const_format_args</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">format_args_nl</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args_nl</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">mod</span> <span class="module declaration">panic</span> <span class="brace">{</span>
     <span class="keyword">pub</span> <span class="keyword">macro</span> <span class="macro declaration">panic_2015</span> <span class="brace">{</span>
@@ -81,13 +81,13 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="parenthesis attribute">(</span><span class="none attribute">std_panic</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">panic</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">panic</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">assert</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">assert</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">asm</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">asm</span> <span class="brace">{</span><span class="brace">}</span>
 
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">toho</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">toho</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented"</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented: {}"</span><span class="comma">,</span> <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span>
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 0716bae751..113463aa7a 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -42,12 +42,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span>
+<pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">id</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
         <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span>
     <span class="brace">}</span><span class="semicolon">;</span>
 <span class="brace">}</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">unsafe_deref</span> <span class="brace">{</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">unsafe_deref</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
         <span class="punctuation">*</span><span class="parenthesis">(</span><span class="operator">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
     <span class="brace">}</span><span class="semicolon">;</span>