Repository: rust-analyzer/rust-analyzer
Pull request #10373 (2021-09-27 16:53:18)

fix: `into_iterator` not completed on `Vec<{unknown}>`
Fixes  #10297 


Patch:
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index aa4f25a3b4..4ef7d399de 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -12,7 +12,7 @@ use hir_ty::{
     },
     Interner, TraitRefExt, WhereClause,
 };
-use syntax::ast::{self, HasName};
+use syntax::ast::{self, NameOwner};
 
 use crate::{
     Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 879124502a..5b3bea2307 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -72,7 +72,7 @@ use once_cell::unsync::Lazy;
 use rustc_hash::FxHashSet;
 use stdx::{format_to, impl_from};
 use syntax::{
-    ast::{self, HasAttrs as _, HasName},
+    ast::{self, AttrsOwner, NameOwner},
     AstNode, AstPtr, SmolStr, SyntaxKind, SyntaxNodePtr,
 };
 use tt::{Ident, Leaf, Literal, TokenTree};
@@ -2504,9 +2504,8 @@ impl Type {
 
     pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
         // There should be no inference vars in types passed here
-        // FIXME check that?
-        let canonical =
-            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
+        let ty = hir_ty::replace_errors_with_variables(&self.ty).value;
+        let canonical = Canonical { value: ty, binders: CanonicalVarKinds::empty(&Interner) };
         let environment = self.env.env.clone();
         let ty = InEnvironment { goal: canonical, environment };
         autoderef(db, Some(self.krate), ty)
@@ -2600,10 +2599,7 @@ impl Type {
         callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
     ) {
         // There should be no inference vars in types passed here
-        // FIXME check that?
-        // FIXME replace Unknown by bound vars here
-        let canonical =
-            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
+        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 
         let env = self.env.clone();
         let krate = krate.id;
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 3d346b60ab..5cda6cc1e9 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -17,7 +17,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::{smallvec, SmallVec};
 use syntax::{
     algo::skip_trivia_token,
-    ast::{self, HasGenericParams, HasLoopBody},
+    ast::{self, GenericParamsOwner, LoopBodyOwner},
     match_ast, AstNode, Direction, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize,
 };
 
@@ -542,56 +542,40 @@ impl<'db> SemanticsImpl<'db> {
             None => return,
         };
         let sa = self.analyze(&parent);
-        let mut stack: SmallVec<[_; 1]> = smallvec![InFile::new(sa.file_id, token)];
+        let mut queue = vec![InFile::new(sa.file_id, token)];
         let mut cache = self.expansion_info_cache.borrow_mut();
-
-        let mut process_expansion_for_token =
-            |stack: &mut SmallVec<_>, file_id, item, token: InFile<&_>| {
-                let mapped_tokens = cache
-                    .entry(file_id)
-                    .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
-                    .as_ref()?
-                    .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.inspect(|token| {
-                    if let Some(parent) = token.value.parent() {
-                        self.cache(find_root(&parent), token.file_id);
-                    }
-                }));
-                // if the length changed we have found a mapping for the token
-                (stack.len() != len).then(|| ())
-            };
-
         // Remap the next token in the queue into a macro call its in, if it is not being remapped
         // either due to not being in a macro-call or because its unused push it into the result vec,
         // otherwise push the remapped tokens back into the queue as they can potentially be remapped again.
-        while let Some(token) = stack.pop() {
+        while let Some(token) = queue.pop() {
             self.db.unwind_if_cancelled();
             let was_not_remapped = (|| {
-                // are we inside an attribute macro call
-                let containing_attribute_macro_call = self.with_ctx(|ctx| {
-                    token
-                        .value
-                        .ancestors()
-                        .filter_map(ast::Item::cast)
-                        .filter_map(|item| {
-                            Some((ctx.item_to_macro_call(token.with_value(item.clone()))?, item))
-                        })
-                        .last()
-                });
-                if let Some((call_id, item)) = containing_attribute_macro_call {
+                if let Some((call_id, item)) = token
+                    .value
+                    .ancestors()
+                    .filter_map(ast::Item::cast)
+                    .filter_map(|item| {
+                        self.with_ctx(|ctx| ctx.item_to_macro_call(token.with_value(item.clone())))
+                            .zip(Some(item))
+                    })
+                    .last()
+                {
                     let file_id = call_id.as_file();
-                    return process_expansion_for_token(
-                        &mut stack,
-                        file_id,
-                        Some(item),
-                        token.as_ref(),
-                    );
+                    let tokens = cache
+                        .entry(file_id)
+                        .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
+                        .as_ref()?
+                        .map_token_down(self.db.upcast(), Some(item), token.as_ref())?;
+
+                    let len = queue.len();
+                    queue.extend(tokens.inspect(|token| {
+                        if let Some(parent) = token.value.parent() {
+                            self.cache(find_root(&parent), token.file_id);
+                        }
+                    }));
+                    return (queue.len() != len).then(|| ());
                 }
 
-                // or are we inside a function-like macro call
                 if let Some(macro_call) = token.value.ancestors().find_map(ast::MacroCall::cast) {
                     let tt = macro_call.token_tree()?;
                     let l_delim = match tt.left_delimiter_token() {
@@ -605,12 +589,21 @@ impl<'db> SemanticsImpl<'db> {
                     if !TextRange::new(l_delim, r_delim).contains_range(token.value.text_range()) {
                         return None;
                     }
-
                     let file_id = sa.expand(self.db, token.with_value(&macro_call))?;
-                    return process_expansion_for_token(&mut stack, file_id, None, token.as_ref());
+                    let tokens = cache
+                        .entry(file_id)
+                        .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
+                        .as_ref()?
+                        .map_token_down(self.db.upcast(), None, token.as_ref())?;
+
+                    let len = queue.len();
+                    queue.extend(tokens.inspect(|token| {
+                        if let Some(parent) = token.value.parent() {
+                            self.cache(find_root(&parent), token.file_id);
+                        }
+                    }));
+                    return (queue.len() != len).then(|| ());
                 }
-
-                // outside of a macro invocation so this is a "final" token
                 None
             })()
             .is_none();
@@ -689,7 +682,7 @@ impl<'db> SemanticsImpl<'db> {
     fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
         let text = lifetime.text();
         let lifetime_param = lifetime.syntax().ancestors().find_map(|syn| {
-            let gpl = ast::AnyHasGenericParams::cast(syn)?.generic_param_list()?;
+            let gpl = ast::DynGenericParamsOwner::cast(syn)?.generic_param_list()?;
             gpl.lifetime_params()
                 .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()).as_ref() == Some(&text))
         })?;
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 20e2481af6..723c7a1727 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -100,7 +100,7 @@ use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
 use stdx::impl_from;
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     match_ast, AstNode, SyntaxNode,
 };
 
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs
index 6ba70a2df6..402fb1d8dc 100644
--- a/crates/hir_def/src/adt.rs
+++ b/crates/hir_def/src/adt.rs
@@ -9,7 +9,7 @@ use hir_expand::{
     InFile,
 };
 use la_arena::{Arena, ArenaMap};
-use syntax::ast::{self, HasName, HasVisibility};
+use syntax::ast::{self, NameOwner, VisibilityOwner};
 use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
 
 use crate::{
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 03fe46e267..04011d9129 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -17,7 +17,7 @@ use la_arena::ArenaMap;
 use mbe::{syntax_node_to_token_tree, DelimiterKind};
 use smallvec::{smallvec, SmallVec};
 use syntax::{
-    ast::{self, AstNode, HasAttrs, IsString},
+    ast::{self, AstNode, AttrsOwner, IsString},
     match_ast, AstPtr, AstToken, SmolStr, SyntaxNode, TextRange, TextSize,
 };
 use tt::Subtree;
@@ -101,7 +101,11 @@ impl ops::Deref for AttrsWithOwner {
 impl RawAttrs {
     pub(crate) const EMPTY: Self = Self { entries: None };
 
-    pub(crate) fn new(db: &dyn DefDatabase, owner: &dyn ast::HasAttrs, hygiene: &Hygiene) -> Self {
+    pub(crate) fn new(
+        db: &dyn DefDatabase,
+        owner: &dyn ast::AttrsOwner,
+        hygiene: &Hygiene,
+    ) -> Self {
         let entries = collect_attrs(owner)
             .flat_map(|(id, attr)| match attr {
                 Either::Left(attr) => {
@@ -118,7 +122,7 @@ impl RawAttrs {
         Self { entries: if entries.is_empty() { None } else { Some(entries) } }
     }
 
-    fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::HasAttrs>) -> Self {
+    fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::AttrsOwner>) -> Self {
         let hygiene = Hygiene::new(db.upcast(), owner.file_id);
         Self::new(db, owner.value, &hygiene)
     }
@@ -204,7 +208,7 @@ impl Attrs {
         let mut res = ArenaMap::default();
 
         for (id, var) in src.value.iter() {
-            let attrs = RawAttrs::from_attrs_owner(db, src.with_value(var as &dyn ast::HasAttrs))
+            let attrs = RawAttrs::from_attrs_owner(db, src.with_value(var as &dyn ast::AttrsOwner))
                 .filter(db, krate);
 
             res.insert(id, attrs)
@@ -222,7 +226,7 @@ impl Attrs {
         let mut res = ArenaMap::default();
 
         for (id, fld) in src.value.iter() {
-            let owner: &dyn HasAttrs = match fld {
+            let owner: &dyn AttrsOwner = match fld {
                 Either::Left(tuple) => tuple,
                 Either::Right(record) => record,
             };
@@ -308,7 +312,7 @@ impl AttrsWithOwner {
                     Some(it) => {
                         let raw_attrs = RawAttrs::from_attrs_owner(
                             db,
-                            it.as_ref().map(|it| it as &dyn ast::HasAttrs),
+                            it.as_ref().map(|it| it as &dyn ast::AttrsOwner),
                         );
                         match mod_data.definition_source(db) {
                             InFile { file_id, value: ModuleSource::SourceFile(file) } => raw_attrs
@@ -319,9 +323,9 @@ impl AttrsWithOwner {
                     None => RawAttrs::from_attrs_owner(
                         db,
                         mod_data.definition_source(db).as_ref().map(|src| match src {
-                            ModuleSource::SourceFile(file) => file as &dyn ast::HasAttrs,
-                            ModuleSource::Module(module) => module as &dyn ast::HasAttrs,
-                            ModuleSource::BlockExpr(block) => block as &dyn ast::HasAttrs,
+                            ModuleSource::SourceFile(file) => file as &dyn ast::AttrsOwner,
+                            ModuleSource::Module(module) => module as &dyn ast::AttrsOwner,
+                            ModuleSource::BlockExpr(block) => block as &dyn ast::AttrsOwner,
                         }),
                     ),
                 }
@@ -394,9 +398,9 @@ impl AttrsWithOwner {
                     None => {
                         let InFile { file_id, value } = mod_data.definition_source(db);
                         let attrs_owner = match &value {
-                            ModuleSource::SourceFile(file) => file as &dyn ast::HasAttrs,
-                            ModuleSource::Module(module) => module as &dyn ast::HasAttrs,
-                            ModuleSource::BlockExpr(block) => block as &dyn ast::HasAttrs,
+                            ModuleSource::SourceFile(file) => file as &dyn ast::AttrsOwner,
+                            ModuleSource::Module(module) => module as &dyn ast::AttrsOwner,
+                            ModuleSource::BlockExpr(block) => block as &dyn ast::AttrsOwner,
                         };
                         return AttrSourceMap::new(InFile::new(file_id, attrs_owner));
                     }
@@ -407,51 +411,51 @@ impl AttrsWithOwner {
                 let file_id = id.parent.file_id(db);
                 let root = db.parse_or_expand(file_id).unwrap();
                 let owner = match &map[id.local_id] {
-                    Either::Left(it) => ast::AnyHasAttrs::new(it.to_node(&root)),
-                    Either::Right(it) => ast::AnyHasAttrs::new(it.to_node(&root)),
+                    Either::Left(it) => ast::DynAttrsOwner::new(it.to_node(&root)),
+                    Either::Right(it) => ast::DynAttrsOwner::new(it.to_node(&root)),
                 };
                 InFile::new(file_id, owner)
             }
             AttrDefId::AdtId(adt) => match adt {
-                AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
-                AdtId::UnionId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
-                AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
+                AdtId::StructId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new),
+                AdtId::UnionId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new),
+                AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new),
             },
-            AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
+            AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new),
             AttrDefId::EnumVariantId(id) => {
                 let map = db.variants_attrs_source_map(id.parent);
                 let file_id = id.parent.lookup(db).id.file_id();
                 let root = db.parse_or_expand(file_id).unwrap();
-                InFile::new(file_id, ast::AnyHasAttrs::new(map[id.local_id].to_node(&root)))
+                InFile::new(file_id, ast::DynAttrsOwner::new(map[id.local_id].to_node(&root)))
             }
-            AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
-            AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
-            AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
-            AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
+            AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new),
+            AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new),
+            AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new),
+            AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new),
             AttrDefId::MacroDefId(id) => id.ast_id().either(
-                |it| it.with_value(ast::AnyHasAttrs::new(it.to_node(db.upcast()))),
-                |it| it.with_value(ast::AnyHasAttrs::new(it.to_node(db.upcast()))),
+                |it| it.with_value(ast::DynAttrsOwner::new(it.to_node(db.upcast()))),
+                |it| it.with_value(ast::DynAttrsOwner::new(it.to_node(db.upcast()))),
             ),
-            AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
+            AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::DynAttrsOwner::new),
             AttrDefId::GenericParamId(id) => match id {
                 GenericParamId::TypeParamId(id) => {
                     id.parent.child_source(db).map(|source| match &source[id.local_id] {
-                        Either::Left(id) => ast::AnyHasAttrs::new(id.clone()),
-                        Either::Right(id) => ast::AnyHasAttrs::new(id.clone()),
+                        Either::Left(id) => ast::DynAttrsOwner::new(id.clone()),
+                        Either::Right(id) => ast::DynAttrsOwner::new(id.clone()),
                     })
                 }
                 GenericParamId::LifetimeParamId(id) => id
                     .parent
                     .child_source(db)
-                    .map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
+                    .map(|source| ast::DynAttrsOwner::new(source[id.local_id].clone())),
                 GenericParamId::ConstParamId(id) => id
                     .parent
                     .child_source(db)
-                    .map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
+                    .map(|source| ast::DynAttrsOwner::new(source[id.local_id].clone())),
             },
         };
 
-        AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs))
+        AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn AttrsOwner))
     }
 
     pub fn docs_with_rangemap(
@@ -551,7 +555,7 @@ pub struct AttrSourceMap {
 }
 
 impl AttrSourceMap {
-    fn new(owner: InFile<&dyn ast::HasAttrs>) -> Self {
+    fn new(owner: InFile<&dyn ast::AttrsOwner>) -> Self {
         let mut attrs = Vec::new();
         let mut doc_comments = Vec::new();
         for (_, attr) in collect_attrs(owner.value) {
@@ -808,10 +812,10 @@ impl<'a> AttrQuery<'a> {
 
 fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> RawAttrs
 where
-    N: ast::HasAttrs,
+    N: ast::AttrsOwner,
 {
     let src = InFile::new(src.file_id, src.to_node(db.upcast()));
-    RawAttrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn ast::HasAttrs))
+    RawAttrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn ast::AttrsOwner))
 }
 
 fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> RawAttrs {
@@ -821,7 +825,7 @@ fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase
 }
 
 fn collect_attrs(
-    owner: &dyn ast::HasAttrs,
+    owner: &dyn ast::AttrsOwner,
 ) -> impl Iterator<Item = (AttrId, Either<ast::Attr, ast::Comment>)> {
     let (inner_attrs, inner_docs) = inner_attributes(owner.syntax())
         .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs)));
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 0eff093beb..5320a96bc5 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -70,11 +70,11 @@ impl CfgExpander {
         CfgExpander { cfg_options, hygiene, krate }
     }
 
-    pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
+    pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs {
         RawAttrs::new(db, owner, &self.hygiene).filter(db, self.krate)
     }
 
-    pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool {
+    pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> bool {
         let attrs = self.parse_attrs(db, owner);
         attrs.is_cfg_enabled(&self.cfg_options)
     }
@@ -179,7 +179,7 @@ impl Expander {
         InFile { file_id: self.current_file_id, value }
     }
 
-    pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
+    pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs {
         self.cfg_expander.parse_attrs(db, owner)
     }
 
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 804d98ce38..6a6d992af3 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -14,7 +14,7 @@ use la_arena::Arena;
 use profile::Count;
 use syntax::{
     ast::{
-        self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
+        self, ArgListOwner, ArrayExprKind, AstChildren, LiteralKind, LoopBodyOwner, NameOwner,
         SlicePatComponents,
     },
     AstNode, AstPtr, SyntaxNodePtr,
@@ -912,7 +912,7 @@ impl ExprCollector<'_> {
 
     /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
     /// not.
-    fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> Option<()> {
+    fn check_cfg(&mut self, owner: &dyn ast::AttrsOwner) -> Option<()> {
         match self.expander.parse_attrs(self.db, owner).cfg() {
             Some(cfg) => {
                 if self.expander.cfg_options().check(&cfg) != Some(false) {
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index 6d63570428..e4580a0ca3 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -7,7 +7,7 @@
 use either::Either;
 use hir_expand::HirFileId;
 use itertools::Itertools;
-use syntax::ast::HasAttrs;
+use syntax::ast::AttrsOwner;
 
 use crate::{
     db::DefDatabase,
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 8c5313fa45..5425ea8bea 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -6,16 +6,14 @@
 use base_db::FileId;
 use either::Either;
 use hir_expand::{
-    name::{AsName, Name},
-    ExpandResult, HirFileId, InFile,
+    name::{name, AsName, Name},
+    HirFileId, InFile,
 };
 use la_arena::{Arena, ArenaMap};
-use once_cell::unsync::Lazy;
-use std::ops::DerefMut;
-use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
+use syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner};
 
 use crate::{
-    body::{Expander, LowerCtx},
+    body::LowerCtx,
     child_by_source::ChildBySource,
     db::DefDatabase,
     dyn_map::DynMap,
@@ -23,8 +21,8 @@ use crate::{
     keys,
     src::{HasChildSource, HasSource},
     type_ref::{LifetimeRef, TypeBound, TypeRef},
-    AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalConstParamId,
-    LocalLifetimeParamId, LocalTypeParamId, Lookup, TypeParamId,
+    AdtId, ConstParamId, GenericDefId, LifetimeParamId, LocalConstParamId, LocalLifetimeParamId,
+    LocalTypeParamId, Lookup, TypeParamId,
 };
 
 /// Data about a generic type parameter (to a function, struct, impl, ...).
@@ -92,6 +90,13 @@ pub enum WherePredicateTypeTarget {
     TypeParam(LocalTypeParamId),
 }
 
+#[derive(Default)]
+pub(crate) struct SourceMap {
+    pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::TypeParam, ast::Trait>>,
+    lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>,
+    const_params: ArenaMap<LocalConstParamId, ast::ConstParam>,
+}
+
 impl GenericParams {
     pub(crate) fn generic_params_query(
         db: &dyn DefDatabase,
@@ -101,23 +106,10 @@ impl GenericParams {
 
         match def {
             GenericDefId::FunctionId(id) => {
-                let loc = id.lookup(db);
-                let tree = loc.id.item_tree(db);
-                let item = &tree[loc.id.value];
-
-                let mut generic_params = GenericParams::clone(&item.explicit_generic_params);
-
-                let module = loc.container.module(db);
-                let func_data = db.function_data(id);
-
-                // Don't create an `Expander` nor call `loc.source(db)` if not needed since this
-                // causes a reparse after the `ItemTree` has been created.
-                let mut expander = Lazy::new(|| Expander::new(db, loc.source(db).file_id, module));
-                for param in &func_data.params {
-                    generic_params.fill_implicit_impl_trait_args(db, &mut expander, param);
-                }
-
-                Interned::new(generic_params)
+                let id = id.lookup(db).id;
+                let tree = id.item_tree(db);
+                let item = &tree[id.value];
+                item.generic_params.clone()
             }
             GenericDefId::AdtId(AdtId::StructId(id)) => {
                 let id = id.lookup(db).id;
@@ -161,9 +153,93 @@ impl GenericParams {
         }
     }
 
-    pub(crate) fn fill(&mut self, lower_ctx: &LowerCtx, node: &dyn HasGenericParams) {
+    fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
+        let mut generics = GenericParams::default();
+        let mut sm = SourceMap::default();
+
+        // FIXME: add `: Sized` bound for everything except for `Self` in traits
+        let file_id = match def {
+            GenericDefId::FunctionId(it) => {
+                let src = it.lookup(db).source(db);
+                let lower_ctx = LowerCtx::new(db, src.file_id);
+                generics.fill(&lower_ctx, &mut sm, &src.value);
+                // lower `impl Trait` in arguments
+                let data = db.function_data(it);
+                for param in &data.params {
+                    generics.fill_implicit_impl_trait_args(param);
+                }
+                src.file_id
+            }
+            GenericDefId::AdtId(AdtId::StructId(it)) => {
+                let src = it.lookup(db).source(db);
+                let lower_ctx = LowerCtx::new(db, src.file_id);
+                generics.fill(&lower_ctx, &mut sm, &src.value);
+                src.file_id
+            }
+            GenericDefId::AdtId(AdtId::UnionId(it)) => {
+                let src = it.lookup(db).source(db);
+                let lower_ctx = LowerCtx::new(db, src.file_id);
+                generics.fill(&lower_ctx, &mut sm, &src.value);
+                src.file_id
+            }
+            GenericDefId::AdtId(AdtId::EnumId(it)) => {
+                let src = it.lookup(db).source(db);
+                let lower_ctx = LowerCtx::new(db, src.file_id);
+                generics.fill(&lower_ctx, &mut sm, &src.value);
+                src.file_id
+            }
+            GenericDefId::TraitId(it) => {
+                let src = it.lookup(db).source(db);
+                let lower_ctx = LowerCtx::new(db, src.file_id);
+
+                // traits get the Self type as an implicit first type parameter
+                let self_param_id = generics.types.alloc(TypeParamData {
+                    name: Some(name![Self]),
+                    default: None,
+                    provenance: TypeParamProvenance::TraitSelf,
+                });
+                sm.type_params.insert(self_param_id, Either::Right(src.value.clone()));
+                // add super traits as bounds on Self
+                // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
+                let self_param = TypeRef::Path(name![Self].into());
+                generics.fill_bounds(&lower_ctx, &src.value, Either::Left(self_param));
+
+                generics.fill(&lower_ctx, &mut sm, &src.value);
+                src.file_id
+            }
+            GenericDefId::TypeAliasId(it) => {
+                let src = it.lookup(db).source(db);
+                let lower_ctx = LowerCtx::new(db, src.file_id);
+
+                generics.fill(&lower_ctx, &mut sm, &src.value);
+                src.file_id
+            }
+            // Note that we don't add `Self` here: in `impl`s, `Self` is not a
+            // type-parameter, but rather is a type-alias for impl's target
+            // type, so this is handled by the resolver.
+            GenericDefId::ImplId(it) => {
+                let src = it.lookup(db).source(db);
+                let lower_ctx = LowerCtx::new(db, src.file_id);
+
+                generics.fill(&lower_ctx, &mut sm, &src.value);
+                src.file_id
+            }
+            // We won't be using this ID anyway
+            GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(),
+        };
+
+        generics.shrink_to_fit();
+        (generics, InFile::new(file_id, sm))
+    }
+
+    pub(crate) fn fill(
+        &mut self,
+        lower_ctx: &LowerCtx,
+        sm: &mut SourceMap,
+        node: &dyn GenericParamsOwner,
+    ) {
         if let Some(params) = node.generic_param_list() {
-            self.fill_params(lower_ctx, params)
+            self.fill_params(lower_ctx, sm, params)
         }
         if let Some(where_clause) = node.where_clause() {
             self.fill_where_predicates(lower_ctx, where_clause);
@@ -173,7 +249,7 @@ impl GenericParams {
     pub(crate) fn fill_bounds(
         &mut self,
         lower_ctx: &LowerCtx,
-        node: &dyn ast::HasTypeBounds,
+        node: &dyn ast::TypeBoundsOwner,
         target: Either<TypeRef, LifetimeRef>,
     ) {
         for bound in
@@ -183,7 +259,12 @@ impl GenericParams {
         }
     }
 
-    fn fill_params(&mut self, lower_ctx: &LowerCtx, params: ast::GenericParamList) {
+    fn fill_params(
+        &mut self,
+        lower_ctx: &LowerCtx,
+        sm: &mut SourceMap,
+        params: ast::GenericParamList,
+    ) {
         for type_param in params.type_params() {
             let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
             // FIXME: Use `Path::from_src`
@@ -194,7 +275,9 @@ impl GenericParams {
                 default,
                 provenance: TypeParamProvenance::TypeParamList,
             };
-            self.types.alloc(param);
+            let param_id = self.types.alloc(param);
+            sm.type_params.insert(param_id, Either::Left(type_param.clone()));
+
             let type_ref = TypeRef::Path(name.into());
             self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
         }
@@ -202,7 +285,8 @@ impl GenericParams {
             let name =
                 lifetime_param.lifetime().map_or_else(Name::missing, |lt| Name::new_lifetime(&lt));
             let param = LifetimeParamData { name: name.clone() };
-            self.lifetimes.alloc(param);
+            let param_id = self.lifetimes.alloc(param);
+            sm.lifetime_params.insert(param_id, lifetime_param.clone());
             let lifetime_ref = LifetimeRef::new_name(name);
             self.fill_bounds(lower_ctx, &lifetime_param, Either::Right(lifetime_ref));
         }
@@ -210,7 +294,8 @@ impl GenericParams {
             let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
             let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
             let param = ConstParamData { name, ty: Interned::new(ty) };
-            self.consts.alloc(param);
+            let param_id = self.consts.alloc(param);
+            sm.const_params.insert(param_id, const_param.clone());
         }
     }
 
@@ -274,12 +359,7 @@ impl GenericParams {
         self.where_predicates.push(predicate);
     }
 
-    pub(crate) fn fill_implicit_impl_trait_args(
-        &mut self,
-        db: &dyn DefDatabase,
-        expander: &mut impl DerefMut<Target = Expander>,
-        type_ref: &TypeRef,
-    ) {
+    pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
         type_ref.walk(&mut |type_ref| {
             if let TypeRef::ImplTrait(bounds) = type_ref {
                 let param = TypeParamData {
@@ -295,18 +375,6 @@ impl GenericParams {
                     });
                 }
             }
-            if let TypeRef::Macro(mc) = type_ref {
-                let macro_call = mc.to_node(db.upcast());
-                match expander.enter_expand::<ast::Type>(db, macro_call) {
-                    Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
-                        let ctx = LowerCtx::new(db, mc.file_id);
-                        let type_ref = TypeRef::from_ast(&ctx, expanded);
-                        self.fill_implicit_impl_trait_args(db, expander, &type_ref);
-                        expander.exit(db, mark);
-                    }
-                    _ => {}
-                }
-            }
         });
     }
 
@@ -339,71 +407,13 @@ impl GenericParams {
     }
 }
 
-fn file_id_and_params_of(
-    def: GenericDefId,
-    db: &dyn DefDatabase,
-) -> (HirFileId, Option<ast::GenericParamList>) {
-    match def {
-        GenericDefId::FunctionId(it) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::AdtId(AdtId::StructId(it)) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::AdtId(AdtId::UnionId(it)) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::AdtId(AdtId::EnumId(it)) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::TraitId(it) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::TypeAliasId(it) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::ImplId(it) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        // We won't be using this ID anyway
-        GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => (FileId(!0).into(), None),
-    }
-}
-
 impl HasChildSource<LocalTypeParamId> for GenericDefId {
     type Value = Either<ast::TypeParam, ast::Trait>;
     fn child_source(
         &self,
         db: &dyn DefDatabase,
     ) -> InFile<ArenaMap<LocalTypeParamId, Self::Value>> {
-        let generic_params = db.generic_params(*self);
-        let mut idx_iter = generic_params.types.iter().map(|(idx, _)| idx);
-
-        let (file_id, generic_params_list) = file_id_and_params_of(*self, db);
-
-        let mut params = ArenaMap::default();
-
-        // For traits the first type index is `Self`, we need to add it before the other params.
-        if let GenericDefId::TraitId(id) = *self {
-            let trait_ref = id.lookup(db).source(db).value.clone();
-            let idx = idx_iter.next().unwrap();
-            params.insert(idx, Either::Right(trait_ref))
-        }
-
-        if let Some(generic_params_list) = generic_params_list {
-            for (idx, ast_param) in idx_iter.zip(generic_params_list.type_params()) {
-                params.insert(idx, Either::Left(ast_param));
-            }
-        }
-
-        InFile::new(file_id, params)
+        GenericParams::new(db, *self).1.map(|source_maps| source_maps.type_params)
     }
 }
 
@@ -413,20 +423,7 @@ impl HasChildSource<LocalLifetimeParamId> for GenericDefId {
         &self,
         db: &dyn DefDatabase,
     ) -> InFile<ArenaMap<LocalLifetimeParamId, Self::Value>> {
-        let generic_params = db.generic_params(*self);
-        let idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
-
-        let (file_id, generic_params_list) = file_id_and_params_of(*self, db);
-
-        let mut params = ArenaMap::default();
-
-        if let Some(generic_params_list) = generic_params_list {
-            for (idx, ast_param) in idx_iter.zip(generic_params_list.lifetime_params()) {
-                params.insert(idx, ast_param);
-            }
-        }
-
-        InFile::new(file_id, params)
+        GenericParams::new(db, *self).1.map(|source_maps| source_maps.lifetime_params)
     }
 }
 
@@ -436,50 +433,28 @@ impl HasChildSource<LocalConstParamId> for GenericDefId {
         &self,
         db: &dyn DefDatabase,
     ) -> InFile<ArenaMap<LocalConstParamId, Self::Value>> {
-        let generic_params = db.generic_params(*self);
-        let idx_iter = generic_params.consts.iter().map(|(idx, _)| idx);
-
-        let (file_id, generic_params_list) = file_id_and_params_of(*self, db);
-
-        let mut params = ArenaMap::default();
-
-        if let Some(generic_params_list) = generic_params_list {
-            for (idx, ast_param) in idx_iter.zip(generic_params_list.const_params()) {
-                params.insert(idx, ast_param);
-            }
-        }
-
-        InFile::new(file_id, params)
+        GenericParams::new(db, *self).1.map(|source_maps| source_maps.const_params)
     }
 }
 
 impl ChildBySource for GenericDefId {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, _: HirFileId) {
-        let generic_params = db.generic_params(*self);
-        let mut types_idx_iter = generic_params.types.iter().map(|(idx, _)| idx);
-        let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
-        let consts_idx_iter = generic_params.consts.iter().map(|(idx, _)| idx);
-
-        let (file_id, generic_params_list) = file_id_and_params_of(*self, db);
-
-        // For traits the first type index is `Self`, skip it.
-        if let GenericDefId::TraitId(_) = *self {
-            types_idx_iter.next().unwrap(); // advance_by(1);
-        }
+        let (_, sm) = GenericParams::new(db, *self);
 
-        if let Some(generic_params_list) = generic_params_list {
-            for (local_id, ast_param) in types_idx_iter.zip(generic_params_list.type_params()) {
-                let id = TypeParamId { parent: *self, local_id };
-                res[keys::TYPE_PARAM].insert(InFile::new(file_id, ast_param), id);
-            }
-            for (local_id, ast_param) in lts_idx_iter.zip(generic_params_list.lifetime_params()) {
-                let id = LifetimeParamId { parent: *self, local_id };
-                res[keys::LIFETIME_PARAM].insert(InFile::new(file_id, ast_param), id);
-            }
-            for (local_id, ast_param) in consts_idx_iter.zip(generic_params_list.const_params()) {
-                let id = ConstParamId { parent: *self, local_id };
-                res[keys::CONST_PARAM].insert(InFile::new(file_id, ast_param), id);
+        let sm = sm.as_ref();
+        for (local_id, src) in sm.value.type_params.iter() {
+            let id = TypeParamId { parent: *self, local_id };
+            if let Either::Left(type_param) = src {
+                res[keys::TYPE_PARAM].insert(sm.with_value(type_param.clone()), id)
             }
         }
+        for (local_id, src) in sm.value.lifetime_params.iter() {
+            let id = LifetimeParamId { parent: *self, local_id };
+            res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id);
+        }
+        for (local_id, src) in sm.value.const_params.iter() {
+            let id = ConstParamId { parent: *self, local_id };
+            res[keys::CONST_PARAM].insert(sm.with_value(src.clone()), id);
+        }
     }
 }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 3900e7e97c..26621b8c7e 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -44,7 +44,7 @@ use std::{
     sync::Arc,
 };
 
-use ast::{AstNode, HasName, StructKind};
+use ast::{AstNode, NameOwner, StructKind};
 use base_db::CrateId;
 use either::Either;
 use hir_expand::{
@@ -605,7 +605,7 @@ pub struct ExternBlock {
 pub struct Function {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub explicit_generic_params: Interned<GenericParams>,
+    pub generic_params: Interned<GenericParams>,
     pub abi: Option<Interned<str>>,
     pub params: IdRange<Param>,
     pub ret_type: Interned<TypeRef>,
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 9c278f5ac6..7bed19a792 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -4,7 +4,7 @@ use std::{collections::hash_map::Entry, mem, sync::Arc};
 
 use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId};
 use syntax::{
-    ast::{self, HasModuleItem},
+    ast::{self, ModuleItemOwner},
     SyntaxNode, WalkEvent,
 };
 
@@ -40,7 +40,7 @@ impl<'a> Ctx<'a> {
         }
     }
 
-    pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
+    pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree {
         self.tree.top_level =
             item_owner.items().flat_map(|item| self.lower_mod_item(&item, false)).collect();
         self.tree
@@ -401,7 +401,7 @@ impl<'a> Ctx<'a> {
         let mut res = Function {
             name,
             visibility,
-            explicit_generic_params: Interned::new(GenericParams::default()),
+            generic_params: Interned::new(GenericParams::default()),
             abi,
             params,
             ret_type: Interned::new(ret_type),
@@ -409,8 +409,7 @@ impl<'a> Ctx<'a> {
             ast_id,
             flags,
         };
-        res.explicit_generic_params =
-            self.lower_generic_params(GenericsOwner::Function(&res), func);
+        res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
 
         Some(id(self.data().functions.alloc(res)))
     }
@@ -645,7 +644,7 @@ impl<'a> Ctx<'a> {
     fn lower_generic_params_and_inner_items(
         &mut self,
         owner: GenericsOwner<'_>,
-        node: &impl ast::HasGenericParams,
+        node: &impl ast::GenericParamsOwner,
     ) -> Interned<GenericParams> {
         // Generics are part of item headers and may contain inner items we need to collect.
         if let Some(params) = node.generic_param_list() {
@@ -661,35 +660,45 @@ impl<'a> Ctx<'a> {
     fn lower_generic_params(
         &mut self,
         owner: GenericsOwner<'_>,
-        node: &impl ast::HasGenericParams,
+        node: &impl ast::GenericParamsOwner,
     ) -> Interned<GenericParams> {
+        let mut sm = &mut Default::default();
         let mut generics = GenericParams::default();
         match owner {
-            GenericsOwner::Function(_)
-            | GenericsOwner::Struct
+            GenericsOwner::Function(func) => {
+                generics.fill(&self.body_ctx, sm, node);
+                // lower `impl Trait` in arguments
+                for id in func.params.clone() {
+                    if let Param::Normal(ty) = &self.data().params[id] {
+                        generics.fill_implicit_impl_trait_args(ty);
+                    }
+                }
+            }
+            GenericsOwner::Struct
             | GenericsOwner::Enum
             | GenericsOwner::Union
             | GenericsOwner::TypeAlias => {
-                generics.fill(&self.body_ctx, node);
+                generics.fill(&self.body_ctx, sm, node);
             }
             GenericsOwner::Trait(trait_def) => {
                 // traits get the Self type as an implicit first type parameter
-                generics.types.alloc(TypeParamData {
+                let self_param_id = generics.types.alloc(TypeParamData {
                     name: Some(name![Self]),
                     default: None,
                     provenance: TypeParamProvenance::TraitSelf,
                 });
+                sm.type_params.insert(self_param_id, Either::Right(trait_def.clone()));
                 // add super traits as bounds on Self
                 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
                 let self_param = TypeRef::Path(name![Self].into());
                 generics.fill_bounds(&self.body_ctx, trait_def, Either::Left(self_param));
-                generics.fill(&self.body_ctx, node);
+                generics.fill(&self.body_ctx, &mut sm, node);
             }
             GenericsOwner::Impl => {
                 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
                 // type-parameter, but rather is a type-alias for impl's target
                 // type, so this is handled by the resolver.
-                generics.fill(&self.body_ctx, node);
+                generics.fill(&self.body_ctx, &mut sm, node);
             }
         }
 
@@ -697,7 +706,7 @@ impl<'a> Ctx<'a> {
         Interned::new(generics)
     }
 
-    fn lower_type_bounds(&mut self, node: &impl ast::HasTypeBounds) -> Vec<Interned<TypeBound>> {
+    fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<Interned<TypeBound>> {
         match node.type_bound_list() {
             Some(bound_list) => bound_list
                 .bounds()
@@ -707,7 +716,7 @@ impl<'a> Ctx<'a> {
         }
     }
 
-    fn lower_visibility(&mut self, item: &impl ast::HasVisibility) -> RawVisibilityId {
+    fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId {
         let vis = match self.forced_visibility {
             Some(vis) => return vis,
             None => RawVisibility::from_ast_with_hygiene(self.db, item.visibility(), &self.hygiene),
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 49dc1eef18..3e33b0c46c 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -234,7 +234,7 @@ impl<'a> Printer<'a> {
                 let Function {
                     name,
                     visibility,
-                    explicit_generic_params,
+                    generic_params,
                     abi,
                     params,
                     ret_type,
@@ -250,7 +250,7 @@ impl<'a> Printer<'a> {
                     w!(self, "extern \"{}\" ", abi);
                 }
                 w!(self, "fn {}", name);
-                self.print_generic_params(explicit_generic_params);
+                self.print_generic_params(generic_params);
                 w!(self, "(");
                 if !params.is_empty() {
                     self.indented(|this| {
@@ -271,7 +271,7 @@ impl<'a> Printer<'a> {
                 }
                 w!(self, ") -> ");
                 self.print_type_ref(ret_type);
-                self.print_where_clause(explicit_generic_params);
+                self.print_where_clause(generic_params);
                 wln!(self, ";");
             }
             ModItem::Struct(it) => {
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index 99e7cdc999..82bdcd5a86 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -6,7 +6,7 @@ use crate::intern::Interned;
 
 use either::Either;
 use hir_expand::name::{name, AsName};
-use syntax::ast::{self, AstNode, HasTypeBounds};
+use syntax::ast::{self, AstNode, TypeBoundsOwner};
 
 use super::AssociatedTypeBinding;
 use crate::{
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs
index eeebe87acd..c5738a2a0e 100644
--- a/crates/hir_expand/src/builtin_derive.rs
+++ b/crates/hir_expand/src/builtin_derive.rs
@@ -4,7 +4,7 @@ use tracing::debug;
 
 use mbe::ExpandResult;
 use syntax::{
-    ast::{self, AstNode, HasGenericParams, HasModuleItem, HasName},
+    ast::{self, AstNode, GenericParamsOwner, ModuleItemOwner, NameOwner},
     match_ast,
 };
 
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 297497ac1b..74f9b23d73 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -1,7 +1,7 @@
 //! Builtin macro
 use crate::{
     db::AstDatabase, name, quote, AstId, CrateId, MacroCallId, MacroCallLoc, MacroDefId,
-    MacroDefKind,
+    MacroDefKind, TextSize,
 };
 
 use base_db::{AnchoredPath, Edition, FileId};
@@ -148,14 +148,25 @@ fn line_expand(
 }
 
 fn stringify_expand(
-    _db: &dyn AstDatabase,
-    _id: MacroCallId,
-    tt: &tt::Subtree,
+    db: &dyn AstDatabase,
+    id: MacroCallId,
+    _tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
-    let pretty = tt::pretty(&tt.token_trees);
+    let loc = db.lookup_intern_macro(id);
+
+    let macro_content = {
+        let arg = match loc.kind.arg(db) {
+            Some(arg) => arg,
+            None => return ExpandResult::only_err(mbe::ExpandError::UnexpectedToken),
+        };
+        let macro_args = arg;
+        let text = macro_args.text();
+        let without_parens = TextSize::of('(')..text.len() - TextSize::of(')');
+        text.slice(without_parens).to_string()
+    };
 
     let expanded = quote! {
-        #pretty
+        #macro_content
     };
 
     ExpandResult::ok(expanded)
@@ -547,7 +558,7 @@ mod tests {
 
     use base_db::{fixture::WithFixture, SourceDatabase};
     use expect_test::{expect, Expect};
-    use syntax::ast::HasName;
+    use syntax::ast::NameOwner;
 
     use crate::{
         name::AsName, test_db::TestDB, AstNode, EagerCallInfo, ExpandTo, MacroCallId,
@@ -674,11 +685,7 @@ mod tests {
             r#"
             #[rustc_builtin_macro]
             macro_rules! stringify {() => {}}
-            stringify!(
-                a
-                b
-                c
-            )
+            stringify!(a b c)
             "#,
             expect![["\"a b c\""]],
         );
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index fd1d8d2e60..09ff972960 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -8,7 +8,7 @@ use mbe::{syntax_node_to_token_tree, ExpandError, ExpandResult};
 use rustc_hash::FxHashSet;
 use syntax::{
     algo::diff,
-    ast::{self, HasAttrs, HasName},
+    ast::{self, AttrsOwner, NameOwner},
     AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken, T,
 };
 
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index 5b3ccdeb60..a1c519b804 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -9,7 +9,7 @@ use db::TokenExpander;
 use either::Either;
 use mbe::Origin;
 use syntax::{
-    ast::{self, HasAttrs},
+    ast::{self, AttrsOwner},
     AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize,
 };
 
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index d903725d88..bdc3023e9c 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -25,8 +25,8 @@ use std::{hash::Hash, iter, sync::Arc};
 use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange};
 use syntax::{
     algo::skip_trivia_token,
-    ast::{self, AstNode, HasAttrs},
-    Direction, SyntaxNode, SyntaxToken, TextRange,
+    ast::{self, AstNode, AttrsOwner},
+    Direction, SyntaxNode, SyntaxToken, TextRange, TextSize,
 };
 
 use crate::{
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index 6fbb9c93b4..ea9b54af63 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -22,7 +22,7 @@ use hir_def::{
 use hir_expand::name::{AsName, Name};
 use stdx::{always, never};
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     AstNode, AstPtr,
 };
 
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs
index 472b396ac5..67f1f6dbdb 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -5,7 +5,7 @@ use ide_db::{
     helpers::visit_file_defs,
     RootDatabase,
 };
-use syntax::{ast::HasName, AstNode, TextRange};
+use syntax::{ast::NameOwner, AstNode, TextRange};
 
 use crate::{
     fn_references::find_all_methods,
@@ -99,7 +99,7 @@ pub(crate) fn annotations(
                 });
             }
 
-            fn name_range<T: HasName>(node: &InFile<T>, file_id: FileId) -> Option<TextRange> {
+            fn name_range<T: NameOwner>(node: &InFile<T>, file_id: FileId) -> Option<TextRange> {
                 if node.file_id == file_id.into() {
                     node.value.name().map(|it| it.syntax().text_range())
                 } else {
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 65c29f6805..6978e4b88f 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -14,7 +14,7 @@ use ide_db::{
 };
 use ide_db::{defs::Definition, RootDatabase};
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     match_ast, AstNode, SmolStr, TextRange,
 };
 
@@ -133,7 +133,7 @@ impl NavigationTarget {
     /// Allows `NavigationTarget` to be created from a `NameOwner`
     pub(crate) fn from_named(
         db: &RootDatabase,
-        node: InFile<&dyn ast::HasName>,
+        node: InFile<&dyn ast::NameOwner>,
         kind: SymbolKind,
     ) -> NavigationTarget {
         let name = node.value.name().map(|it| it.text().into()).unwrap_or_else(|| "_".into());
@@ -257,13 +257,13 @@ impl ToNavFromAst for hir::Trait {
 impl<D> TryToNav for D
 where
     D: HasSource + ToNavFromAst + Copy + HasAttrs + HirDisplay,
-    D::Ast: ast::HasName,
+    D::Ast: ast::NameOwner,
 {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
         let src = self.source(db)?;
         let mut res = NavigationTarget::from_named(
             db,
-            src.as_ref().map(|it| it as &dyn ast::HasName),
+            src.as_ref().map(|it| it as &dyn ast::NameOwner),
             D::KIND,
         );
         res.docs = self.docs(db);
@@ -343,7 +343,7 @@ impl TryToNav for hir::Field {
 impl TryToNav for hir::MacroDef {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
         let src = self.source(db)?;
-        let name_owner: &dyn ast::HasName = match &src.value {
+        let name_owner: &dyn ast::NameOwner = match &src.value {
             Either::Left(it) => it,
             Either::Right(it) => it,
         };
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs
index 409f3901f5..19071d6be9 100644
--- a/crates/ide/src/file_structure.rs
+++ b/crates/ide/src/file_structure.rs
@@ -1,6 +1,6 @@
 use ide_db::SymbolKind;
 use syntax::{
-    ast::{self, HasAttrs, HasGenericParams, HasName},
+    ast::{self, AttrsOwner, GenericParamsOwner, NameOwner},
     match_ast, AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, TextRange,
     WalkEvent,
 };
@@ -74,11 +74,11 @@ pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
 }
 
 fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
-    fn decl<N: HasName + HasAttrs>(node: N, kind: StructureNodeKind) -> Option<StructureNode> {
+    fn decl<N: NameOwner + AttrsOwner>(node: N, kind: StructureNodeKind) -> Option<StructureNode> {
         decl_with_detail(&node, None, kind)
     }
 
-    fn decl_with_type_ref<N: HasName + HasAttrs>(
+    fn decl_with_type_ref<N: NameOwner + AttrsOwner>(
         node: &N,
         type_ref: Option<ast::Type>,
         kind: StructureNodeKind,
@@ -91,7 +91,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
         decl_with_detail(node, detail, kind)
     }
 
-    fn decl_with_detail<N: HasName + HasAttrs>(
+    fn decl_with_detail<N: NameOwner + AttrsOwner>(
         node: &N,
         detail: Option<String>,
         kind: StructureNodeKind,
diff --git a/crates/ide/src/fn_references.rs b/crates/ide/src/fn_references.rs
index 63fb322cea..1a99a1f371 100644
--- a/crates/ide/src/fn_references.rs
+++ b/crates/ide/src/fn_references.rs
@@ -4,7 +4,7 @@
 use hir::Semantics;
 use ide_assists::utils::test_related_attribute;
 use ide_db::RootDatabase;
-use syntax::{ast, ast::HasName, AstNode, SyntaxNode};
+use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode};
 
 use crate::{FileId, FileRange};
 
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 66126c8d55..6f69421002 100755
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -152,7 +152,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
 
 fn contiguous_range_for_item_group<N>(first: N, visited: &mut FxHashSet<N>) -> Option<TextRange>
 where
-    N: ast::HasVisibility + Clone + Hash + Eq,
+    N: ast::VisibilityOwner + Clone + Hash + Eq,
 {
     if !visited.insert(first.clone()) {
         return None;
diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs
index 6b557bc92d..6aef3a9429 100644
--- a/crates/ide/src/highlight_related.rs
+++ b/crates/ide/src/highlight_related.rs
@@ -8,7 +8,7 @@ use ide_db::{
 };
 use rustc_hash::FxHashSet;
 use syntax::{
-    ast::{self, HasLoopBody},
+    ast::{self, LoopBodyOwner},
     match_ast, AstNode,
     SyntaxKind::IDENT,
     SyntaxNode, SyntaxToken, TextRange, TextSize, T,
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 401feffff4..79e68aa1dd 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -4,7 +4,7 @@ use ide_db::RootDatabase;
 use ide_db::{base_db::FileRange, helpers::FamousDefs};
 use stdx::to_lower_snake_case;
 use syntax::{
-    ast::{self, AstNode, HasArgList, HasName},
+    ast::{self, ArgListOwner, AstNode, NameOwner},
     match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T,
 };
 
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 3ebec4dd8f..c39d00b6e7 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -22,7 +22,7 @@ use ide_db::{
 use rustc_hash::FxHashMap;
 use syntax::{
     algo::find_node_at_offset,
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     match_ast, AstNode, SyntaxNode, TextRange, TextSize, T,
 };
 
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 5d0cf7bba4..376384670a 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -1,6 +1,6 @@
 use std::fmt;
 
-use ast::HasName;
+use ast::NameOwner;
 use cfg::CfgExpr;
 use either::Either;
 use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, InFile, Semantics};
@@ -14,7 +14,7 @@ use ide_db::{
 use itertools::Itertools;
 use rustc_hash::{FxHashMap, FxHashSet};
 use stdx::{always, format_to};
-use syntax::ast::{self, AstNode, HasAttrs as _};
+use syntax::ast::{self, AstNode, AttrsOwner};
 
 use crate::{
     display::{ToNav, TryToNav},
@@ -328,7 +328,7 @@ pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) ->
 
     let nav = NavigationTarget::from_named(
         sema.db,
-        func.as_ref().map(|it| it as &dyn ast::HasName),
+        func.as_ref().map(|it| it as &dyn ast::NameOwner),
         SymbolKind::Function,
     );
     let cfg = def.attrs(sema.db).cfg();
diff --git a/crates/ide_assists/src/handlers/add_lifetime_to_type.rs b/crates/ide_assists/src/handlers/add_lifetime_to_type.rs
index 14cdc1cf86..7030d0f978 100644
--- a/crates/ide_assists/src/handlers/add_lifetime_to_type.rs
+++ b/crates/ide_assists/src/handlers/add_lifetime_to_type.rs
@@ -1,4 +1,4 @@
-use syntax::ast::{self, AstNode, HasGenericParams, HasName};
+use syntax::ast::{self, AstNode, GenericParamsOwner, NameOwner};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
diff --git a/crates/ide_assists/src/handlers/add_missing_match_arms.rs b/crates/ide_assists/src/handlers/add_missing_match_arms.rs
index c856ab45d7..cdbd8ac183 100644
--- a/crates/ide_assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide_assists/src/handlers/add_missing_match_arms.rs
@@ -5,7 +5,7 @@ use hir::{Adt, HasSource, ModuleDef, Semantics};
 use ide_db::helpers::{mod_path_to_ast, FamousDefs};
 use ide_db::RootDatabase;
 use itertools::Itertools;
-use syntax::ast::{self, make, AstNode, HasName, MatchArm, Pat};
+use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat};
 
 use crate::{
     utils::{self, render_snippet, Cursor},
diff --git a/crates/ide_assists/src/handlers/change_visibility.rs b/crates/ide_assists/src/handlers/change_visibility.rs
index 5f15e923ad..ed936667f8 100644
--- a/crates/ide_assists/src/handlers/change_visibility.rs
+++ b/crates/ide_assists/src/handlers/change_visibility.rs
@@ -1,5 +1,5 @@
 use syntax::{
-    ast::{self, HasName, HasVisibility},
+    ast::{self, NameOwner, VisibilityOwner},
     AstNode,
     SyntaxKind::{
         CONST, ENUM, FN, MACRO_DEF, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, USE, VISIBILITY,
diff --git a/crates/ide_assists/src/handlers/convert_bool_then.rs b/crates/ide_assists/src/handlers/convert_bool_then.rs
index 2e24c22c9f..e7939269ad 100644
--- a/crates/ide_assists/src/handlers/convert_bool_then.rs
+++ b/crates/ide_assists/src/handlers/convert_bool_then.rs
@@ -9,7 +9,7 @@ use ide_db::{
 };
 use itertools::Itertools;
 use syntax::{
-    ast::{self, edit::AstNodeEdit, make, HasArgList},
+    ast::{self, edit::AstNodeEdit, make, ArgListOwner},
     ted, AstNode, SyntaxNode,
 };
 
diff --git a/crates/ide_assists/src/handlers/convert_into_to_from.rs b/crates/ide_assists/src/handlers/convert_into_to_from.rs
index 29555a5111..2d8b936cd6 100644
--- a/crates/ide_assists/src/handlers/convert_into_to_from.rs
+++ b/crates/ide_assists/src/handlers/convert_into_to_from.rs
@@ -2,7 +2,7 @@ use ide_db::{
     helpers::{mod_path_to_ast, FamousDefs},
     traits::resolve_target_trait,
 };
-use syntax::ast::{self, AstNode, HasName};
+use syntax::ast::{self, AstNode, NameOwner};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
diff --git a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
index 8744115f29..aef03e3238 100644
--- a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -2,7 +2,7 @@ use hir::known;
 use ide_db::helpers::FamousDefs;
 use stdx::format_to;
 use syntax::{
-    ast::{self, edit_in_place::Indent, make, HasArgList, HasLoopBody},
+    ast::{self, edit_in_place::Indent, make, ArgListOwner, LoopBodyOwner},
     AstNode,
 };
 
diff --git a/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index 9b8e548e8f..bb0382e15f 100644
--- a/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -1,7 +1,7 @@
 use either::Either;
 use ide_db::defs::{Definition, NameRefClass};
 use syntax::{
-    ast::{self, AstNode, HasGenericParams, HasVisibility},
+    ast::{self, AstNode, GenericParamsOwner, VisibilityOwner},
     match_ast, SyntaxNode,
 };
 
diff --git a/crates/ide_assists/src/handlers/convert_while_to_loop.rs b/crates/ide_assists/src/handlers/convert_while_to_loop.rs
index 2ecf646252..cbddc106ff 100644
--- a/crates/ide_assists/src/handlers/convert_while_to_loop.rs
+++ b/crates/ide_assists/src/handlers/convert_while_to_loop.rs
@@ -4,7 +4,7 @@ use syntax::{
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
-        make, HasLoopBody,
+        make, LoopBodyOwner,
     },
     AstNode, T,
 };
diff --git a/crates/ide_assists/src/handlers/destructure_tuple_binding.rs b/crates/ide_assists/src/handlers/destructure_tuple_binding.rs
index a57b3c3904..a421f57754 100644
--- a/crates/ide_assists/src/handlers/destructure_tuple_binding.rs
+++ b/crates/ide_assists/src/handlers/destructure_tuple_binding.rs
@@ -5,7 +5,7 @@ use ide_db::{
 };
 use itertools::Itertools;
 use syntax::{
-    ast::{self, AstNode, FieldExpr, HasName, IdentPat, MethodCallExpr},
+    ast::{self, AstNode, FieldExpr, IdentPat, MethodCallExpr, NameOwner},
     TextRange,
 };
 
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index 4b11c5da19..733bb34788 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -636,7 +636,7 @@ impl FunctionBody {
         let mut ancestors = self.parent()?.ancestors();
         let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted);
         let mut parent_loop = None;
-        let mut set_parent_loop = |loop_: &dyn ast::HasLoopBody| {
+        let mut set_parent_loop = |loop_: &dyn ast::LoopBodyOwner| {
             if loop_
                 .loop_body()
                 .map_or(false, |it| it.syntax().text_range().contains_range(self.text_range()))
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index d481b8c298..3bc347b1e2 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -15,8 +15,8 @@ use itertools::Itertools;
 use rustc_hash::FxHashSet;
 use syntax::{
     ast::{
-        self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasAttrs, HasGenericParams,
-        HasName, HasTypeBounds, HasVisibility,
+        self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, AttrsOwner,
+        GenericParamsOwner, NameOwner, TypeBoundsOwner, VisibilityOwner,
     },
     match_ast,
     ted::{self, Position},
diff --git a/crates/ide_assists/src/handlers/extract_type_alias.rs b/crates/ide_assists/src/handlers/extract_type_alias.rs
index f0c4d521db..a2dd23b58b 100644
--- a/crates/ide_assists/src/handlers/extract_type_alias.rs
+++ b/crates/ide_assists/src/handlers/extract_type_alias.rs
@@ -2,7 +2,7 @@ use either::Either;
 use ide_db::helpers::node_ext::walk_ty;
 use itertools::Itertools;
 use syntax::{
-    ast::{self, edit::IndentLevel, AstNode, HasGenericParams, HasName},
+    ast::{self, edit::IndentLevel, AstNode, GenericParamsOwner, NameOwner},
     match_ast,
 };
 
diff --git a/crates/ide_assists/src/handlers/fix_visibility.rs b/crates/ide_assists/src/handlers/fix_visibility.rs
index 80da4a35ad..08d665f8ee 100644
--- a/crates/ide_assists/src/handlers/fix_visibility.rs
+++ b/crates/ide_assists/src/handlers/fix_visibility.rs
@@ -1,7 +1,7 @@
 use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
 use ide_db::base_db::FileId;
 use syntax::{
-    ast::{self, HasVisibility as _},
+    ast::{self, VisibilityOwner},
     AstNode, TextRange, TextSize,
 };
 
@@ -147,7 +147,7 @@ fn target_data_for_def(
     ) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId)>
     where
         S: HasSource<Ast = Ast>,
-        Ast: AstNode + ast::HasVisibility,
+        Ast: AstNode + ast::VisibilityOwner,
     {
         let source = x.source(db)?;
         let in_file_syntax = source.syntax();
diff --git a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
index e67789a662..e55c385029 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
@@ -1,5 +1,5 @@
 use ide_db::{helpers::FamousDefs, RootDatabase};
-use syntax::ast::{self, AstNode, HasName};
+use syntax::ast::{self, AstNode, NameOwner};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs
index 680ec0d1cd..b54ec59da1 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs
@@ -2,7 +2,7 @@ use ide_db::helpers::FamousDefs;
 use itertools::Itertools;
 use stdx::format_to;
 use syntax::{
-    ast::{self, HasGenericParams, HasName, HasTypeBounds, Impl},
+    ast::{self, GenericParamsOwner, Impl, NameOwner, TypeBoundsOwner},
     AstNode,
 };
 
diff --git a/crates/ide_assists/src/handlers/generate_deref.rs b/crates/ide_assists/src/handlers/generate_deref.rs
index 2208c23c15..4e10fdb854 100644
--- a/crates/ide_assists/src/handlers/generate_deref.rs
+++ b/crates/ide_assists/src/handlers/generate_deref.rs
@@ -2,7 +2,7 @@ use std::fmt::Display;
 
 use ide_db::{helpers::FamousDefs, RootDatabase};
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     AstNode, SyntaxNode,
 };
 
diff --git a/crates/ide_assists/src/handlers/generate_derive.rs b/crates/ide_assists/src/handlers/generate_derive.rs
index 28483f795e..adae8ab7e9 100644
--- a/crates/ide_assists/src/handlers/generate_derive.rs
+++ b/crates/ide_assists/src/handlers/generate_derive.rs
@@ -1,5 +1,5 @@
 use syntax::{
-    ast::{self, AstNode, HasAttrs},
+    ast::{self, AstNode, AttrsOwner},
     SyntaxKind::{COMMENT, WHITESPACE},
     TextSize,
 };
diff --git a/crates/ide_assists/src/handlers/generate_enum_is_method.rs b/crates/ide_assists/src/handlers/generate_enum_is_method.rs
index c2a6e438b1..94216f2dff 100644
--- a/crates/ide_assists/src/handlers/generate_enum_is_method.rs
+++ b/crates/ide_assists/src/handlers/generate_enum_is_method.rs
@@ -1,6 +1,6 @@
 use stdx::to_lower_snake_case;
-use syntax::ast::HasVisibility;
-use syntax::ast::{self, AstNode, HasName};
+use syntax::ast::VisibilityOwner;
+use syntax::ast::{self, AstNode, NameOwner};
 
 use crate::{
     utils::{add_method_to_adt, find_struct_impl},
diff --git a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
index a9116be67c..986fb23155 100644
--- a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
+++ b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
@@ -1,7 +1,7 @@
 use itertools::Itertools;
 use stdx::to_lower_snake_case;
-use syntax::ast::HasVisibility;
-use syntax::ast::{self, AstNode, HasName};
+use syntax::ast::VisibilityOwner;
+use syntax::ast::{self, AstNode, NameOwner};
 
 use crate::{
     utils::{add_method_to_adt, find_struct_impl},
diff --git a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
index 96b751f099..8727be07dd 100644
--- a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
@@ -1,6 +1,6 @@
 use ide_db::helpers::FamousDefs;
 use ide_db::RootDatabase;
-use syntax::ast::{self, AstNode, HasName};
+use syntax::ast::{self, AstNode, NameOwner};
 
 use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
 
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index 8a115087da..0255e508b4 100644
--- a/crates/ide_assists/src/handlers/generate_function.rs
+++ b/crates/ide_assists/src/handlers/generate_function.rs
@@ -11,7 +11,7 @@ use syntax::{
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
-        make, AstNode, CallExpr, HasArgList, HasModuleItem,
+        make, ArgListOwner, AstNode, CallExpr, ModuleItemOwner,
     },
     SyntaxKind, SyntaxNode, TextRange, TextSize,
 };
diff --git a/crates/ide_assists/src/handlers/generate_getter.rs b/crates/ide_assists/src/handlers/generate_getter.rs
index 186e01fa9d..739f3e592f 100644
--- a/crates/ide_assists/src/handlers/generate_getter.rs
+++ b/crates/ide_assists/src/handlers/generate_getter.rs
@@ -1,5 +1,5 @@
 use stdx::{format_to, to_lower_snake_case};
-use syntax::ast::{self, AstNode, HasName, HasVisibility};
+use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
 
 use crate::{
     utils::useless_type_special_case,
diff --git a/crates/ide_assists/src/handlers/generate_impl.rs b/crates/ide_assists/src/handlers/generate_impl.rs
index 58fea103f8..fd2e250bc3 100644
--- a/crates/ide_assists/src/handlers/generate_impl.rs
+++ b/crates/ide_assists/src/handlers/generate_impl.rs
@@ -1,4 +1,4 @@
-use syntax::ast::{self, AstNode, HasName};
+use syntax::ast::{self, AstNode, NameOwner};
 
 use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assists};
 
diff --git a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
index d831289775..910010a044 100644
--- a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
+++ b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
@@ -1,6 +1,6 @@
 use hir::{known, HasSource, Name};
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     AstNode,
 };
 
diff --git a/crates/ide_assists/src/handlers/generate_new.rs b/crates/ide_assists/src/handlers/generate_new.rs
index 6a1f710f6d..b65e8387b0 100644
--- a/crates/ide_assists/src/handlers/generate_new.rs
+++ b/crates/ide_assists/src/handlers/generate_new.rs
@@ -1,6 +1,6 @@
 use itertools::Itertools;
 use stdx::format_to;
-use syntax::ast::{self, AstNode, HasName, HasVisibility, StructKind};
+use syntax::ast::{self, AstNode, NameOwner, StructKind, VisibilityOwner};
 
 use crate::{
     utils::{find_impl_block_start, find_struct_impl, generate_impl_text},
diff --git a/crates/ide_assists/src/handlers/generate_setter.rs b/crates/ide_assists/src/handlers/generate_setter.rs
index 5005ac9f5c..5bdf6b3f44 100644
--- a/crates/ide_assists/src/handlers/generate_setter.rs
+++ b/crates/ide_assists/src/handlers/generate_setter.rs
@@ -1,5 +1,5 @@
 use stdx::{format_to, to_lower_snake_case};
-use syntax::ast::{self, AstNode, HasName, HasVisibility};
+use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
 
 use crate::{
     utils::{find_impl_block_end, find_struct_impl, generate_impl_text},
diff --git a/crates/ide_assists/src/handlers/inline_call.rs b/crates/ide_assists/src/handlers/inline_call.rs
index d252d61a69..bd566ec820 100644
--- a/crates/ide_assists/src/handlers/inline_call.rs
+++ b/crates/ide_assists/src/handlers/inline_call.rs
@@ -4,14 +4,14 @@ use hir::{db::HirDatabase, HasSource, PathResolution, Semantics, TypeInfo};
 use ide_db::{
     base_db::{FileId, FileRange},
     defs::Definition,
-    helpers::{insert_use::remove_path_if_in_use_stmt, node_ext::expr_as_name_ref},
+    helpers::insert_use::remove_path_if_in_use_stmt,
     path_transform::PathTransform,
     search::{FileReference, SearchScope},
     RootDatabase,
 };
 use itertools::{izip, Itertools};
 use syntax::{
-    ast::{self, edit_in_place::Indent, HasArgList, PathExpr},
+    ast::{self, edit_in_place::Indent, ArgListOwner},
     ted, AstNode, SyntaxNode,
 };
 
@@ -359,17 +359,11 @@ fn inline(
     }
     // Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
     for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments).rev() {
-        let inline_direct = |usage, replacement: &ast::Expr| {
-            if let Some(field) = path_expr_as_record_field(usage) {
-                cov_mark::hit!(inline_call_inline_direct_field);
-                field.replace_expr(replacement.clone_for_update());
-            } else {
-                ted::replace(usage.syntax(), &replacement.syntax().clone_for_update());
-            }
-        };
-        // izip confuses RA due to our lack of hygiene info currently losing us typeinfo
-        let usages: &[ast::PathExpr] = &*usages;
-        match usages {
+        let expr_is_name_ref = matches!(&expr,
+            ast::Expr::PathExpr(expr)
+                if expr.path().and_then(|path| path.as_single_name_ref()).is_some()
+        );
+        match &*usages {
             // inline single use closure arguments
             [usage]
                 if matches!(expr, ast::Expr::ClosureExpr(_))
@@ -377,19 +371,21 @@ fn inline(
             {
                 cov_mark::hit!(inline_call_inline_closure);
                 let expr = make::expr_paren(expr.clone());
-                inline_direct(usage, &expr);
+                ted::replace(usage.syntax(), expr.syntax().clone_for_update());
             }
             // inline single use literals
             [usage] if matches!(expr, ast::Expr::Literal(_)) => {
                 cov_mark::hit!(inline_call_inline_literal);
-                inline_direct(usage, &expr);
+                ted::replace(usage.syntax(), expr.syntax().clone_for_update());
             }
             // inline direct local arguments
-            [_, ..] if expr_as_name_ref(&expr).is_some() => {
+            [_, ..] if expr_is_name_ref => {
                 cov_mark::hit!(inline_call_inline_locals);
-                usages.into_iter().for_each(|usage| inline_direct(usage, &expr));
+                usages.into_iter().for_each(|usage| {
+                    ted::replace(usage.syntax(), &expr.syntax().clone_for_update());
+                });
             }
-            // can't inline, emit a let statement
+            // cant inline, emit a let statement
             _ => {
                 let ty =
                     sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
@@ -425,12 +421,6 @@ fn inline(
     }
 }
 
-fn path_expr_as_record_field(usage: &PathExpr) -> Option<ast::RecordExprField> {
-    let path = usage.path()?;
-    let name_ref = path.as_single_name_ref()?;
-    ast::RecordExprField::for_name_ref(&name_ref)
-}
-
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -1032,61 +1022,6 @@ fn foo$0() {
 fn foo() {
     foo$0();
 }
-"#,
-        );
-    }
-
-    #[test]
-    fn inline_call_field_shorthand() {
-        cov_mark::check!(inline_call_inline_direct_field);
-        check_assist(
-            inline_call,
-            r#"
-struct Foo {
-    field: u32,
-    field1: u32,
-    field2: u32,
-    field3: u32,
-}
-fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
-    Foo {
-        field,
-        field1,
-        field2: val2,
-        field3: val3,
-    }
-}
-fn main() {
-    let bar = 0;
-    let baz = 0;
-    foo$0(bar, 0, baz, 0);
-}
-"#,
-            r#"
-struct Foo {
-    field: u32,
-    field1: u32,
-    field2: u32,
-    field3: u32,
-}
-fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
-    Foo {
-        field,
-        field1,
-        field2: val2,
-        field3: val3,
-    }
-}
-fn main() {
-    let bar = 0;
-    let baz = 0;
-    Foo {
-            field: bar,
-            field1: 0,
-            field2: baz,
-            field3: 0,
-        };
-}
 "#,
         );
     }
diff --git a/crates/ide_assists/src/handlers/inline_local_variable.rs b/crates/ide_assists/src/handlers/inline_local_variable.rs
index f01dff0965..337cd6cb5a 100644
--- a/crates/ide_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ide_assists/src/handlers/inline_local_variable.rs
@@ -7,7 +7,7 @@ use ide_db::{
     RootDatabase,
 };
 use syntax::{
-    ast::{self, AstNode, AstToken, HasName},
+    ast::{self, AstNode, AstToken, NameOwner},
     SyntaxElement, TextRange,
 };
 
diff --git a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs
index ec6be2e816..8077f73d1e 100644
--- a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs
+++ b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs
@@ -1,6 +1,6 @@
 use rustc_hash::FxHashSet;
 use syntax::{
-    ast::{self, edit_in_place::GenericParamsOwnerEdit, make, HasGenericParams},
+    ast::{self, edit_in_place::GenericParamsOwnerEdit, make, GenericParamsOwner},
     ted::{self, Position},
     AstNode, TextRange,
 };
diff --git a/crates/ide_assists/src/handlers/move_bounds.rs b/crates/ide_assists/src/handlers/move_bounds.rs
index 01c6eea225..d89d11bdf4 100644
--- a/crates/ide_assists/src/handlers/move_bounds.rs
+++ b/crates/ide_assists/src/handlers/move_bounds.rs
@@ -1,5 +1,5 @@
 use syntax::{
-    ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasName, HasTypeBounds},
+    ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, NameOwner, TypeBoundsOwner},
     match_ast,
 };
 
diff --git a/crates/ide_assists/src/handlers/move_from_mod_rs.rs b/crates/ide_assists/src/handlers/move_from_mod_rs.rs
deleted file mode 100644
index 026f4aaf6c..0000000000
--- a/crates/ide_assists/src/handlers/move_from_mod_rs.rs
+++ /dev/null
@@ -1,130 +0,0 @@
-use ide_db::{
-    assists::{AssistId, AssistKind},
-    base_db::AnchoredPathBuf,
-};
-use syntax::{ast, AstNode};
-
-use crate::{
-    assist_context::{AssistContext, Assists},
-    utils::trimmed_text_range,
-};
-
-// Assist: move_from_mod_rs
-//
-// Moves xxx/mod.rs to xxx.rs.
-//
-// ```
-// //- /main.rs
-// mod a;
-// //- /a/mod.rs
-// $0fn t() {}$0
-// ```
-// ->
-// ```
-// fn t() {}
-// ```
-pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
-    let source_file = ctx.find_node_at_offset::<ast::SourceFile>()?;
-    let module = ctx.sema.to_module_def(ctx.frange.file_id)?;
-    // Enable this assist if the user select all "meaningful" content in the source file
-    let trimmed_selected_range = trimmed_text_range(&source_file, ctx.frange.range);
-    let trimmed_file_range = trimmed_text_range(&source_file, source_file.syntax().text_range());
-    if !module.is_mod_rs(ctx.db()) {
-        cov_mark::hit!(not_mod_rs);
-        return None;
-    }
-    if trimmed_selected_range != trimmed_file_range {
-        cov_mark::hit!(not_all_selected);
-        return None;
-    }
-
-    let target = source_file.syntax().text_range();
-    let module_name = module.name(ctx.db())?.to_string();
-    let path = format!("../{}.rs", module_name);
-    let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
-    acc.add(
-        AssistId("move_from_mod_rs", AssistKind::Refactor),
-        format!("Convert {}/mod.rs to {}.rs", module_name, module_name),
-        target,
-        |builder| {
-            builder.move_file(ctx.frange.file_id, dst);
-        },
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::tests::{check_assist, check_assist_not_applicable};
-
-    use super::*;
-
-    #[test]
-    fn trivial() {
-        check_assist(
-            move_from_mod_rs,
-            r#"
-//- /main.rs
-mod a;
-//- /a/mod.rs
-$0fn t() {}
-$0"#,
-            r#"
-//- /a.rs
-fn t() {}
-"#,
-        );
-    }
-
-    #[test]
-    fn must_select_all_file() {
-        cov_mark::check!(not_all_selected);
-        check_assist_not_applicable(
-            move_from_mod_rs,
-            r#"
-//- /main.rs
-mod a;
-//- /a/mod.rs
-fn t() {}$0
-"#,
-        );
-        cov_mark::check!(not_all_selected);
-        check_assist_not_applicable(
-            move_from_mod_rs,
-            r#"
-//- /main.rs
-mod a;
-//- /a/mod.rs
-$0fn$0 t() {}
-"#,
-        );
-    }
-
-    #[test]
-    fn cannot_move_not_mod_rs() {
-        cov_mark::check!(not_mod_rs);
-        check_assist_not_applicable(
-            move_from_mod_rs,
-            r#"//- /main.rs
-mod a;
-//- /a.rs
-$0fn t() {}$0
-"#,
-        );
-    }
-
-    #[test]
-    fn cannot_downgrade_main_and_lib_rs() {
-        check_assist_not_applicable(
-            move_from_mod_rs,
-            r#"//- /main.rs
-$0fn t() {}$0
-"#,
-        );
-        check_assist_not_applicable(
-            move_from_mod_rs,
-            r#"//- /lib.rs
-$0fn t() {}$0
-"#,
-        );
-    }
-}
diff --git a/crates/ide_assists/src/handlers/move_module_to_file.rs b/crates/ide_assists/src/handlers/move_module_to_file.rs
index 30dc7c5fa4..cfc54be8d1 100644
--- a/crates/ide_assists/src/handlers/move_module_to_file.rs
+++ b/crates/ide_assists/src/handlers/move_module_to_file.rs
@@ -5,7 +5,7 @@ use ide_db::base_db::AnchoredPathBuf;
 use itertools::Itertools;
 use stdx::format_to;
 use syntax::{
-    ast::{self, edit::AstNodeEdit, HasName},
+    ast::{self, edit::AstNodeEdit, NameOwner},
     AstNode, TextRange,
 };
 
diff --git a/crates/ide_assists/src/handlers/move_to_mod_rs.rs b/crates/ide_assists/src/handlers/move_to_mod_rs.rs
index 6f505de4cf..9b060bb710 100644
--- a/crates/ide_assists/src/handlers/move_to_mod_rs.rs
+++ b/crates/ide_assists/src/handlers/move_to_mod_rs.rs
@@ -2,13 +2,39 @@ use ide_db::{
     assists::{AssistId, AssistKind},
     base_db::AnchoredPathBuf,
 };
-use syntax::{ast, AstNode};
-
-use crate::{
-    assist_context::{AssistContext, Assists},
-    utils::trimmed_text_range,
+use syntax::{
+    ast::{self, Whitespace},
+    AstNode, AstToken, SourceFile, TextRange, TextSize,
 };
 
+use crate::assist_context::{AssistContext, Assists};
+
+/// Trim(remove leading and trailing whitespace) `initial_range` in `source_file`, return the trimmed range.
+fn trimmed_text_range(source_file: &SourceFile, initial_range: TextRange) -> TextRange {
+    let mut trimmed_range = initial_range;
+    while source_file
+        .syntax()
+        .token_at_offset(trimmed_range.start())
+        .find_map(Whitespace::cast)
+        .is_some()
+        && trimmed_range.start() < trimmed_range.end()
+    {
+        let start = trimmed_range.start() + TextSize::from(1);
+        trimmed_range = TextRange::new(start, trimmed_range.end());
+    }
+    while source_file
+        .syntax()
+        .token_at_offset(trimmed_range.end())
+        .find_map(Whitespace::cast)
+        .is_some()
+        && trimmed_range.start() < trimmed_range.end()
+    {
+        let end = trimmed_range.end() - TextSize::from(1);
+        trimmed_range = TextRange::new(trimmed_range.start(), end);
+    }
+    trimmed_range
+}
+
 // Assist: move_to_mod_rs
 //
 // Moves xxx.rs to xxx/mod.rs.
@@ -38,13 +64,16 @@ pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext) -> Option<(
         return None;
     }
 
-    let target = source_file.syntax().text_range();
+    let target = TextRange::new(
+        source_file.syntax().text_range().start(),
+        source_file.syntax().text_range().end(),
+    );
     let module_name = module.name(ctx.db())?.to_string();
     let path = format!("./{}/mod.rs", module_name);
     let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
     acc.add(
         AssistId("move_to_mod_rs", AssistKind::Refactor),
-        format!("Convert {}.rs to {}/mod.rs", module_name, module_name),
+        format!("Turn {}.rs to {}/mod.rs", module_name, module_name),
         target,
         |builder| {
             builder.move_file(ctx.frange.file_id, dst);
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs
index 8a2ec8ba80..2510eae971 100644
--- a/crates/ide_assists/src/handlers/qualify_path.rs
+++ b/crates/ide_assists/src/handlers/qualify_path.rs
@@ -8,7 +8,7 @@ use ide_db::helpers::{
 use ide_db::RootDatabase;
 use syntax::{
     ast,
-    ast::{make, HasArgList},
+    ast::{make, ArgListOwner},
     AstNode,
 };
 
diff --git a/crates/ide_assists/src/handlers/remove_unused_param.rs b/crates/ide_assists/src/handlers/remove_unused_param.rs
index 545809a71d..75b9f827d7 100644
--- a/crates/ide_assists/src/handlers/remove_unused_param.rs
+++ b/crates/ide_assists/src/handlers/remove_unused_param.rs
@@ -1,7 +1,7 @@
 use ide_db::{base_db::FileId, defs::Definition, search::FileReference};
 use syntax::{
     algo::find_node_at_range,
-    ast::{self, HasArgList},
+    ast::{self, ArgListOwner},
     AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, T,
 };
 
diff --git a/crates/ide_assists/src/handlers/reorder_impl.rs b/crates/ide_assists/src/handlers/reorder_impl.rs
index 8ae12ab1f4..d398373c34 100644
--- a/crates/ide_assists/src/handlers/reorder_impl.rs
+++ b/crates/ide_assists/src/handlers/reorder_impl.rs
@@ -4,7 +4,7 @@ use rustc_hash::FxHashMap;
 use hir::{PathResolution, Semantics};
 use ide_db::RootDatabase;
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     ted, AstNode,
 };
 
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
index c0b7db332e..d6319ea5c1 100644
--- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -3,7 +3,7 @@ use ide_db::helpers::{import_assets::NameToImport, mod_path_to_ast};
 use ide_db::items_locator;
 use itertools::Itertools;
 use syntax::{
-    ast::{self, make, AstNode, HasName},
+    ast::{self, make, AstNode, NameOwner},
     SyntaxKind::{IDENT, WHITESPACE},
 };
 
diff --git a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
index 3a89c2b996..1873653306 100644
--- a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
@@ -6,7 +6,7 @@ use syntax::{
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
-        make, HasName,
+        make, NameOwner,
     },
     AstNode, TextRange,
 };
diff --git a/crates/ide_assists/src/handlers/sort_items.rs b/crates/ide_assists/src/handlers/sort_items.rs
index a9d4f4299e..f318c048b1 100644
--- a/crates/ide_assists/src/handlers/sort_items.rs
+++ b/crates/ide_assists/src/handlers/sort_items.rs
@@ -3,7 +3,7 @@ use std::cmp::Ordering;
 use itertools::Itertools;
 
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     ted, AstNode, TextRange,
 };
 
@@ -195,7 +195,7 @@ fn add_sort_variants_assist(acc: &mut Assists, variant_list: ast::VariantList) -
     )
 }
 
-fn sort_by_name<T: HasName + Clone>(initial: &[T]) -> Vec<T> {
+fn sort_by_name<T: NameOwner + Clone>(initial: &[T]) -> Vec<T> {
     initial
         .iter()
         .cloned()
diff --git a/crates/ide_assists/src/handlers/toggle_ignore.rs b/crates/ide_assists/src/handlers/toggle_ignore.rs
index feaa24c1fe..4da6089cac 100644
--- a/crates/ide_assists/src/handlers/toggle_ignore.rs
+++ b/crates/ide_assists/src/handlers/toggle_ignore.rs
@@ -1,5 +1,5 @@
 use syntax::{
-    ast::{self, HasAttrs},
+    ast::{self, AttrsOwner},
     AstNode, AstToken,
 };
 
diff --git a/crates/ide_assists/src/handlers/unmerge_use.rs b/crates/ide_assists/src/handlers/unmerge_use.rs
index 71a816e19f..22853b7e36 100644
--- a/crates/ide_assists/src/handlers/unmerge_use.rs
+++ b/crates/ide_assists/src/handlers/unmerge_use.rs
@@ -1,6 +1,6 @@
 use itertools::Itertools;
 use syntax::{
-    ast::{self, make, HasVisibility},
+    ast::{self, make, VisibilityOwner},
     ted::{self, Position},
     AstNode, SyntaxKind,
 };
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index d41d06f2d9..255ff47b80 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -154,7 +154,6 @@ mod handlers {
     mod move_guard;
     mod move_module_to_file;
     mod move_to_mod_rs;
-    mod move_from_mod_rs;
     mod pull_assignment_up;
     mod qualify_path;
     mod raw_string;
@@ -230,7 +229,6 @@ mod handlers {
             move_guard::move_guard_to_arm_body,
             move_module_to_file::move_module_to_file,
             move_to_mod_rs::move_to_mod_rs,
-            move_from_mod_rs::move_from_mod_rs,
             pull_assignment_up::pull_assignment_up,
             qualify_path::qualify_path,
             raw_string::add_hash,
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs
index 5273a3107b..aa0956d0f6 100644
--- a/crates/ide_assists/src/utils.rs
+++ b/crates/ide_assists/src/utils.rs
@@ -14,11 +14,11 @@ use syntax::{
         self,
         edit::{self, AstNodeEdit},
         edit_in_place::AttrsOwnerEdit,
-        make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
+        make, ArgListOwner, AttrsOwner, GenericParamsOwner, NameOwner, TypeBoundsOwner,
     },
-    ted, AstNode, AstToken, Direction, SmolStr, SourceFile,
+    ted, AstNode, Direction, SmolStr,
     SyntaxKind::*,
-    SyntaxNode, TextRange, TextSize, T,
+    SyntaxNode, TextSize, T,
 };
 
 use crate::assist_context::{AssistBuilder, AssistContext};
@@ -500,29 +500,3 @@ pub(crate) fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> {
         .filter(|f| f.name().is_some())
         .collect()
 }
-
-/// Trim(remove leading and trailing whitespace) `initial_range` in `source_file`, return the trimmed range.
-pub(crate) fn trimmed_text_range(source_file: &SourceFile, initial_range: TextRange) -> TextRange {
-    let mut trimmed_range = initial_range;
-    while source_file
-        .syntax()
-        .token_at_offset(trimmed_range.start())
-        .find_map(Whitespace::cast)
-        .is_some()
-        && trimmed_range.start() < trimmed_range.end()
-    {
-        let start = trimmed_range.start() + TextSize::from(1);
-        trimmed_range = TextRange::new(start, trimmed_range.end());
-    }
-    while source_file
-        .syntax()
-        .token_at_offset(trimmed_range.end())
-        .find_map(Whitespace::cast)
-        .is_some()
-        && trimmed_range.start() < trimmed_range.end()
-    {
-        let end = trimmed_range.end() - TextSize::from(1);
-        trimmed_range = TextRange::new(trimmed_range.start(), end);
-    }
-    trimmed_range
-}
diff --git a/crates/ide_assists/src/utils/gen_trait_fn_body.rs b/crates/ide_assists/src/utils/gen_trait_fn_body.rs
index 6915460209..eb4a23a8da 100644
--- a/crates/ide_assists/src/utils/gen_trait_fn_body.rs
+++ b/crates/ide_assists/src/utils/gen_trait_fn_body.rs
@@ -1,7 +1,7 @@
 //! This module contains functions to generate default trait impl function bodies where possible.
 
 use syntax::{
-    ast::{self, edit::AstNodeEdit, make, AstNode, BinaryOp, CmpOp, HasName, LogicOp},
+    ast::{self, edit::AstNodeEdit, make, AstNode, BinaryOp, CmpOp, LogicOp, NameOwner},
     ted,
 };
 
diff --git a/crates/ide_assists/src/utils/suggest_name.rs b/crates/ide_assists/src/utils/suggest_name.rs
index 35e2300196..17db6d3c19 100644
--- a/crates/ide_assists/src/utils/suggest_name.rs
+++ b/crates/ide_assists/src/utils/suggest_name.rs
@@ -5,7 +5,7 @@ use ide_db::RootDatabase;
 use itertools::Itertools;
 use stdx::to_lower_snake_case;
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     match_ast, AstNode, SmolStr,
 };
 
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index 94a5ebabf9..213cb70170 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -697,4 +697,26 @@ fn f() {
             "#]],
         );
     }
+
+    #[test]
+    fn completes_method_call_when_receiver_type_has_errors_issue_10297() {
+        check(
+            r#"
+//- minicore: iterator, sized
+struct Vec<T>;
+impl<T> IntoIterator for Vec<T> {
+    type Item = ();
+    type IntoIter = ();
+    fn into_iter(self);
+}
+fn main() {
+    let x: Vec<_>;
+    x.$0;
+}
+"#,
+            expect![[r#"
+                me into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter
+            "#]],
+        )
+    }
 }
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index a9f1944e28..28da6d69c8 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -2,7 +2,7 @@
 
 use rustc_hash::FxHashMap;
 use syntax::{
-    ast::{self, HasModuleItem},
+    ast::{self, ModuleItemOwner},
     match_ast, AstNode,
 };
 
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 9d3e894a3d..7d5c36d01f 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -9,7 +9,7 @@ use ide_db::{
 };
 use syntax::{
     algo::find_node_at_offset,
-    ast::{self, HasName, NameOrNameRef},
+    ast::{self, NameOrNameRef, NameOwner},
     match_ast, AstNode, NodeOrToken,
     SyntaxKind::{self, *},
     SyntaxNode, SyntaxToken, TextRange, TextSize, T,
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 381a6a83aa..05792dd47e 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -8,7 +8,7 @@ use hir::Semantics;
 use ide_db::RootDatabase;
 use syntax::{
     algo::non_trivia_sibling,
-    ast::{self, HasArgList, HasLoopBody},
+    ast::{self, ArgListOwner, LoopBodyOwner},
     match_ast, AstNode, Direction, SyntaxElement,
     SyntaxKind::*,
     SyntaxNode, SyntaxToken, TextRange, TextSize, T,
diff --git a/crates/ide_completion/src/render/const_.rs b/crates/ide_completion/src/render/const_.rs
index 166ae3c16b..4609f2e967 100644
--- a/crates/ide_completion/src/render/const_.rs
+++ b/crates/ide_completion/src/render/const_.rs
@@ -3,7 +3,7 @@
 use hir::{AsAssocItem, HasSource};
 use ide_db::SymbolKind;
 use syntax::{
-    ast::{Const, HasName},
+    ast::{Const, NameOwner},
     display::const_label,
 };
 
diff --git a/crates/ide_completion/src/render/type_alias.rs b/crates/ide_completion/src/render/type_alias.rs
index c1e6182643..6021448e78 100644
--- a/crates/ide_completion/src/render/type_alias.rs
+++ b/crates/ide_completion/src/render/type_alias.rs
@@ -3,7 +3,7 @@
 use hir::{AsAssocItem, HasSource};
 use ide_db::SymbolKind;
 use syntax::{
-    ast::{HasName, TypeAlias},
+    ast::{NameOwner, TypeAlias},
     display::type_label,
 };
 
diff --git a/crates/ide_db/src/call_info.rs b/crates/ide_db/src/call_info.rs
index e1d85f0411..3d32fddd93 100644
--- a/crates/ide_db/src/call_info.rs
+++ b/crates/ide_db/src/call_info.rs
@@ -5,7 +5,7 @@ use hir::{HasAttrs, HirDisplay, Semantics, Type};
 use stdx::format_to;
 use syntax::{
     algo,
-    ast::{self, HasArgList, HasName},
+    ast::{self, ArgListOwner, NameOwner},
     match_ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextSize,
 };
 
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index a8087d47fe..a52c4046bf 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -13,7 +13,7 @@ use base_db::FileId;
 use either::Either;
 use hir::{ItemInNs, MacroDef, ModuleDef, Name, Semantics};
 use syntax::{
-    ast::{self, make, HasLoopBody},
+    ast::{self, make, LoopBodyOwner},
     AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent, T,
 };
 
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index d6bb19d129..a672c10917 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -6,7 +6,7 @@ use hir::{
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     utils::path_to_string_stripping_turbo_fish,
     AstNode, SyntaxNode,
 };
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index a5d1932775..a8ac0a9006 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -7,7 +7,7 @@ use std::cmp::Ordering;
 use hir::Semantics;
 use syntax::{
     algo,
-    ast::{self, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, PathSegmentKind},
+    ast::{self, make, AstNode, AttrsOwner, ModuleItemOwner, PathSegmentKind, VisibilityOwner},
     match_ast, ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
 };
 
@@ -51,7 +51,7 @@ pub enum ImportScope {
 
 impl ImportScope {
     fn from(syntax: SyntaxNode) -> Option<Self> {
-        fn contains_cfg_attr(attrs: &dyn HasAttrs) -> bool {
+        fn contains_cfg_attr(attrs: &dyn AttrsOwner) -> bool {
             attrs
                 .attrs()
                 .any(|attr| attr.as_simple_call().map_or(false, |(ident, _)| ident == "cfg"))
diff --git a/crates/ide_db/src/helpers/merge_imports.rs b/crates/ide_db/src/helpers/merge_imports.rs
index 8189d6e53f..6f130e99b4 100644
--- a/crates/ide_db/src/helpers/merge_imports.rs
+++ b/crates/ide_db/src/helpers/merge_imports.rs
@@ -3,7 +3,7 @@ use std::cmp::Ordering;
 
 use itertools::{EitherOrBoth, Itertools};
 use syntax::{
-    ast::{self, make, AstNode, HasAttrs, HasVisibility, PathSegmentKind},
+    ast::{self, make, AstNode, AttrsOwner, PathSegmentKind, VisibilityOwner},
     ted,
 };
 
diff --git a/crates/ide_db/src/helpers/node_ext.rs b/crates/ide_db/src/helpers/node_ext.rs
index 82178ed749..fe823f74f8 100644
--- a/crates/ide_db/src/helpers/node_ext.rs
+++ b/crates/ide_db/src/helpers/node_ext.rs
@@ -7,16 +7,18 @@ use syntax::{
 pub fn expr_as_name_ref(expr: &ast::Expr) -> Option<ast::NameRef> {
     if let ast::Expr::PathExpr(expr) = expr {
         let path = expr.path()?;
-        path.as_single_name_ref()
-    } else {
-        None
+        let segment = path.segment()?;
+        let name_ref = segment.name_ref()?;
+        if path.qualifier().is_none() {
+            return Some(name_ref);
+        }
     }
+    None
 }
 
 pub fn block_as_lone_tail(block: &ast::BlockExpr) -> Option<ast::Expr> {
     block.statements().next().is_none().then(|| block.tail_expr()).flatten()
 }
-
 /// Preorder walk all the expression's child expressions.
 pub fn walk_expr(expr: &ast::Expr, cb: &mut dyn FnMut(ast::Expr)) {
     preorder_expr(expr, &mut |ev| {
diff --git a/crates/ide_db/src/rename.rs b/crates/ide_db/src/rename.rs
index 0ca0dc8c6b..a5dca509fe 100644
--- a/crates/ide_db/src/rename.rs
+++ b/crates/ide_db/src/rename.rs
@@ -27,7 +27,7 @@ use either::Either;
 use hir::{AsAssocItem, FieldSource, HasSource, InFile, ModuleSource, Semantics};
 use stdx::never;
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     lex_single_syntax_kind, AstNode, SyntaxKind, TextRange, T,
 };
 use text_edit::{TextEdit, TextEditBuilder};
@@ -156,7 +156,7 @@ impl Definition {
         fn name_range<D>(def: D, sema: &Semantics<RootDatabase>) -> Option<FileRange>
         where
             D: HasSource,
-            D::Ast: ast::HasName,
+            D::Ast: ast::NameOwner,
         {
             let src = def.source(sema.db)?;
             let name = src.value.name()?;
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index 54ceafa67f..fb3568b107 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -37,7 +37,7 @@ use hir::db::DefDatabase;
 use rayon::prelude::*;
 use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     match_ast, AstNode, Parse, SmolStr, SourceFile,
     SyntaxKind::*,
     SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent,
@@ -427,7 +427,7 @@ fn source_file_to_file_symbols(source_file: &SourceFile, file_id: FileId) -> Vec
 }
 
 fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
-    fn decl<N: HasName>(node: N) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
+    fn decl<N: NameOwner>(node: N) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
         let name = node.name()?;
         let name_range = name.syntax().text_range();
         let name = name.text().into();
diff --git a/crates/ide_db/src/traits.rs b/crates/ide_db/src/traits.rs
index def7a8acaa..66ae81c73e 100644
--- a/crates/ide_db/src/traits.rs
+++ b/crates/ide_db/src/traits.rs
@@ -4,7 +4,7 @@ use crate::RootDatabase;
 use hir::Semantics;
 use rustc_hash::FxHashSet;
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     AstNode,
 };
 
diff --git a/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index 9826e1c707..c47ceab33d 100644
--- a/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -1,7 +1,7 @@
 use hir::{db::AstDatabase, InFile};
 use ide_db::source_change::SourceChange;
 use syntax::{
-    ast::{self, HasArgList},
+    ast::{self, ArgListOwner},
     AstNode, TextRange,
 };
 use text_edit::TextEdit;
diff --git a/crates/ide_diagnostics/src/handlers/unlinked_file.rs b/crates/ide_diagnostics/src/handlers/unlinked_file.rs
index cc10a63f87..9eafd42d86 100644
--- a/crates/ide_diagnostics/src/handlers/unlinked_file.rs
+++ b/crates/ide_diagnostics/src/handlers/unlinked_file.rs
@@ -7,7 +7,7 @@ use ide_db::{
     RootDatabase,
 };
 use syntax::{
-    ast::{self, HasModuleItem, HasName},
+    ast::{self, ModuleItemOwner, NameOwner},
     AstNode, TextRange, TextSize,
 };
 use text_edit::TextEdit;
diff --git a/crates/ide_ssr/src/matching.rs b/crates/ide_ssr/src/matching.rs
index 88c1d80608..6812947218 100644
--- a/crates/ide_ssr/src/matching.rs
+++ b/crates/ide_ssr/src/matching.rs
@@ -527,7 +527,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
         pattern_ufcs: &UfcsCallInfo,
         code: &ast::MethodCallExpr,
     ) -> Result<(), MatchFailed> {
-        use ast::HasArgList;
+        use ast::ArgListOwner;
         let code_resolved_function = self
             .sema
             .resolve_method_call(code)
@@ -587,7 +587,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
         pattern_ufcs: &UfcsCallInfo,
         code: &ast::CallExpr,
     ) -> Result<(), MatchFailed> {
-        use ast::HasArgList;
+        use ast::ArgListOwner;
         // Check that the first argument is the expected type.
         if let (Some(pattern_type), Some(expr)) = (
             &pattern_ufcs.qualifier_type,
diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs
index cd5d76be3c..ffa316dd24 100644
--- a/crates/mbe/src/benchmark.rs
+++ b/crates/mbe/src/benchmark.rs
@@ -2,7 +2,7 @@
 
 use rustc_hash::FxHashMap;
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, NameOwner},
     AstNode, SmolStr,
 };
 use test_utils::{bench, bench_fixture, skip_slow_tests};
diff --git a/crates/proc_macro_srv/src/abis/abi_1_47/rustc_server.rs b/crates/proc_macro_srv/src/abis/abi_1_47/rustc_server.rs
index ff4976d0cb..088cc694e8 100644
--- a/crates/proc_macro_srv/src/abis/abi_1_47/rustc_server.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/rustc_server.rs
@@ -199,7 +199,44 @@ pub mod token_stream {
 
     impl ToString for TokenStream {
         fn to_string(&self) -> String {
-            tt::pretty(&self.token_trees)
+            return tokentrees_to_text(&self.token_trees[..]);
+
+            fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String {
+                tkns.iter()
+                    .fold((String::new(), true), |(last, last_to_joint), tkn| {
+                        let s = [last, tokentree_to_text(tkn)].join(if last_to_joint {
+                            ""
+                        } else {
+                            " "
+                        });
+                        let mut is_joint = false;
+                        if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
+                            if punct.spacing == tt::Spacing::Joint {
+                                is_joint = true;
+                            }
+                        }
+                        (s, is_joint)
+                    })
+                    .0
+            }
+
+            fn tokentree_to_text(tkn: &tt::TokenTree) -> String {
+                match tkn {
+                    tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
+                    tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
+                    tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
+                    tt::TokenTree::Subtree(subtree) => {
+                        let content = tokentrees_to_text(&subtree.token_trees);
+                        let (open, close) = match subtree.delimiter.map(|it| it.kind) {
+                            None => ("", ""),
+                            Some(tt::DelimiterKind::Brace) => ("{", "}"),
+                            Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
+                            Some(tt::DelimiterKind::Bracket) => ("[", "]"),
+                        };
+                        format!("{}{}{}", open, content, close)
+                    }
+                }
+            }
         }
     }
 
diff --git a/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs b/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs
index 56f9853399..8dfd65ade1 100644
--- a/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs
@@ -199,7 +199,44 @@ pub mod token_stream {
 
     impl ToString for TokenStream {
         fn to_string(&self) -> String {
-            tt::pretty(&self.token_trees)
+            return tokentrees_to_text(&self.token_trees[..]);
+
+            fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String {
+                tkns.iter()
+                    .fold((String::new(), true), |(last, last_to_joint), tkn| {
+                        let s = [last, tokentree_to_text(tkn)].join(if last_to_joint {
+                            ""
+                        } else {
+                            " "
+                        });
+                        let mut is_joint = false;
+                        if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
+                            if punct.spacing == tt::Spacing::Joint {
+                                is_joint = true;
+                            }
+                        }
+                        (s, is_joint)
+                    })
+                    .0
+            }
+
+            fn tokentree_to_text(tkn: &tt::TokenTree) -> String {
+                match tkn {
+                    tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
+                    tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
+                    tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
+                    tt::TokenTree::Subtree(subtree) => {
+                        let content = tokentrees_to_text(&subtree.token_trees);
+                        let (open, close) = match subtree.delimiter.map(|it| it.kind) {
+                            None => ("", ""),
+                            Some(tt::DelimiterKind::Brace) => ("{", "}"),
+                            Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
+                            Some(tt::DelimiterKind::Bracket) => ("[", "]"),
+                        };
+                        format!("{}{}{}", open, content, close)
+                    }
+                }
+            }
         }
     }
 
diff --git a/crates/proc_macro_srv/src/abis/abi_1_56/rustc_server.rs b/crates/proc_macro_srv/src/abis/abi_1_56/rustc_server.rs
index c1064ae968..562ee69e37 100644
--- a/crates/proc_macro_srv/src/abis/abi_1_56/rustc_server.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_56/rustc_server.rs
@@ -199,7 +199,44 @@ pub mod token_stream {
 
     impl ToString for TokenStream {
         fn to_string(&self) -> String {
-            tt::pretty(&self.token_trees)
+            return tokentrees_to_text(&self.token_trees[..]);
+
+            fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String {
+                tkns.iter()
+                    .fold((String::new(), true), |(last, last_to_joint), tkn| {
+                        let s = [last, tokentree_to_text(tkn)].join(if last_to_joint {
+                            ""
+                        } else {
+                            " "
+                        });
+                        let mut is_joint = false;
+                        if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
+                            if punct.spacing == tt::Spacing::Joint {
+                                is_joint = true;
+                            }
+                        }
+                        (s, is_joint)
+                    })
+                    .0
+            }
+
+            fn tokentree_to_text(tkn: &tt::TokenTree) -> String {
+                match tkn {
+                    tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
+                    tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
+                    tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
+                    tt::TokenTree::Subtree(subtree) => {
+                        let content = tokentrees_to_text(&subtree.token_trees);
+                        let (open, close) = match subtree.delimiter.map(|it| it.kind) {
+                            None => ("", ""),
+                            Some(tt::DelimiterKind::Brace) => ("{", "}"),
+                            Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
+                            Some(tt::DelimiterKind::Bracket) => ("[", "]"),
+                        };
+                        format!("{}{}{}", open, content, close)
+                    }
+                }
+            }
         }
     }
 
@@ -424,20 +461,19 @@ impl server::Group for Rustc {
         group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified)
     }
 
-    fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
-        if let Some(delim) = &mut group.delimiter {
-            delim.id = span;
-        }
+    fn set_span(&mut self, _group: &mut Self::Group, _span: Self::Span) {
+        // FIXME handle span
     }
 
-    fn span_open(&mut self, group: &Self::Group) -> Self::Span {
-        // FIXME we only store one `TokenId` for the delimiters
-        group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified)
+    fn span_open(&mut self, _group: &Self::Group) -> Self::Span {
+        // FIXME handle span
+        // MySpan(self.span_interner.intern(&MySpanData(group.span_open())))
+        tt::TokenId::unspecified()
     }
 
-    fn span_close(&mut self, group: &Self::Group) -> Self::Span {
-        // FIXME we only store one `TokenId` for the delimiters
-        group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified)
+    fn span_close(&mut self, _group: &Self::Group) -> Self::Span {
+        // FIXME handle span
+        tt::TokenId::unspecified()
     }
 }
 
@@ -455,11 +491,13 @@ impl server::Punct for Rustc {
     fn spacing(&mut self, punct: Self::Punct) -> bridge::Spacing {
         spacing_to_external(punct.spacing)
     }
-    fn span(&mut self, punct: Self::Punct) -> Self::Span {
-        punct.id
+    fn span(&mut self, _punct: Self::Punct) -> Self::Span {
+        // FIXME handle span
+        tt::TokenId::unspecified()
     }
-    fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
-        tt::Punct { id: span, ..punct }
+    fn with_span(&mut self, punct: Self::Punct, _span: Self::Span) -> Self::Punct {
+        // FIXME handle span
+        punct
     }
 }
 
@@ -473,13 +511,13 @@ impl server::Ident for Rustc {
         )
     }
 
-    fn span(&mut self, ident: Self::Ident) -> Self::Span {
-        self.ident_interner.get(ident.0).0.id
+    fn span(&mut self, _ident: Self::Ident) -> Self::Span {
+        // FIXME handle span
+        tt::TokenId::unspecified()
     }
-    fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
-        let data = self.ident_interner.get(ident.0);
-        let new = IdentData(tt::Ident { id: span, ..data.0.clone() });
-        IdentId(self.ident_interner.intern(&new))
+    fn with_span(&mut self, ident: Self::Ident, _span: Self::Span) -> Self::Ident {
+        // FIXME handle span
+        ident
     }
 }
 
@@ -499,8 +537,8 @@ impl server::Literal for Rustc {
         None
     }
 
-    fn to_string(&mut self, literal: &Self::Literal) -> String {
-        literal.to_string()
+    fn to_string(&mut self, _literal: &Self::Literal) -> String {
+        _literal.to_string()
     }
 
     fn integer(&mut self, n: &str) -> Self::Literal {
@@ -580,8 +618,8 @@ impl server::Literal for Rustc {
         literal.id
     }
 
-    fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) {
-        literal.id = span;
+    fn set_span(&mut self, _literal: &mut Self::Literal, _span: Self::Span) {
+        // FIXME handle span
     }
 
     fn subspan(
@@ -652,12 +690,10 @@ impl server::Span for Rustc {
         unimplemented!()
     }
     fn save_span(&mut self, _span: Self::Span) -> usize {
-        // FIXME stub
-        0
+        unimplemented!()
     }
     fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span {
-        // FIXME stub
-        tt::TokenId::unspecified()
+        unimplemented!()
     }
     /// Recent feature, not yet in the proc_macro
     ///
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 6c09833368..8f02082f3e 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -143,7 +143,7 @@ config_data! {
         diagnostics_warningsAsInfo: Vec<String> = "[]",
 
         /// Expand attribute macros.
-        experimental_procAttrMacros: bool = "true",
+        experimental_procAttrMacros: bool = "false",
 
         /// Controls file watching implementation.
         files_watcher: String = "\"client\"",
diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs
index e57c3d2fe4..e07b22a550 100644
--- a/crates/syntax/src/ast.rs
+++ b/crates/syntax/src/ast.rs
@@ -30,8 +30,8 @@ pub use self::{
         QuoteOffsets, Radix,
     },
     traits::{
-        CommentIter, HasArgList, HasAttrs, HasDocComments, HasGenericParams, HasLoopBody,
-        HasModuleItem, HasName, HasTypeBounds, HasVisibility,
+        ArgListOwner, AttrsOwner, CommentIter, DocCommentsOwner, GenericParamsOwner, LoopBodyOwner,
+        ModuleItemOwner, NameOwner, TypeBoundsOwner, VisibilityOwner,
     },
 };
 
@@ -118,7 +118,7 @@ mod support {
 
 #[test]
 fn assert_ast_is_object_safe() {
-    fn _f(_: &dyn AstNode, _: &dyn HasName) {}
+    fn _f(_: &dyn AstNode, _: &dyn NameOwner) {}
 }
 
 #[test]
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index d271b5f836..d6775c89ba 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -7,16 +7,16 @@ use rowan::SyntaxElement;
 
 use crate::{
     algo::neighbor,
-    ast::{self, edit::IndentLevel, make, HasGenericParams},
+    ast::{self, edit::IndentLevel, make, GenericParamsOwner},
     ted::{self, Position},
     AstNode, AstToken, Direction,
     SyntaxKind::{ATTR, COMMENT, WHITESPACE},
     SyntaxNode,
 };
 
-use super::HasName;
+use super::NameOwner;
 
-pub trait GenericParamsOwnerEdit: ast::HasGenericParams {
+pub trait GenericParamsOwnerEdit: ast::GenericParamsOwner {
     fn get_or_create_generic_param_list(&self) -> ast::GenericParamList;
     fn get_or_create_where_clause(&self) -> ast::WhereClause;
 }
@@ -194,7 +194,7 @@ fn create_generic_param_list(position: Position) -> ast::GenericParamList {
     gpl
 }
 
-pub trait AttrsOwnerEdit: ast::HasAttrs {
+pub trait AttrsOwnerEdit: ast::AttrsOwner {
     fn remove_attrs_and_docs(&self) {
         remove_attrs_and_docs(self.syntax());
 
@@ -218,7 +218,7 @@ pub trait AttrsOwnerEdit: ast::HasAttrs {
     }
 }
 
-impl<T: ast::HasAttrs> AttrsOwnerEdit for T {}
+impl<T: ast::AttrsOwner> AttrsOwnerEdit for T {}
 
 impl ast::GenericParamList {
     pub fn add_generic_param(&self, generic_param: ast::GenericParam) {
@@ -451,35 +451,6 @@ impl ast::RecordExprFieldList {
     }
 }
 
-impl ast::RecordExprField {
-    /// This will either replace the initializer, or in the case that this is a shorthand convert
-    /// the initializer into the name ref and insert the expr as the new initializer.
-    pub fn replace_expr(&self, expr: ast::Expr) {
-        if let Some(_) = self.name_ref() {
-            match self.expr() {
-                Some(prev) => ted::replace(prev.syntax(), expr.syntax()),
-                None => ted::append_child(self.syntax(), expr.syntax()),
-            }
-            return;
-        }
-        // this is a shorthand
-        if let Some(ast::Expr::PathExpr(path_expr)) = self.expr() {
-            if let Some(path) = path_expr.path() {
-                if let Some(name_ref) = path.as_single_name_ref() {
-                    path_expr.syntax().detach();
-                    let children = vec![
-                        name_ref.syntax().clone().into(),
-                        ast::make::token(T![:]).into(),
-                        ast::make::tokens::single_space().into(),
-                        expr.syntax().clone().into(),
-                    ];
-                    ted::insert_all_raw(Position::last_child_of(self.syntax()), children);
-                }
-            }
-        }
-    }
-}
-
 impl ast::StmtList {
     pub fn push_front(&self, statement: ast::Stmt) {
         ted::insert(Position::after(self.l_curly_token().unwrap()), statement.syntax());
diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs
index 7363ad905a..4f92cc0671 100644
--- a/crates/syntax/src/ast/expr_ext.rs
+++ b/crates/syntax/src/ast/expr_ext.rs
@@ -13,7 +13,7 @@ use crate::{
     SyntaxToken, T,
 };
 
-impl ast::HasAttrs for ast::Expr {}
+impl ast::AttrsOwner for ast::Expr {}
 
 impl ast::Expr {
     pub fn is_block_like(&self) -> bool {
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 5d92a0f9e5..066ad91d38 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -104,7 +104,7 @@ impl TypeArg {
 pub struct AssocTypeArg {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasTypeBounds for AssocTypeArg {}
+impl ast::TypeBoundsOwner for AssocTypeArg {}
 impl AssocTypeArg {
     pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
     pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
@@ -145,7 +145,7 @@ impl TypeBoundList {
 pub struct MacroCall {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MacroCall {}
+impl ast::AttrsOwner for MacroCall {}
 impl MacroCall {
     pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
     pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
@@ -179,7 +179,7 @@ impl TokenTree {
 pub struct MacroItems {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasModuleItem for MacroItems {}
+impl ast::ModuleItemOwner for MacroItems {}
 impl MacroItems {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct MacroStmts {
@@ -193,8 +193,8 @@ impl MacroStmts {
 pub struct SourceFile {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for SourceFile {}
-impl ast::HasModuleItem for SourceFile {}
+impl ast::AttrsOwner for SourceFile {}
+impl ast::ModuleItemOwner for SourceFile {}
 impl SourceFile {
     pub fn shebang_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![shebang]) }
 }
@@ -202,9 +202,9 @@ impl SourceFile {
 pub struct Const {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Const {}
-impl ast::HasName for Const {}
-impl ast::HasVisibility for Const {}
+impl ast::AttrsOwner for Const {}
+impl ast::NameOwner for Const {}
+impl ast::VisibilityOwner for Const {}
 impl Const {
     pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
     pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
@@ -219,10 +219,10 @@ impl Const {
 pub struct Enum {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Enum {}
-impl ast::HasName for Enum {}
-impl ast::HasVisibility for Enum {}
-impl ast::HasGenericParams for Enum {}
+impl ast::AttrsOwner for Enum {}
+impl ast::NameOwner for Enum {}
+impl ast::VisibilityOwner for Enum {}
+impl ast::GenericParamsOwner for Enum {}
 impl Enum {
     pub fn enum_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![enum]) }
     pub fn variant_list(&self) -> Option<VariantList> { support::child(&self.syntax) }
@@ -231,7 +231,7 @@ impl Enum {
 pub struct ExternBlock {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ExternBlock {}
+impl ast::AttrsOwner for ExternBlock {}
 impl ExternBlock {
     pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
     pub fn extern_item_list(&self) -> Option<ExternItemList> { support::child(&self.syntax) }
@@ -240,8 +240,8 @@ impl ExternBlock {
 pub struct ExternCrate {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ExternCrate {}
-impl ast::HasVisibility for ExternCrate {}
+impl ast::AttrsOwner for ExternCrate {}
+impl ast::VisibilityOwner for ExternCrate {}
 impl ExternCrate {
     pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
     pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
@@ -253,10 +253,10 @@ impl ExternCrate {
 pub struct Fn {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Fn {}
-impl ast::HasName for Fn {}
-impl ast::HasVisibility for Fn {}
-impl ast::HasGenericParams for Fn {}
+impl ast::AttrsOwner for Fn {}
+impl ast::NameOwner for Fn {}
+impl ast::VisibilityOwner for Fn {}
+impl ast::GenericParamsOwner for Fn {}
 impl Fn {
     pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
     pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
@@ -273,9 +273,9 @@ impl Fn {
 pub struct Impl {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Impl {}
-impl ast::HasVisibility for Impl {}
-impl ast::HasGenericParams for Impl {}
+impl ast::AttrsOwner for Impl {}
+impl ast::VisibilityOwner for Impl {}
+impl ast::GenericParamsOwner for Impl {}
 impl Impl {
     pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
     pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
@@ -289,9 +289,9 @@ impl Impl {
 pub struct MacroRules {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MacroRules {}
-impl ast::HasName for MacroRules {}
-impl ast::HasVisibility for MacroRules {}
+impl ast::AttrsOwner for MacroRules {}
+impl ast::NameOwner for MacroRules {}
+impl ast::VisibilityOwner for MacroRules {}
 impl MacroRules {
     pub fn macro_rules_token(&self) -> Option<SyntaxToken> {
         support::token(&self.syntax, T![macro_rules])
@@ -303,9 +303,9 @@ impl MacroRules {
 pub struct MacroDef {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MacroDef {}
-impl ast::HasName for MacroDef {}
-impl ast::HasVisibility for MacroDef {}
+impl ast::AttrsOwner for MacroDef {}
+impl ast::NameOwner for MacroDef {}
+impl ast::VisibilityOwner for MacroDef {}
 impl MacroDef {
     pub fn macro_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![macro]) }
     pub fn args(&self) -> Option<TokenTree> { support::child(&self.syntax) }
@@ -315,9 +315,9 @@ impl MacroDef {
 pub struct Module {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Module {}
-impl ast::HasName for Module {}
-impl ast::HasVisibility for Module {}
+impl ast::AttrsOwner for Module {}
+impl ast::NameOwner for Module {}
+impl ast::VisibilityOwner for Module {}
 impl Module {
     pub fn mod_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mod]) }
     pub fn item_list(&self) -> Option<ItemList> { support::child(&self.syntax) }
@@ -327,9 +327,9 @@ impl Module {
 pub struct Static {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Static {}
-impl ast::HasName for Static {}
-impl ast::HasVisibility for Static {}
+impl ast::AttrsOwner for Static {}
+impl ast::NameOwner for Static {}
+impl ast::VisibilityOwner for Static {}
 impl Static {
     pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) }
     pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
@@ -343,10 +343,10 @@ impl Static {
 pub struct Struct {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Struct {}
-impl ast::HasName for Struct {}
-impl ast::HasVisibility for Struct {}
-impl ast::HasGenericParams for Struct {}
+impl ast::AttrsOwner for Struct {}
+impl ast::NameOwner for Struct {}
+impl ast::VisibilityOwner for Struct {}
+impl ast::GenericParamsOwner for Struct {}
 impl Struct {
     pub fn struct_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![struct]) }
     pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
@@ -356,11 +356,11 @@ impl Struct {
 pub struct Trait {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Trait {}
-impl ast::HasName for Trait {}
-impl ast::HasVisibility for Trait {}
-impl ast::HasGenericParams for Trait {}
-impl ast::HasTypeBounds for Trait {}
+impl ast::AttrsOwner for Trait {}
+impl ast::NameOwner for Trait {}
+impl ast::VisibilityOwner for Trait {}
+impl ast::GenericParamsOwner for Trait {}
+impl ast::TypeBoundsOwner for Trait {}
 impl Trait {
     pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
     pub fn auto_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![auto]) }
@@ -371,11 +371,11 @@ impl Trait {
 pub struct TypeAlias {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for TypeAlias {}
-impl ast::HasName for TypeAlias {}
-impl ast::HasVisibility for TypeAlias {}
-impl ast::HasGenericParams for TypeAlias {}
-impl ast::HasTypeBounds for TypeAlias {}
+impl ast::AttrsOwner for TypeAlias {}
+impl ast::NameOwner for TypeAlias {}
+impl ast::VisibilityOwner for TypeAlias {}
+impl ast::GenericParamsOwner for TypeAlias {}
+impl ast::TypeBoundsOwner for TypeAlias {}
 impl TypeAlias {
     pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
     pub fn type_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![type]) }
@@ -387,10 +387,10 @@ impl TypeAlias {
 pub struct Union {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Union {}
-impl ast::HasName for Union {}
-impl ast::HasVisibility for Union {}
-impl ast::HasGenericParams for Union {}
+impl ast::AttrsOwner for Union {}
+impl ast::NameOwner for Union {}
+impl ast::VisibilityOwner for Union {}
+impl ast::GenericParamsOwner for Union {}
 impl Union {
     pub fn union_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![union]) }
     pub fn record_field_list(&self) -> Option<RecordFieldList> { support::child(&self.syntax) }
@@ -399,8 +399,8 @@ impl Union {
 pub struct Use {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Use {}
-impl ast::HasVisibility for Use {}
+impl ast::AttrsOwner for Use {}
+impl ast::VisibilityOwner for Use {}
 impl Use {
     pub fn use_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![use]) }
     pub fn use_tree(&self) -> Option<UseTree> { support::child(&self.syntax) }
@@ -421,8 +421,8 @@ impl Visibility {
 pub struct ItemList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ItemList {}
-impl ast::HasModuleItem for ItemList {}
+impl ast::AttrsOwner for ItemList {}
+impl ast::ModuleItemOwner for ItemList {}
 impl ItemList {
     pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
     pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
@@ -431,7 +431,7 @@ impl ItemList {
 pub struct Rename {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasName for Rename {}
+impl ast::NameOwner for Rename {}
 impl Rename {
     pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
     pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
@@ -475,7 +475,7 @@ impl WhereClause {
 pub struct BlockExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for BlockExpr {}
+impl ast::AttrsOwner for BlockExpr {}
 impl BlockExpr {
     pub fn label(&self) -> Option<Label> { support::child(&self.syntax) }
     pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) }
@@ -488,8 +488,8 @@ impl BlockExpr {
 pub struct SelfParam {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for SelfParam {}
-impl ast::HasName for SelfParam {}
+impl ast::AttrsOwner for SelfParam {}
+impl ast::NameOwner for SelfParam {}
 impl SelfParam {
     pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
     pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
@@ -501,7 +501,7 @@ impl SelfParam {
 pub struct Param {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Param {}
+impl ast::AttrsOwner for Param {}
 impl Param {
     pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
     pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
@@ -530,9 +530,9 @@ impl TupleFieldList {
 pub struct RecordField {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RecordField {}
-impl ast::HasName for RecordField {}
-impl ast::HasVisibility for RecordField {}
+impl ast::AttrsOwner for RecordField {}
+impl ast::NameOwner for RecordField {}
+impl ast::VisibilityOwner for RecordField {}
 impl RecordField {
     pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
@@ -541,8 +541,8 @@ impl RecordField {
 pub struct TupleField {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for TupleField {}
-impl ast::HasVisibility for TupleField {}
+impl ast::AttrsOwner for TupleField {}
+impl ast::VisibilityOwner for TupleField {}
 impl TupleField {
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 }
@@ -559,9 +559,9 @@ impl VariantList {
 pub struct Variant {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Variant {}
-impl ast::HasName for Variant {}
-impl ast::HasVisibility for Variant {}
+impl ast::AttrsOwner for Variant {}
+impl ast::NameOwner for Variant {}
+impl ast::VisibilityOwner for Variant {}
 impl Variant {
     pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) }
     pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
@@ -571,7 +571,7 @@ impl Variant {
 pub struct AssocItemList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for AssocItemList {}
+impl ast::AttrsOwner for AssocItemList {}
 impl AssocItemList {
     pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
     pub fn assoc_items(&self) -> AstChildren<AssocItem> { support::children(&self.syntax) }
@@ -581,7 +581,7 @@ impl AssocItemList {
 pub struct ExternItemList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ExternItemList {}
+impl ast::AttrsOwner for ExternItemList {}
 impl ExternItemList {
     pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
     pub fn extern_items(&self) -> AstChildren<ExternItem> { support::children(&self.syntax) }
@@ -591,8 +591,8 @@ impl ExternItemList {
 pub struct ConstParam {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ConstParam {}
-impl ast::HasName for ConstParam {}
+impl ast::AttrsOwner for ConstParam {}
+impl ast::NameOwner for ConstParam {}
 impl ConstParam {
     pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
     pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
@@ -604,8 +604,8 @@ impl ConstParam {
 pub struct LifetimeParam {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for LifetimeParam {}
-impl ast::HasTypeBounds for LifetimeParam {}
+impl ast::AttrsOwner for LifetimeParam {}
+impl ast::TypeBoundsOwner for LifetimeParam {}
 impl LifetimeParam {
     pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 }
@@ -613,9 +613,9 @@ impl LifetimeParam {
 pub struct TypeParam {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for TypeParam {}
-impl ast::HasName for TypeParam {}
-impl ast::HasTypeBounds for TypeParam {}
+impl ast::AttrsOwner for TypeParam {}
+impl ast::NameOwner for TypeParam {}
+impl ast::TypeBoundsOwner for TypeParam {}
 impl TypeParam {
     pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
     pub fn default_type(&self) -> Option<Type> { support::child(&self.syntax) }
@@ -624,7 +624,7 @@ impl TypeParam {
 pub struct WherePred {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasTypeBounds for WherePred {}
+impl ast::TypeBoundsOwner for WherePred {}
 impl WherePred {
     pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
     pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
@@ -653,7 +653,7 @@ impl ExprStmt {
 pub struct LetStmt {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for LetStmt {}
+impl ast::AttrsOwner for LetStmt {}
 impl LetStmt {
     pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
     pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
@@ -667,7 +667,7 @@ impl LetStmt {
 pub struct ArrayExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ArrayExpr {}
+impl ast::AttrsOwner for ArrayExpr {}
 impl ArrayExpr {
     pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
     pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
@@ -679,7 +679,7 @@ impl ArrayExpr {
 pub struct AwaitExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for AwaitExpr {}
+impl ast::AttrsOwner for AwaitExpr {}
 impl AwaitExpr {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
@@ -689,13 +689,13 @@ impl AwaitExpr {
 pub struct BinExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for BinExpr {}
+impl ast::AttrsOwner for BinExpr {}
 impl BinExpr {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct BoxExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for BoxExpr {}
+impl ast::AttrsOwner for BoxExpr {}
 impl BoxExpr {
     pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) }
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
@@ -704,7 +704,7 @@ impl BoxExpr {
 pub struct BreakExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for BreakExpr {}
+impl ast::AttrsOwner for BreakExpr {}
 impl BreakExpr {
     pub fn break_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![break]) }
     pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
@@ -714,8 +714,8 @@ impl BreakExpr {
 pub struct CallExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for CallExpr {}
-impl ast::HasArgList for CallExpr {}
+impl ast::AttrsOwner for CallExpr {}
+impl ast::ArgListOwner for CallExpr {}
 impl CallExpr {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
@@ -723,7 +723,7 @@ impl CallExpr {
 pub struct CastExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for CastExpr {}
+impl ast::AttrsOwner for CastExpr {}
 impl CastExpr {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
@@ -733,7 +733,7 @@ impl CastExpr {
 pub struct ClosureExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ClosureExpr {}
+impl ast::AttrsOwner for ClosureExpr {}
 impl ClosureExpr {
     pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) }
     pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
@@ -746,7 +746,7 @@ impl ClosureExpr {
 pub struct ContinueExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ContinueExpr {}
+impl ast::AttrsOwner for ContinueExpr {}
 impl ContinueExpr {
     pub fn continue_token(&self) -> Option<SyntaxToken> {
         support::token(&self.syntax, T![continue])
@@ -757,7 +757,7 @@ impl ContinueExpr {
 pub struct FieldExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for FieldExpr {}
+impl ast::AttrsOwner for FieldExpr {}
 impl FieldExpr {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
@@ -767,8 +767,8 @@ impl FieldExpr {
 pub struct ForExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ForExpr {}
-impl ast::HasLoopBody for ForExpr {}
+impl ast::AttrsOwner for ForExpr {}
+impl ast::LoopBodyOwner for ForExpr {}
 impl ForExpr {
     pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
     pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
@@ -779,7 +779,7 @@ impl ForExpr {
 pub struct IfExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for IfExpr {}
+impl ast::AttrsOwner for IfExpr {}
 impl IfExpr {
     pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
     pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) }
@@ -789,7 +789,7 @@ impl IfExpr {
 pub struct IndexExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for IndexExpr {}
+impl ast::AttrsOwner for IndexExpr {}
 impl IndexExpr {
     pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
     pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
@@ -798,14 +798,14 @@ impl IndexExpr {
 pub struct Literal {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for Literal {}
+impl ast::AttrsOwner for Literal {}
 impl Literal {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct LoopExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for LoopExpr {}
-impl ast::HasLoopBody for LoopExpr {}
+impl ast::AttrsOwner for LoopExpr {}
+impl ast::LoopBodyOwner for LoopExpr {}
 impl LoopExpr {
     pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) }
 }
@@ -813,7 +813,7 @@ impl LoopExpr {
 pub struct MatchExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MatchExpr {}
+impl ast::AttrsOwner for MatchExpr {}
 impl MatchExpr {
     pub fn match_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![match]) }
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
@@ -823,8 +823,8 @@ impl MatchExpr {
 pub struct MethodCallExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MethodCallExpr {}
-impl ast::HasArgList for MethodCallExpr {}
+impl ast::AttrsOwner for MethodCallExpr {}
+impl ast::ArgListOwner for MethodCallExpr {}
 impl MethodCallExpr {
     pub fn receiver(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
@@ -835,7 +835,7 @@ impl MethodCallExpr {
 pub struct ParenExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ParenExpr {}
+impl ast::AttrsOwner for ParenExpr {}
 impl ParenExpr {
     pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
@@ -845,7 +845,7 @@ impl ParenExpr {
 pub struct PathExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for PathExpr {}
+impl ast::AttrsOwner for PathExpr {}
 impl PathExpr {
     pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 }
@@ -853,7 +853,7 @@ impl PathExpr {
 pub struct PrefixExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for PrefixExpr {}
+impl ast::AttrsOwner for PrefixExpr {}
 impl PrefixExpr {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
@@ -861,7 +861,7 @@ impl PrefixExpr {
 pub struct RangeExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RangeExpr {}
+impl ast::AttrsOwner for RangeExpr {}
 impl RangeExpr {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct RecordExpr {
@@ -877,7 +877,7 @@ impl RecordExpr {
 pub struct RefExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RefExpr {}
+impl ast::AttrsOwner for RefExpr {}
 impl RefExpr {
     pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
     pub fn raw_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![raw]) }
@@ -889,7 +889,7 @@ impl RefExpr {
 pub struct ReturnExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for ReturnExpr {}
+impl ast::AttrsOwner for ReturnExpr {}
 impl ReturnExpr {
     pub fn return_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![return]) }
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
@@ -898,7 +898,7 @@ impl ReturnExpr {
 pub struct TryExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for TryExpr {}
+impl ast::AttrsOwner for TryExpr {}
 impl TryExpr {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
@@ -907,7 +907,7 @@ impl TryExpr {
 pub struct TupleExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for TupleExpr {}
+impl ast::AttrsOwner for TupleExpr {}
 impl TupleExpr {
     pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
     pub fn fields(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
@@ -917,8 +917,8 @@ impl TupleExpr {
 pub struct WhileExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for WhileExpr {}
-impl ast::HasLoopBody for WhileExpr {}
+impl ast::AttrsOwner for WhileExpr {}
+impl ast::LoopBodyOwner for WhileExpr {}
 impl WhileExpr {
     pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
     pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) }
@@ -927,7 +927,7 @@ impl WhileExpr {
 pub struct YieldExpr {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for YieldExpr {}
+impl ast::AttrsOwner for YieldExpr {}
 impl YieldExpr {
     pub fn yield_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![yield]) }
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
@@ -936,7 +936,7 @@ impl YieldExpr {
 pub struct StmtList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for StmtList {}
+impl ast::AttrsOwner for StmtList {}
 impl StmtList {
     pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
     pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
@@ -955,7 +955,7 @@ impl Label {
 pub struct RecordExprFieldList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RecordExprFieldList {}
+impl ast::AttrsOwner for RecordExprFieldList {}
 impl RecordExprFieldList {
     pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
     pub fn fields(&self) -> AstChildren<RecordExprField> { support::children(&self.syntax) }
@@ -967,7 +967,7 @@ impl RecordExprFieldList {
 pub struct RecordExprField {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RecordExprField {}
+impl ast::AttrsOwner for RecordExprField {}
 impl RecordExprField {
     pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
     pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
@@ -996,7 +996,7 @@ impl Condition {
 pub struct MatchArmList {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MatchArmList {}
+impl ast::AttrsOwner for MatchArmList {}
 impl MatchArmList {
     pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
     pub fn arms(&self) -> AstChildren<MatchArm> { support::children(&self.syntax) }
@@ -1006,7 +1006,7 @@ impl MatchArmList {
 pub struct MatchArm {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for MatchArm {}
+impl ast::AttrsOwner for MatchArm {}
 impl MatchArm {
     pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
     pub fn guard(&self) -> Option<MatchGuard> { support::child(&self.syntax) }
@@ -1155,8 +1155,8 @@ impl TypeBound {
 pub struct IdentPat {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for IdentPat {}
-impl ast::HasName for IdentPat {}
+impl ast::AttrsOwner for IdentPat {}
+impl ast::NameOwner for IdentPat {}
 impl IdentPat {
     pub fn ref_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ref]) }
     pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
@@ -1296,7 +1296,7 @@ impl RecordPatFieldList {
 pub struct RecordPatField {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for RecordPatField {}
+impl ast::AttrsOwner for RecordPatField {}
 impl RecordPatField {
     pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
     pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
@@ -1379,7 +1379,7 @@ pub enum Item {
     Union(Union),
     Use(Use),
 }
-impl ast::HasAttrs for Item {}
+impl ast::AttrsOwner for Item {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Stmt {
     ExprStmt(ExprStmt),
@@ -1416,10 +1416,10 @@ pub enum Adt {
     Struct(Struct),
     Union(Union),
 }
-impl ast::HasAttrs for Adt {}
-impl ast::HasGenericParams for Adt {}
-impl ast::HasName for Adt {}
-impl ast::HasVisibility for Adt {}
+impl ast::AttrsOwner for Adt {}
+impl ast::GenericParamsOwner for Adt {}
+impl ast::NameOwner for Adt {}
+impl ast::VisibilityOwner for Adt {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum AssocItem {
     Const(Const),
@@ -1427,7 +1427,7 @@ pub enum AssocItem {
     MacroCall(MacroCall),
     TypeAlias(TypeAlias),
 }
-impl ast::HasAttrs for AssocItem {}
+impl ast::AttrsOwner for AssocItem {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum ExternItem {
     Fn(Fn),
@@ -1435,54 +1435,54 @@ pub enum ExternItem {
     Static(Static),
     TypeAlias(TypeAlias),
 }
-impl ast::HasAttrs for ExternItem {}
+impl ast::AttrsOwner for ExternItem {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum GenericParam {
     ConstParam(ConstParam),
     LifetimeParam(LifetimeParam),
     TypeParam(TypeParam),
 }
-impl ast::HasAttrs for GenericParam {}
+impl ast::AttrsOwner for GenericParam {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AnyHasArgList {
+pub struct DynArgListOwner {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasArgList for AnyHasArgList {}
+impl ast::ArgListOwner for DynArgListOwner {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AnyHasAttrs {
+pub struct DynAttrsOwner {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasAttrs for AnyHasAttrs {}
+impl ast::AttrsOwner for DynAttrsOwner {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AnyHasGenericParams {
+pub struct DynGenericParamsOwner {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasGenericParams for AnyHasGenericParams {}
+impl ast::GenericParamsOwner for DynGenericParamsOwner {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AnyHasLoopBody {
+pub struct DynLoopBodyOwner {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasLoopBody for AnyHasLoopBody {}
+impl ast::LoopBodyOwner for DynLoopBodyOwner {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AnyHasModuleItem {
+pub struct DynModuleItemOwner {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasModuleItem for AnyHasModuleItem {}
+impl ast::ModuleItemOwner for DynModuleItemOwner {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AnyHasName {
+pub struct DynNameOwner {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasName for AnyHasName {}
+impl ast::NameOwner for DynNameOwner {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AnyHasTypeBounds {
+pub struct DynTypeBoundsOwner {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasTypeBounds for AnyHasTypeBounds {}
+impl ast::TypeBoundsOwner for DynTypeBoundsOwner {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AnyHasVisibility {
+pub struct DynVisibilityOwner {
     pub(crate) syntax: SyntaxNode,
 }
-impl ast::HasVisibility for AnyHasVisibility {}
+impl ast::VisibilityOwner for DynVisibilityOwner {}
 impl AstNode for Name {
     fn can_cast(kind: SyntaxKind) -> bool { kind == NAME }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3597,13 +3597,13 @@ impl AstNode for GenericParam {
         }
     }
 }
-impl AnyHasArgList {
+impl DynArgListOwner {
     #[inline]
-    pub fn new<T: ast::HasArgList>(node: T) -> AnyHasArgList {
-        AnyHasArgList { syntax: node.syntax().clone() }
+    pub fn new<T: ast::ArgListOwner>(node: T) -> DynArgListOwner {
+        DynArgListOwner { syntax: node.syntax().clone() }
     }
 }
-impl AstNode for AnyHasArgList {
+impl AstNode for DynArgListOwner {
     fn can_cast(kind: SyntaxKind) -> bool {
         match kind {
             CALL_EXPR | METHOD_CALL_EXPR => true,
@@ -3611,17 +3611,17 @@ impl AstNode for AnyHasArgList {
         }
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        Self::can_cast(syntax.kind()).then(|| AnyHasArgList { syntax })
+        Self::can_cast(syntax.kind()).then(|| DynArgListOwner { syntax })
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AnyHasAttrs {
+impl DynAttrsOwner {
     #[inline]
-    pub fn new<T: ast::HasAttrs>(node: T) -> AnyHasAttrs {
-        AnyHasAttrs { syntax: node.syntax().clone() }
+    pub fn new<T: ast::AttrsOwner>(node: T) -> DynAttrsOwner {
+        DynAttrsOwner { syntax: node.syntax().clone() }
     }
 }
-impl AstNode for AnyHasAttrs {
+impl AstNode for DynAttrsOwner {
     fn can_cast(kind: SyntaxKind) -> bool {
         match kind {
             MACRO_CALL
@@ -3692,17 +3692,17 @@ impl AstNode for AnyHasAttrs {
         }
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        Self::can_cast(syntax.kind()).then(|| AnyHasAttrs { syntax })
+        Self::can_cast(syntax.kind()).then(|| DynAttrsOwner { syntax })
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AnyHasGenericParams {
+impl DynGenericParamsOwner {
     #[inline]
-    pub fn new<T: ast::HasGenericParams>(node: T) -> AnyHasGenericParams {
-        AnyHasGenericParams { syntax: node.syntax().clone() }
+    pub fn new<T: ast::GenericParamsOwner>(node: T) -> DynGenericParamsOwner {
+        DynGenericParamsOwner { syntax: node.syntax().clone() }
     }
 }
-impl AstNode for AnyHasGenericParams {
+impl AstNode for DynGenericParamsOwner {
     fn can_cast(kind: SyntaxKind) -> bool {
         match kind {
             ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION => true,
@@ -3710,17 +3710,17 @@ impl AstNode for AnyHasGenericParams {
         }
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        Self::can_cast(syntax.kind()).then(|| AnyHasGenericParams { syntax })
+        Self::can_cast(syntax.kind()).then(|| DynGenericParamsOwner { syntax })
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AnyHasLoopBody {
+impl DynLoopBodyOwner {
     #[inline]
-    pub fn new<T: ast::HasLoopBody>(node: T) -> AnyHasLoopBody {
-        AnyHasLoopBody { syntax: node.syntax().clone() }
+    pub fn new<T: ast::LoopBodyOwner>(node: T) -> DynLoopBodyOwner {
+        DynLoopBodyOwner { syntax: node.syntax().clone() }
     }
 }
-impl AstNode for AnyHasLoopBody {
+impl AstNode for DynLoopBodyOwner {
     fn can_cast(kind: SyntaxKind) -> bool {
         match kind {
             FOR_EXPR | LOOP_EXPR | WHILE_EXPR => true,
@@ -3728,17 +3728,17 @@ impl AstNode for AnyHasLoopBody {
         }
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        Self::can_cast(syntax.kind()).then(|| AnyHasLoopBody { syntax })
+        Self::can_cast(syntax.kind()).then(|| DynLoopBodyOwner { syntax })
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AnyHasModuleItem {
+impl DynModuleItemOwner {
     #[inline]
-    pub fn new<T: ast::HasModuleItem>(node: T) -> AnyHasModuleItem {
-        AnyHasModuleItem { syntax: node.syntax().clone() }
+    pub fn new<T: ast::ModuleItemOwner>(node: T) -> DynModuleItemOwner {
+        DynModuleItemOwner { syntax: node.syntax().clone() }
     }
 }
-impl AstNode for AnyHasModuleItem {
+impl AstNode for DynModuleItemOwner {
     fn can_cast(kind: SyntaxKind) -> bool {
         match kind {
             MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => true,
@@ -3746,17 +3746,17 @@ impl AstNode for AnyHasModuleItem {
         }
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        Self::can_cast(syntax.kind()).then(|| AnyHasModuleItem { syntax })
+        Self::can_cast(syntax.kind()).then(|| DynModuleItemOwner { syntax })
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AnyHasName {
+impl DynNameOwner {
     #[inline]
-    pub fn new<T: ast::HasName>(node: T) -> AnyHasName {
-        AnyHasName { syntax: node.syntax().clone() }
+    pub fn new<T: ast::NameOwner>(node: T) -> DynNameOwner {
+        DynNameOwner { syntax: node.syntax().clone() }
     }
 }
-impl AstNode for AnyHasName {
+impl AstNode for DynNameOwner {
     fn can_cast(kind: SyntaxKind) -> bool {
         match kind {
             CONST | ENUM | FN | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT
@@ -3766,17 +3766,17 @@ impl AstNode for AnyHasName {
         }
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        Self::can_cast(syntax.kind()).then(|| AnyHasName { syntax })
+        Self::can_cast(syntax.kind()).then(|| DynNameOwner { syntax })
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AnyHasTypeBounds {
+impl DynTypeBoundsOwner {
     #[inline]
-    pub fn new<T: ast::HasTypeBounds>(node: T) -> AnyHasTypeBounds {
-        AnyHasTypeBounds { syntax: node.syntax().clone() }
+    pub fn new<T: ast::TypeBoundsOwner>(node: T) -> DynTypeBoundsOwner {
+        DynTypeBoundsOwner { syntax: node.syntax().clone() }
     }
 }
-impl AstNode for AnyHasTypeBounds {
+impl AstNode for DynTypeBoundsOwner {
     fn can_cast(kind: SyntaxKind) -> bool {
         match kind {
             ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED => true,
@@ -3784,17 +3784,17 @@ impl AstNode for AnyHasTypeBounds {
         }
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        Self::can_cast(syntax.kind()).then(|| AnyHasTypeBounds { syntax })
+        Self::can_cast(syntax.kind()).then(|| DynTypeBoundsOwner { syntax })
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AnyHasVisibility {
+impl DynVisibilityOwner {
     #[inline]
-    pub fn new<T: ast::HasVisibility>(node: T) -> AnyHasVisibility {
-        AnyHasVisibility { syntax: node.syntax().clone() }
+    pub fn new<T: ast::VisibilityOwner>(node: T) -> DynVisibilityOwner {
+        DynVisibilityOwner { syntax: node.syntax().clone() }
     }
 }
-impl AstNode for AnyHasVisibility {
+impl AstNode for DynVisibilityOwner {
     fn can_cast(kind: SyntaxKind) -> bool {
         match kind {
             CONST | ENUM | EXTERN_CRATE | FN | IMPL | MACRO_RULES | MACRO_DEF | MODULE | STATIC
@@ -3805,7 +3805,7 @@ impl AstNode for AnyHasVisibility {
         }
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
-        Self::can_cast(syntax.kind()).then(|| AnyHasVisibility { syntax })
+        Self::can_cast(syntax.kind()).then(|| DynVisibilityOwner { syntax })
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index a07f02e445..cb3bdaac1b 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -11,8 +11,8 @@ use rowan::{GreenNodeData, GreenTokenData};
 
 use crate::{
     ast::{
-        self, support, AstNode, AstToken, HasAttrs, HasGenericParams, HasModuleItem, HasName,
-        SyntaxNode,
+        self, support, AstNode, AstToken, AttrsOwner, GenericParamsOwner, ModuleItemOwner,
+        NameOwner, SyntaxNode,
     },
     NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T,
 };
@@ -50,7 +50,7 @@ fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
     }
 }
 
-impl ast::HasModuleItem for ast::StmtList {}
+impl ast::ModuleItemOwner for ast::StmtList {}
 
 impl ast::BlockExpr {
     // FIXME: remove all these methods, they belong to ast::StmtList
@@ -107,7 +107,7 @@ impl AstNode for Macro {
     }
 }
 
-impl HasName for Macro {
+impl NameOwner for Macro {
     fn name(&self) -> Option<ast::Name> {
         match self {
             Macro::MacroRules(mac) => mac.name(),
@@ -116,7 +116,7 @@ impl HasName for Macro {
     }
 }
 
-impl HasAttrs for Macro {}
+impl AttrsOwner for Macro {}
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum AttrKind {
@@ -531,7 +531,7 @@ impl ast::Variant {
 
 impl ast::Item {
     pub fn generic_param_list(&self) -> Option<ast::GenericParamList> {
-        ast::AnyHasGenericParams::cast(self.syntax().clone())?.generic_param_list()
+        ast::DynGenericParamsOwner::cast(self.syntax().clone())?.generic_param_list()
     }
 }
 
@@ -765,21 +765,21 @@ impl ast::GenericParamList {
     }
 }
 
-impl ast::HasDocComments for ast::SourceFile {}
-impl ast::HasDocComments for ast::Fn {}
-impl ast::HasDocComments for ast::Struct {}
-impl ast::HasDocComments for ast::Union {}
-impl ast::HasDocComments for ast::RecordField {}
-impl ast::HasDocComments for ast::TupleField {}
-impl ast::HasDocComments for ast::Enum {}
-impl ast::HasDocComments for ast::Variant {}
-impl ast::HasDocComments for ast::Trait {}
-impl ast::HasDocComments for ast::Module {}
-impl ast::HasDocComments for ast::Static {}
-impl ast::HasDocComments for ast::Const {}
-impl ast::HasDocComments for ast::TypeAlias {}
-impl ast::HasDocComments for ast::Impl {}
-impl ast::HasDocComments for ast::MacroRules {}
-impl ast::HasDocComments for ast::MacroDef {}
-impl ast::HasDocComments for ast::Macro {}
-impl ast::HasDocComments for ast::Use {}
+impl ast::DocCommentsOwner for ast::SourceFile {}
+impl ast::DocCommentsOwner for ast::Fn {}
+impl ast::DocCommentsOwner for ast::Struct {}
+impl ast::DocCommentsOwner for ast::Union {}
+impl ast::DocCommentsOwner for ast::RecordField {}
+impl ast::DocCommentsOwner for ast::TupleField {}
+impl ast::DocCommentsOwner for ast::Enum {}
+impl ast::DocCommentsOwner for ast::Variant {}
+impl ast::DocCommentsOwner for ast::Trait {}
+impl ast::DocCommentsOwner for ast::Module {}
+impl ast::DocCommentsOwner for ast::Static {}
+impl ast::DocCommentsOwner for ast::Const {}
+impl ast::DocCommentsOwner for ast::TypeAlias {}
+impl ast::DocCommentsOwner for ast::Impl {}
+impl ast::DocCommentsOwner for ast::MacroRules {}
+impl ast::DocCommentsOwner for ast::MacroDef {}
+impl ast::DocCommentsOwner for ast::Macro {}
+impl ast::DocCommentsOwner for ast::Use {}
diff --git a/crates/syntax/src/ast/traits.rs b/crates/syntax/src/ast/traits.rs
index eae3a7e2fe..ddd2136370 100644
--- a/crates/syntax/src/ast/traits.rs
+++ b/crates/syntax/src/ast/traits.rs
@@ -7,19 +7,19 @@ use crate::{
     SyntaxToken, T,
 };
 
-pub trait HasName: AstNode {
+pub trait NameOwner: AstNode {
     fn name(&self) -> Option<ast::Name> {
         support::child(self.syntax())
     }
 }
 
-pub trait HasVisibility: AstNode {
+pub trait VisibilityOwner: AstNode {
     fn visibility(&self) -> Option<ast::Visibility> {
         support::child(self.syntax())
     }
 }
 
-pub trait HasLoopBody: AstNode {
+pub trait LoopBodyOwner: AstNode {
     fn loop_body(&self) -> Option<ast::BlockExpr> {
         support::child(self.syntax())
     }
@@ -29,19 +29,19 @@ pub trait HasLoopBody: AstNode {
     }
 }
 
-pub trait HasArgList: AstNode {
+pub trait ArgListOwner: AstNode {
     fn arg_list(&self) -> Option<ast::ArgList> {
         support::child(self.syntax())
     }
 }
 
-pub trait HasModuleItem: AstNode {
+pub trait ModuleItemOwner: AstNode {
     fn items(&self) -> AstChildren<ast::Item> {
         support::children(self.syntax())
     }
 }
 
-pub trait HasGenericParams: AstNode {
+pub trait GenericParamsOwner: AstNode {
     fn generic_param_list(&self) -> Option<ast::GenericParamList> {
         support::child(self.syntax())
     }
@@ -51,7 +51,7 @@ pub trait HasGenericParams: AstNode {
     }
 }
 
-pub trait HasTypeBounds: AstNode {
+pub trait TypeBoundsOwner: AstNode {
     fn type_bound_list(&self) -> Option<ast::TypeBoundList> {
         support::child(self.syntax())
     }
@@ -61,7 +61,7 @@ pub trait HasTypeBounds: AstNode {
     }
 }
 
-pub trait HasAttrs: AstNode {
+pub trait AttrsOwner: AstNode {
     fn attrs(&self) -> AstChildren<ast::Attr> {
         support::children(self.syntax())
     }
@@ -70,7 +70,7 @@ pub trait HasAttrs: AstNode {
     }
 }
 
-pub trait HasDocComments: HasAttrs {
+pub trait DocCommentsOwner: AttrsOwner {
     fn doc_comments(&self) -> CommentIter {
         CommentIter { iter: self.syntax().children_with_tokens() }
     }
diff --git a/crates/syntax/src/display.rs b/crates/syntax/src/display.rs
index 1498385fef..2422da23f4 100644
--- a/crates/syntax/src/display.rs
+++ b/crates/syntax/src/display.rs
@@ -2,11 +2,11 @@
 //! into types that may be used to render in a UI.
 
 use crate::{
-    ast::{self, AstNode, HasAttrs, HasGenericParams, HasName},
+    ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner},
     SyntaxKind::{ATTR, COMMENT},
 };
 
-use ast::HasVisibility;
+use ast::VisibilityOwner;
 use stdx::format_to;
 
 pub fn function_declaration(node: &ast::Fn) -> String {
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index 132d300674..00749d742f 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -255,7 +255,7 @@ macro_rules! match_ast {
 /// API.
 #[test]
 fn api_walkthrough() {
-    use ast::{HasModuleItem, HasName};
+    use ast::{ModuleItemOwner, NameOwner};
 
     let source_code = "
         fn foo() {
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index b2d42f6651..a7c469ffdf 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -13,7 +13,7 @@ use rustc_lexer::unescape::{
 
 use crate::{
     algo,
-    ast::{self, HasVisibility},
+    ast::{self, VisibilityOwner},
     match_ast, AstNode, SyntaxError,
     SyntaxKind::{CONST, FN, INT_NUMBER, TYPE_ALIAS},
     SyntaxNode, SyntaxToken, TextSize, T,
diff --git a/crates/syntax/src/validation/block.rs b/crates/syntax/src/validation/block.rs
index 9076b82503..e03a77749d 100644
--- a/crates/syntax/src/validation/block.rs
+++ b/crates/syntax/src/validation/block.rs
@@ -1,7 +1,7 @@
 //! Logic for validating block expressions i.e. `ast::BlockExpr`.
 
 use crate::{
-    ast::{self, AstNode, HasAttrs},
+    ast::{self, AstNode, AttrsOwner},
     SyntaxError,
     SyntaxKind::*,
 };
diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs
index 66180bb156..f457881f2e 100644
--- a/crates/tt/src/lib.rs
+++ b/crates/tt/src/lib.rs
@@ -274,36 +274,3 @@ impl Subtree {
 }
 
 pub mod buffer;
-
-pub fn pretty(tkns: &[TokenTree]) -> String {
-    fn tokentree_to_text(tkn: &TokenTree) -> String {
-        match tkn {
-            TokenTree::Leaf(Leaf::Ident(ident)) => ident.text.clone().into(),
-            TokenTree::Leaf(Leaf::Literal(literal)) => literal.text.clone().into(),
-            TokenTree::Leaf(Leaf::Punct(punct)) => format!("{}", punct.char),
-            TokenTree::Subtree(subtree) => {
-                let content = pretty(&subtree.token_trees);
-                let (open, close) = match subtree.delimiter.map(|it| it.kind) {
-                    None => ("", ""),
-                    Some(DelimiterKind::Brace) => ("{", "}"),
-                    Some(DelimiterKind::Parenthesis) => ("(", ")"),
-                    Some(DelimiterKind::Bracket) => ("[", "]"),
-                };
-                format!("{}{}{}", open, content, close)
-            }
-        }
-    }
-
-    tkns.iter()
-        .fold((String::new(), true), |(last, last_to_joint), tkn| {
-            let s = [last, tokentree_to_text(tkn)].join(if last_to_joint { "" } else { " " });
-            let mut is_joint = false;
-            if let TokenTree::Leaf(Leaf::Punct(punct)) = tkn {
-                if punct.spacing == Spacing::Joint {
-                    is_joint = true;
-                }
-            }
-            (s, is_joint)
-        })
-        .0
-}
diff --git a/crates/vfs/src/vfs_path.rs b/crates/vfs/src/vfs_path.rs
index ffd673573a..0ad56e00d7 100644
--- a/crates/vfs/src/vfs_path.rs
+++ b/crates/vfs/src/vfs_path.rs
@@ -359,7 +359,6 @@ impl VirtualPath {
             }
             path = &path["../".len()..]
         }
-        path = path.trim_start_matches("./");
         res.0 = format!("{}/{}", res.0, path);
         Some(res)
     }
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 768216fed9..5e7b722226 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -191,7 +191,7 @@ List of warnings that should be displayed with info severity.
 The warnings will be indicated by a blue squiggly underline in code
 and a blue icon in the `Problems Panel`.
 --
-[[rust-analyzer.experimental.procAttrMacros]]rust-analyzer.experimental.procAttrMacros (default: `true`)::
+[[rust-analyzer.experimental.procAttrMacros]]rust-analyzer.experimental.procAttrMacros (default: `false`)::
 +
 --
 Expand attribute macros.
diff --git a/editors/code/package.json b/editors/code/package.json
index a9593024d4..541293ff12 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -641,7 +641,7 @@
                 },
                 "rust-analyzer.experimental.procAttrMacros": {
                     "markdownDescription": "Expand attribute macros.",
-                    "default": true,
+                    "default": false,
                     "type": "boolean"
                 },
                 "rust-analyzer.files.watcher": {


Test patch:
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 7671ccefd1..a153e17b17 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -340,11 +340,12 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
                 T: 'b
             {
                 // flags = 0x2
-                pub(self) fn f<G>(
+                pub(self) fn f<G, _anon_1>(
                     _: impl Copy,
                 ) -> impl Copy
                 where
-                    G: 'a;
+                    G: 'a,
+                    _anon_1: Copy;
             }
 
             pub(self) enum Enum<'a, T, const U: u8> {
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index cf6833e56a..af6e773217 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -26,7 +26,7 @@ use hir_expand::{db::AstDatabase, InFile};
 use once_cell::race::OnceBool;
 use stdx::format_to;
 use syntax::{
-    ast::{self, AstNode, HasName},
+    ast::{self, AstNode, NameOwner},
     SyntaxNode,
 };
 use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 2f38d584a1..618499fdc1 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1177,24 +1177,3 @@ fn multiexp_inner() {
         "#,
     );
 }
-
-#[test]
-fn macro_expands_to_impl_trait() {
-    check_no_mismatches(
-        r#"
-trait Foo {}
-
-macro_rules! ty {
-    () => {
-        impl Foo
-    }
-}
-
-fn foo(_: ty!()) {}
-
-fn bar() {
-    foo(());
-}
-    "#,
-    )
-}
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index 7f3c93d740..e211b09987 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -169,7 +169,7 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label:
                 let sr = db.source_root(sr);
                 let mut base = sr.path_for_file(&dst.anchor).unwrap().clone();
                 base.pop();
-                let created_file_path = base.join(&dst.path).unwrap();
+                let created_file_path = format!("{}{}", base.to_string(), &dst.path[1..]);
                 format_to!(buf, "//- {}\n", created_file_path);
                 buf.push_str(&contents);
             }
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index 9ad7b6097a..87b3be3498 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -1296,22 +1296,6 @@ fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
     )
 }
 
-#[test]
-fn doctest_move_from_mod_rs() {
-    check_doc_test(
-        "move_from_mod_rs",
-        r#####"
-//- /main.rs
-mod a;
-//- /a/mod.rs
-$0fn t() {}$0
-"#####,
-        r#####"
-fn t() {}
-"#####,
-    )
-}
-
 #[test]
 fn doctest_move_guard_to_arm_body() {
     check_doc_test(
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 26924fa8f3..e6ac9754da 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -238,7 +238,7 @@ fn debug_dump_ignore_spaces(node: &syntax::SyntaxNode) -> String {
 
 #[test]
 fn test_node_to_tt_censor() {
-    use syntax::ast::{HasAttrs, HasModuleItem};
+    use syntax::ast::{AttrsOwner, ModuleItemOwner};
 
     let source = r##"
 #[attr0]
diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs
index f8f7a3ad32..ca48ca14e4 100644
--- a/crates/syntax/src/tests.rs
+++ b/crates/syntax/src/tests.rs
@@ -8,7 +8,7 @@ use std::{
     path::{Path, PathBuf},
 };
 
-use ast::HasName;
+use ast::NameOwner;
 use expect_test::expect_file;
 use rayon::prelude::*;
 use test_utils::{bench, bench_fixture, project_root};
diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs
index 564cf6663c..07213b08be 100644
--- a/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/crates/syntax/src/tests/sourcegen_ast.rs
@@ -209,7 +209,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
         })
         .unzip();
 
-    let (any_node_defs, any_node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
+    let (dyn_node_defs, dyn_node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
         .nodes
         .iter()
         .flat_map(|node| node.traits.iter().map(move |t| (t, node)))
@@ -217,7 +217,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
         .into_iter()
         .sorted_by_key(|(k, _)| k.clone())
         .map(|(trait_name, nodes)| {
-            let name = format_ident!("Any{}", trait_name);
+            let name = format_ident!("Dyn{}", trait_name);
             let trait_name = format_ident!("{}", trait_name);
             let kinds: Vec<_> = nodes
                 .iter()
@@ -297,10 +297,10 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
 
         #(#node_defs)*
         #(#enum_defs)*
-        #(#any_node_defs)*
+        #(#dyn_node_defs)*
         #(#node_boilerplate_impls)*
         #(#enum_boilerplate_impls)*
-        #(#any_node_boilerplate_impls)*
+        #(#dyn_node_boilerplate_impls)*
         #(#display_impls)*
     };
 
@@ -740,14 +740,14 @@ fn extract_enums(ast: &mut AstSrc) {
 
 fn extract_struct_traits(ast: &mut AstSrc) {
     let traits: &[(&str, &[&str])] = &[
-        ("HasAttrs", &["attrs"]),
-        ("HasName", &["name"]),
-        ("HasVisibility", &["visibility"]),
-        ("HasGenericParams", &["generic_param_list", "where_clause"]),
-        ("HasTypeBounds", &["type_bound_list", "colon_token"]),
-        ("HasModuleItem", &["items"]),
-        ("HasLoopBody", &["label", "loop_body"]),
-        ("HasArgList", &["arg_list"]),
+        ("AttrsOwner", &["attrs"]),
+        ("NameOwner", &["name"]),
+        ("VisibilityOwner", &["visibility"]),
+        ("GenericParamsOwner", &["generic_param_list", "where_clause"]),
+        ("TypeBoundsOwner", &["type_bound_list", "colon_token"]),
+        ("ModuleItemOwner", &["items"]),
+        ("LoopBodyOwner", &["label", "loop_body"]),
+        ("ArgListOwner", &["arg_list"]),
     ];
 
     for node in &mut ast.nodes {