Repository: rust-analyzer/rust-analyzer
Pull request #11630 (2022-03-05 22:20:29)

fix: Recognize `Self` as a proper keyword
Fixes https://github.com/rust-analyzer/rust-analyzer/issues/11627


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 9cc5a73c96..f1b559f405 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1833,9 +1833,9 @@ checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
 
 [[package]]
 name = "ungrammar"
-version = "1.16.0"
+version = "1.16.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a62374cbbda72c1459ce5e7bfcdf1bd284c812a4faf2324aa083e5d9ea87880f"
+checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f"
 
 [[package]]
 name = "unicase"
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 2e0dbf82b7..80205f7fbc 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -10,7 +10,10 @@ use hir_def::{
     resolver::{self, HasResolver, Resolver, TypeNs},
     AsMacroCall, FunctionId, TraitId, VariantId,
 };
-use hir_expand::{name::AsName, ExpansionInfo, MacroCallId};
+use hir_expand::{
+    name::{known, AsName},
+    ExpansionInfo, MacroCallId,
+};
 use hir_ty::Interner;
 use itertools::Itertools;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -910,13 +913,14 @@ impl<'db> SemanticsImpl<'db> {
 
     fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
         let krate = self.scope(extern_crate.syntax()).krate()?;
-        krate.dependencies(self.db).into_iter().find_map(|dep| {
-            if dep.name == extern_crate.name_ref()?.as_name() {
-                Some(dep.krate)
-            } else {
-                None
-            }
-        })
+        let name = extern_crate.name_ref()?.as_name();
+        if name == known::SELF_PARAM {
+            return Some(krate);
+        }
+        krate
+            .dependencies(self.db)
+            .into_iter()
+            .find_map(|dep| (dep.name == name).then(|| dep.krate))
     }
 
     fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index 49e55e03d1..550f12dabd 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -53,6 +53,10 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
                     }
                 }
             }
+            ast::PathSegmentKind::SelfTypeKw => {
+                segments.push(name![Self]);
+                generic_args.push(None)
+            }
             ast::PathSegmentKind::Type { type_ref, trait_ref } => {
                 assert!(path.qualifier().is_none()); // this can only occur at the first segment
 
diff --git a/crates/hir_expand/src/mod_path.rs b/crates/hir_expand/src/mod_path.rs
index 9c06a3f892..5e264d0398 100644
--- a/crates/hir_expand/src/mod_path.rs
+++ b/crates/hir_expand/src/mod_path.rs
@@ -5,7 +5,11 @@ use std::{
     iter,
 };
 
-use crate::{db::AstDatabase, hygiene::Hygiene, name::Name};
+use crate::{
+    db::AstDatabase,
+    hygiene::Hygiene,
+    name::{known, Name},
+};
 use base_db::CrateId;
 use either::Either;
 use syntax::{ast, AstNode};
@@ -162,6 +166,12 @@ fn convert_path(
                 }
             }
         }
+        ast::PathSegmentKind::SelfTypeKw => {
+            if prefix.is_some() {
+                return None;
+            }
+            ModPath::from_segments(PathKind::Plain, Some(known::SELF_TYPE))
+        }
         ast::PathSegmentKind::CrateKw => {
             if prefix.is_some() {
                 return None;
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs
index ae4dfd47bd..5520ee5528 100644
--- a/crates/ide/src/extend_selection.rs
+++ b/crates/ide/src/extend_selection.rs
@@ -246,7 +246,7 @@ fn pick_best(l: SyntaxToken, r: SyntaxToken) -> SyntaxToken {
     fn priority(n: &SyntaxToken) -> usize {
         match n.kind() {
             WHITESPACE => 0,
-            IDENT | T![self] | T![super] | T![crate] | LIFETIME_IDENT => 2,
+            IDENT | T![self] | T![super] | T![crate] | T![Self] | LIFETIME_IDENT => 2,
             _ => 1,
         }
     }
diff --git a/crates/ide/src/goto_declaration.rs b/crates/ide/src/goto_declaration.rs
index e62daf03f9..cb2cddc20d 100644
--- a/crates/ide/src/goto_declaration.rs
+++ b/crates/ide/src/goto_declaration.rs
@@ -18,7 +18,7 @@ pub(crate) fn goto_declaration(
     let file = sema.parse(position.file_id).syntax().clone();
     let original_token = file
         .token_at_offset(position.offset)
-        .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate]))?;
+        .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?;
     let range = original_token.text_range();
     let info: Vec<NavigationTarget> = sema
         .descend_into_macros(original_token)
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index e599efc5e2..d664e2ca65 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -30,7 +30,14 @@ pub(crate) fn goto_definition(
     let file = sema.parse(position.file_id).syntax().clone();
     let original_token =
         pick_best_token(file.token_at_offset(position.offset), |kind| match kind {
-            IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | COMMENT => 2,
+            IDENT
+            | INT_NUMBER
+            | LIFETIME_IDENT
+            | T![self]
+            | T![super]
+            | T![crate]
+            | T![Self]
+            | COMMENT => 2,
             kind if kind.is_trivia() => 0,
             _ => 1,
         })?;
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 0eba0b09ba..30d0d34358 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -100,7 +100,7 @@ pub(crate) fn hover(
     let offset = range.start();
 
     let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
-        IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3,
+        IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 3,
         T!['('] | T![')'] => 2,
         kind if kind.is_trivia() => 0,
         _ => 1,
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 40a647c90b..f8ac43bbdd 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -545,7 +545,6 @@ fn keyword_hints(
                 },
             }
         }
-
         T![fn] => {
             let module = match ast::FnPtrType::cast(parent) {
                 // treat fn keyword inside function pointer type as primitive
@@ -554,7 +553,7 @@ fn keyword_hints(
             };
             KeywordHint::new(token.text().to_string(), module)
         }
-
+        T![Self] => KeywordHint::new(token.text().to_string(), "self_upper_keyword".into()),
         _ => KeywordHint::new(token.text().to_string(), format!("{}_keyword", token.text())),
     }
 }
diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs
index 53f6d7ec7a..2e93d895f0 100644
--- a/crates/ide/src/moniker.rs
+++ b/crates/ide/src/moniker.rs
@@ -69,7 +69,14 @@ pub(crate) fn moniker(
     let file = sema.parse(file_id).syntax().clone();
     let current_crate = crate_for_file(db, file_id)?;
     let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
-        IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | COMMENT => 2,
+        IDENT
+        | INT_NUMBER
+        | LIFETIME_IDENT
+        | T![self]
+        | T![super]
+        | T![crate]
+        | T![Self]
+        | COMMENT => 2,
         kind if kind.is_trivia() => 0,
         _ => 1,
     })?;
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index d5bfbd1894..fb94342a78 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -126,7 +126,7 @@ impl StaticIndex<'_> {
         let tokens = tokens.filter(|token| {
             matches!(
                 token.kind(),
-                IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate]
+                IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
             )
         });
         let mut result = StaticIndexedFile { file_id, inlay_hints, folds, tokens: vec![] };
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 776a0f8295..968aa33116 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -118,6 +118,7 @@ pub struct HlRange {
 // parameter:: Emitted for non-self function parameters.
 // property:: Emitted for struct and union fields.
 // selfKeyword:: Emitted for the self function parameter and self path-specifier.
+// selfTypeKeyword:: Emitted for the Self type parameter.
 // toolModule:: Emitted for tool modules.
 // typeParameter:: Emitted for type parameters.
 // unresolvedReference:: Emitted for unresolved references, names that rust-analyzer can't find the definition of.
@@ -327,7 +328,7 @@ fn traverse(
                     // as otherwise we won't ever visit them
                     match (token.kind(), parent.kind()) {
                         (T![ident], NAME | NAME_REF) => parent.into(),
-                        (T![self] | T![super] | T![crate], NAME_REF) => parent.into(),
+                        (T![self] | T![super] | T![crate] | T![Self], NAME_REF) => parent.into(),
                         (INT_NUMBER, NAME_REF) => parent.into(),
                         (LIFETIME_IDENT, LIFETIME) => parent.into(),
                         _ => token.into(),
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 8ad27b1fdc..43a3fb2d71 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -192,9 +192,11 @@ fn keyword(
         T![true] | T![false] => HlTag::BoolLiteral.into(),
         // crate is handled just as a token if it's in an `extern crate`
         T![crate] if parent_matches::<ast::ExternCrate>(&token) => h,
-        // self, crate and super are handled as either a Name or NameRef already, unless they
+        // self, crate, super and `Self` are handled as either a Name or NameRef already, unless they
         // are inside unmapped token trees
-        T![self] | T![crate] | T![super] if parent_matches::<ast::NameRef>(&token) => return None,
+        T![self] | T![crate] | T![super] | T![Self] if parent_matches::<ast::NameRef>(&token) => {
+            return None
+        }
         T![self] if parent_matches::<ast::Name>(&token) => return None,
         T![ref] => match token.parent().and_then(ast::IdentPat::cast) {
             Some(ident) if sema.is_unsafe_ident_pat(&ident) => h | HlMod::Unsafe,
@@ -269,12 +271,13 @@ fn highlight_name_ref(
         }
         NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(),
     };
-    if name_ref.self_token().is_some() {
-        h.tag = HlTag::Symbol(SymbolKind::SelfParam);
-    }
-    if name_ref.crate_token().is_some() || name_ref.super_token().is_some() {
-        h.tag = HlTag::Keyword;
-    }
+
+    h.tag = match name_ref.token_kind() {
+        T![Self] => HlTag::Symbol(SymbolKind::SelfType),
+        T![self] => HlTag::Symbol(SymbolKind::SelfParam),
+        T![super] | T![crate] => HlTag::Keyword,
+        _ => h.tag,
+    };
     h
 }
 
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index bdf484e01f..cb9d36f830 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -141,6 +141,7 @@ impl HlTag {
                 SymbolKind::Macro => "macro",
                 SymbolKind::Module => "module",
                 SymbolKind::SelfParam => "self_keyword",
+                SymbolKind::SelfType => "self_type_keyword",
                 SymbolKind::Static => "static",
                 SymbolKind::Struct => "struct",
                 SymbolKind::ToolModule => "tool_module",
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index acaf17c255..32b14764a1 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -260,6 +260,7 @@ impl CompletionItemKind {
                 SymbolKind::Macro => "ma",
                 SymbolKind::Module => "md",
                 SymbolKind::SelfParam => "sp",
+                SymbolKind::SelfType => "sy",
                 SymbolKind::Static => "sc",
                 SymbolKind::Struct => "st",
                 SymbolKind::ToolModule => "tm",
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index d6f8cd0f4b..efb704b253 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -238,7 +238,9 @@ impl ImportGroup {
                 "core" => ImportGroup::Std,
                 _ => ImportGroup::ExternCrate,
             },
-            PathSegmentKind::Type { .. } => unreachable!(),
+            // these aren't valid use paths, so fall back to something random
+            PathSegmentKind::SelfTypeKw => ImportGroup::ExternCrate,
+            PathSegmentKind::Type { .. } => ImportGroup::ExternCrate,
         }
     }
 }
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index 602eaf0de5..3f64c0a124 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -163,6 +163,7 @@ pub enum SymbolKind {
     Macro,
     Module,
     SelfParam,
+    SelfType,
     Static,
     Struct,
     ToolModule,
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs
index 0cc0ed31aa..b4a60574e5 100644
--- a/crates/parser/src/grammar/paths.rs
+++ b/crates/parser/src/grammar/paths.rs
@@ -1,10 +1,10 @@
 use super::*;
 
 pub(super) const PATH_FIRST: TokenSet =
-    TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![:], T![<]]);
+    TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self], T![:], T![<]]);
 
 pub(super) fn is_path_start(p: &Parser) -> bool {
-    is_use_path_start(p) || p.at(T![<])
+    is_use_path_start(p) || p.at(T![<]) || p.at(T![Self])
 }
 
 pub(super) fn is_use_path_start(p: &Parser) -> bool {
@@ -88,7 +88,7 @@ fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
             }
             // test crate_path
             // use crate::foo;
-            T![self] | T![super] | T![crate] => {
+            T![self] | T![super] | T![crate] | T![Self] => {
                 let m = p.start();
                 p.bump_any();
                 m.complete(p, NAME_REF);
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
index 05c1aea5c4..ff067f5293 100644
--- a/crates/parser/src/grammar/types.rs
+++ b/crates/parser/src/grammar/types.rs
@@ -14,6 +14,7 @@ pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[
     T![for],
     T![impl],
     T![dyn],
+    T![Self],
 ]));
 
 const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[
@@ -46,7 +47,7 @@ fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) {
         T![dyn] => dyn_trait_type(p),
         // Some path types are not allowed to have bounds (no plus)
         T![<] => path_type_(p, allow_bounds),
-        _ if paths::is_use_path_start(p) => path_or_macro_type_(p, allow_bounds),
+        _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds),
         _ => {
             p.err_recover("expected type", TYPE_RECOVERY_SET);
         }
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
index 4e8a0cfe80..297809976e 100644
--- a/crates/parser/src/syntax_kind/generated.rs
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -90,6 +90,7 @@ pub enum SyntaxKind {
     REF_KW,
     RETURN_KW,
     SELF_KW,
+    SELF_TYPE_KW,
     STATIC_KW,
     STRUCT_KW,
     SUPER_KW,
@@ -264,10 +265,10 @@ impl SyntaxKind {
             AS_KW | ASYNC_KW | AWAIT_KW | BOX_KW | BREAK_KW | CONST_KW | CONTINUE_KW | CRATE_KW
             | DYN_KW | ELSE_KW | ENUM_KW | EXTERN_KW | FALSE_KW | FN_KW | FOR_KW | IF_KW
             | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
-            | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | STATIC_KW | STRUCT_KW | SUPER_KW
-            | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW | WHERE_KW | WHILE_KW
-            | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW | RAW_KW
-            | MACRO_RULES_KW => true,
+            | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | SELF_TYPE_KW | STATIC_KW
+            | STRUCT_KW | SUPER_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW
+            | WHERE_KW | WHILE_KW | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW
+            | RAW_KW | MACRO_RULES_KW => true,
             _ => false,
         }
     }
@@ -319,6 +320,7 @@ impl SyntaxKind {
             "ref" => REF_KW,
             "return" => RETURN_KW,
             "self" => SELF_KW,
+            "Self" => SELF_TYPE_KW,
             "static" => STATIC_KW,
             "struct" => STRUCT_KW,
             "super" => SUPER_KW,
@@ -383,5 +385,5 @@ impl SyntaxKind {
     }
 }
 #[macro_export]
-macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
+macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
 pub use T;
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index c6322327a5..5fb945ea98 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -66,6 +66,7 @@ define_semantic_token_types![
     (PARENTHESIS, "parenthesis"),
     (PUNCTUATION, "punctuation"),
     (SELF_KEYWORD, "selfKeyword"),
+    (SELF_TYPE_KEYWORD, "selfTypeKeyword"),
     (SEMICOLON, "semicolon"),
     (TYPE_ALIAS, "typeAlias"),
     (TOOL_MODULE, "toolModule"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index f0de166d8b..4a2b3a1b47 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -55,7 +55,9 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind {
         | SymbolKind::Attribute
         | SymbolKind::Derive => lsp_types::SymbolKind::FUNCTION,
         SymbolKind::Module | SymbolKind::ToolModule => lsp_types::SymbolKind::MODULE,
-        SymbolKind::TypeAlias | SymbolKind::TypeParam => lsp_types::SymbolKind::TYPE_PARAMETER,
+        SymbolKind::TypeAlias | SymbolKind::TypeParam | SymbolKind::SelfType => {
+            lsp_types::SymbolKind::TYPE_PARAMETER
+        }
         SymbolKind::Field => lsp_types::SymbolKind::FIELD,
         SymbolKind::Static => lsp_types::SymbolKind::CONSTANT,
         SymbolKind::Const => lsp_types::SymbolKind::CONSTANT,
@@ -124,6 +126,7 @@ pub(crate) fn completion_item_kind(
             SymbolKind::Macro => lsp_types::CompletionItemKind::FUNCTION,
             SymbolKind::Module => lsp_types::CompletionItemKind::MODULE,
             SymbolKind::SelfParam => lsp_types::CompletionItemKind::VALUE,
+            SymbolKind::SelfType => lsp_types::CompletionItemKind::TYPE_PARAMETER,
             SymbolKind::Static => lsp_types::CompletionItemKind::VALUE,
             SymbolKind::Struct => lsp_types::CompletionItemKind::STRUCT,
             SymbolKind::Trait => lsp_types::CompletionItemKind::INTERFACE,
@@ -483,6 +486,7 @@ fn semantic_token_type_and_modifiers(
             SymbolKind::Label => semantic_tokens::LABEL,
             SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER,
             SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD,
+            SymbolKind::SelfType => semantic_tokens::SELF_TYPE_KEYWORD,
             SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE,
             SymbolKind::Function => {
                 if highlight.mods.contains(HlMod::Associated) {
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 8baea77075..d8f8290745 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -30,7 +30,7 @@ rayon = "1"
 expect-test = "1.2.0-pre.1"
 proc-macro2 = "1.0.8"
 quote = "1.0.2"
-ungrammar = "=1.16.0"
+ungrammar = "=1.16.1"
 
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index fc1ee6f601..6f236c01ce 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -1,5 +1,6 @@
 //! Generated by `sourcegen_ast`, do not edit by hand.
 
+#![allow(non_snake_case)]
 use crate::{
     ast::{self, support, AstChildren, AstNode},
     SyntaxKind::{self, *},
@@ -24,6 +25,7 @@ impl NameRef {
     pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
     pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) }
     pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
+    pub fn Self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![Self]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 1a754ef460..19a007e072 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -185,7 +185,7 @@ pub(crate) fn generic_arg_list() -> ast::GenericArgList {
 }
 
 pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
-    ast_from_text(&format!("use {};", name_ref))
+    ast_from_text(&format!("type __ = {};", name_ref))
 }
 
 pub fn path_segment_ty(type_ref: ast::Type, trait_ref: Option<ast::PathType>) -> ast::PathSegment {
@@ -209,7 +209,7 @@ pub fn path_segment_crate() -> ast::PathSegment {
 }
 
 pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path {
-    ast_from_text(&format!("use {}", segment))
+    ast_from_text(&format!("type __ = {};", segment))
 }
 
 pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
@@ -217,7 +217,7 @@ pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
 }
 // FIXME: path concatenation operation doesn't make sense as AST op.
 pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path {
-    ast_from_text(&format!("{}::{}", first, second))
+    ast_from_text(&format!("type __ = {}::{};", first, second))
 }
 
 pub fn path_from_segments(
@@ -234,7 +234,7 @@ pub fn path_from_segments(
 
 pub fn join_paths(paths: impl IntoIterator<Item = ast::Path>) -> ast::Path {
     let paths = paths.into_iter().map(|it| it.syntax().clone()).join("::");
-    ast_from_text(&format!("use {};", paths))
+    ast_from_text(&format!("type __ = {};", paths))
 }
 
 // FIXME: should not be pub
@@ -782,6 +782,7 @@ pub fn struct_(
     ))
 }
 
+#[track_caller]
 fn ast_from_text<N: AstNode>(text: &str) -> N {
     let parse = SourceFile::parse(text);
     let node = match parse.tree().syntax().descendants().find_map(N::cast) {
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 229c71c76b..333ee35d63 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -34,6 +34,10 @@ impl ast::NameRef {
     pub fn as_tuple_field(&self) -> Option<usize> {
         self.text().parse().ok()
     }
+
+    pub fn token_kind(&self) -> SyntaxKind {
+        self.syntax().first_token().map_or(SyntaxKind::ERROR, |it| it.kind())
+    }
 }
 
 fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
@@ -183,6 +187,7 @@ impl ast::Attr {
 pub enum PathSegmentKind {
     Name(ast::NameRef),
     Type { type_ref: Option<ast::Type>, trait_ref: Option<ast::PathType> },
+    SelfTypeKw,
     SelfKw,
     SuperKw,
     CrateKw,
@@ -204,16 +209,21 @@ impl ast::PathSegment {
         self.name_ref().and_then(|it| it.self_token())
     }
 
+    pub fn self_type_token(&self) -> Option<SyntaxToken> {
+        self.name_ref().and_then(|it| it.Self_token())
+    }
+
     pub fn super_token(&self) -> Option<SyntaxToken> {
         self.name_ref().and_then(|it| it.super_token())
     }
 
     pub fn kind(&self) -> Option<PathSegmentKind> {
         let res = if let Some(name_ref) = self.name_ref() {
-            match name_ref.syntax().first_token().map(|it| it.kind()) {
-                Some(T![self]) => PathSegmentKind::SelfKw,
-                Some(T![super]) => PathSegmentKind::SuperKw,
-                Some(T![crate]) => PathSegmentKind::CrateKw,
+            match name_ref.token_kind() {
+                T![Self] => PathSegmentKind::SelfTypeKw,
+                T![self] => PathSegmentKind::SelfKw,
+                T![super] => PathSegmentKind::SuperKw,
+                T![crate] => PathSegmentKind::CrateKw,
                 _ => PathSegmentKind::Name(name_ref),
             }
         } else {
diff --git a/editors/code/package.json b/editors/code/package.json
index 1252752a9a..4843ea8421 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -1294,6 +1294,11 @@
                 "description": "Style for the self keyword",
                 "superType": "keyword"
             },
+            {
+                "id": "selfTypeKeyword",
+                "description": "Style for the self type keyword",
+                "superType": "keyword"
+            },
             {
                 "id": "semicolon",
                 "description": "Style for ;",


Test patch:
diff --git a/crates/hir_def/src/macro_expansion_tests.rs b/crates/hir_def/src/macro_expansion_tests.rs
index 1a7d9aa841..f86d87d5cc 100644
--- a/crates/hir_def/src/macro_expansion_tests.rs
+++ b/crates/hir_def/src/macro_expansion_tests.rs
@@ -302,6 +302,7 @@ fn pretty_print_macro_expansion(expn: SyntaxNode, map: Option<&TokenMap>) -> Str
             (T![fn], T!['(']) => "",
             (T![']'], _) if curr_kind.is_keyword() => " ",
             (T![']'], T![#]) => "\n",
+            (T![Self], T![::]) => "",
             _ if prev_kind.is_keyword() => " ",
             _ => "",
         };
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index 22bdfffa3e..86ed8dbd77 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -59,11 +59,11 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="field declaration">x</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
 <span class="brace">}</span>
 
-<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="keyword">where</span> <span class="type_param">Self</span><span class="colon">:</span> <span class="brace">{</span>
+<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span>
     <span class="keyword">fn</span> <span class="function associated declaration reference trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
-<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="keyword">where</span> <span class="self_type">Self</span><span class="colon">:</span> <span class="brace">{</span>
+<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span>
     <span class="keyword">fn</span> <span class="function associated declaration reference trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
         <span class="self_keyword reference">self</span><span class="operator">.</span><span class="field">x</span>
     <span class="brace">}</span>
@@ -210,7 +210,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 <span class="keyword">impl</span> <span class="enum public">Bool</span> <span class="brace">{</span>
     <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function associated consuming declaration public">to_primitive</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="brace">{</span>
-        <span class="unresolved_reference">matches</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="keyword">self</span><span class="comma">,</span> Self<span class="colon">:</span><span class="colon">:</span>True<span class="parenthesis">)</span>
+        <span class="bool_literal">true</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
 <span class="keyword">const</span> <span class="constant declaration">USAGE_OF_BOOL</span><span class="colon">:</span><span class="builtin_type">bool</span> <span class="operator">=</span> <span class="enum public">Bool</span><span class="operator">::</span><span class="enum_variant public">True</span><span class="operator">.</span><span class="function associated consuming public">to_primitive</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
new file mode 100644
index 0000000000..145bba2a06
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
@@ -0,0 +1,57 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.function.unsafe    { color: #BC8383; }
+.trait.unsafe       { color: #BC8383; }
+.operator.unsafe    { color: #BC8383; }
+.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
+.keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root">self</span><span class="semicolon">;</span>
+
+<span class="keyword">use</span> <span class="keyword crate_root">crate</span><span class="semicolon">;</span>
+<span class="keyword">use</span> <span class="self_keyword crate_root">self</span><span class="semicolon">;</span>
+<span class="keyword">mod</span> <span class="module declaration">__</span> <span class="brace">{</span>
+    <span class="keyword">use</span> <span class="keyword crate_root">super</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span>
+<span class="brace">}</span>
+
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">void</span> <span class="brace">{</span>
+    <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="brace">}</span>
+<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="keyword">Self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+<span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span>
+<span class="keyword">fn</span> <span class="function declaration">__</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="unresolved_reference">Self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index c14e3330e3..0af743431b 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -113,11 +113,11 @@ struct Foo {
     x: u32,
 }
 
-trait Bar where Self: {
+trait Bar {
     fn bar(&self) -> i32;
 }
 
-impl Bar for Foo where Self: {
+impl Bar for Foo {
     fn bar(&self) -> i32 {
         self.x
     }
@@ -264,7 +264,7 @@ pub enum Bool { True, False }
 
 impl Bool {
     pub const fn to_primitive(self) -> bool {
-        matches!(self, Self::True)
+        true
     }
 }
 const USAGE_OF_BOOL:bool = Bool::True.to_primitive();
@@ -334,6 +334,30 @@ where
     );
 }
 
+#[test]
+fn test_keyword_highlighting() {
+    check_highlighting(
+        r#"
+extern crate self;
+
+use crate;
+use self;
+mod __ {
+    use super::*;
+}
+
+macro_rules! void {
+    ($($tt:tt)) => {}
+}
+void!(Self);
+struct __ where Self:;
+fn __(_: Self) {}
+"#,
+        expect_file!["./test_data/highlight_keywords.html"],
+        false,
+    );
+}
+
 #[test]
 fn test_string_highlighting() {
     // The format string detection is based on macro-expansion,
diff --git a/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.txt b/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.txt
index d542e0edc7..a0b5626296 100644
--- a/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.txt
+++ b/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.txt
@@ -29,7 +29,7 @@ SOURCE_FILE
                 PATH
                   PATH_SEGMENT
                     NAME_REF
-                      IDENT "Self"
+                      SELF_TYPE_KW "Self"
           R_PAREN ")"
         WHITESPACE " "
         BLOCK_EXPR
@@ -63,7 +63,7 @@ SOURCE_FILE
                         PATH
                           PATH_SEGMENT
                             NAME_REF
-                              IDENT "Self"
+                              SELF_TYPE_KW "Self"
                     R_ANGLE ">"
           R_PAREN ")"
         WHITESPACE " "
diff --git a/crates/parser/test_data/parser/inline/ok/0041_trait_item.txt b/crates/parser/test_data/parser/inline/ok/0041_trait_item.txt
index 86d92406d8..dd7f76eb93 100644
--- a/crates/parser/test_data/parser/inline/ok/0041_trait_item.txt
+++ b/crates/parser/test_data/parser/inline/ok/0041_trait_item.txt
@@ -24,7 +24,7 @@ SOURCE_FILE
             PATH
               PATH_SEGMENT
                 NAME_REF
-                  IDENT "Self"
+                  SELF_TYPE_KW "Self"
         SEMICOLON ";"
       WHITESPACE " "
       R_CURLY "}"
diff --git a/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.txt b/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.txt
index ab42d81f9b..46cd8ee665 100644
--- a/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.txt
+++ b/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.txt
@@ -13,7 +13,7 @@ SOURCE_FILE
           PATH
             PATH_SEGMENT
               NAME_REF
-                IDENT "Self"
+                SELF_TYPE_KW "Self"
         COLON ":"
         WHITESPACE " "
         TYPE_BOUND_LIST
diff --git a/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.txt b/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.txt
index 88b1f8c29e..4443d9d142 100644
--- a/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.txt
+++ b/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.txt
@@ -73,7 +73,7 @@ SOURCE_FILE
           PATH
             PATH_SEGMENT
               NAME_REF
-                IDENT "Self"
+                SELF_TYPE_KW "Self"
         COLON ":"
         WHITESPACE " "
         TYPE_BOUND_LIST
diff --git a/crates/parser/test_data/parser/ok/0045_block_attrs.txt b/crates/parser/test_data/parser/ok/0045_block_attrs.txt
index 6b6f3bfe3e..9684bb11cd 100644
--- a/crates/parser/test_data/parser/ok/0045_block_attrs.txt
+++ b/crates/parser/test_data/parser/ok/0045_block_attrs.txt
@@ -199,7 +199,7 @@ SOURCE_FILE
                                       PATH
                                         PATH_SEGMENT
                                           NAME_REF
-                                            IDENT "Self"
+                                            SELF_TYPE_KW "Self"
                                   R_ANGLE ">"
           R_PAREN ")"
         WHITESPACE " "
diff --git a/crates/parser/test_data/parser/ok/0051_parameter_attrs.txt b/crates/parser/test_data/parser/ok/0051_parameter_attrs.txt
index e1ebf5a38c..f8b11e7782 100644
--- a/crates/parser/test_data/parser/ok/0051_parameter_attrs.txt
+++ b/crates/parser/test_data/parser/ok/0051_parameter_attrs.txt
@@ -494,7 +494,7 @@ SOURCE_FILE
               PATH
                 PATH_SEGMENT
                   NAME_REF
-                    IDENT "Self"
+                    SELF_TYPE_KW "Self"
           R_PAREN ")"
         WHITESPACE " "
         BLOCK_EXPR
@@ -536,7 +536,7 @@ SOURCE_FILE
                         PATH
                           PATH_SEGMENT
                             NAME_REF
-                              IDENT "Self"
+                              SELF_TYPE_KW "Self"
                     R_ANGLE ">"
           R_PAREN ")"
         WHITESPACE " "
diff --git a/crates/syntax/src/tests/ast_src.rs b/crates/syntax/src/tests/ast_src.rs
index 3152137fb8..e808cb4be4 100644
--- a/crates/syntax/src/tests/ast_src.rs
+++ b/crates/syntax/src/tests/ast_src.rs
@@ -67,8 +67,8 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
     keywords: &[
         "as", "async", "await", "box", "break", "const", "continue", "crate", "dyn", "else",
         "enum", "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "macro",
-        "match", "mod", "move", "mut", "pub", "ref", "return", "self", "static", "struct", "super",
-        "trait", "true", "try", "type", "unsafe", "use", "where", "while", "yield",
+        "match", "mod", "move", "mut", "pub", "ref", "return", "self", "Self", "static", "struct",
+        "super", "trait", "true", "try", "type", "unsafe", "use", "where", "while", "yield",
     ],
     contextual_keywords: &["auto", "default", "existential", "union", "raw", "macro_rules"],
     literals: &["INT_NUMBER", "FLOAT_NUMBER", "CHAR", "BYTE", "STRING", "BYTE_STRING"],
diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs
index 5ed56a81c4..cb38abfe89 100644
--- a/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/crates/syntax/src/tests/sourcegen_ast.rs
@@ -297,6 +297,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
     }
 
     let ast = quote! {
+        #![allow(non_snake_case)]
         use crate::{
             SyntaxNode, SyntaxToken, SyntaxKind::{self, *},
             ast::{self, AstNode, AstChildren, support},
@@ -356,21 +357,24 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String {
     let punctuation =
         grammar.punct.iter().map(|(_token, name)| format_ident!("{}", name)).collect::<Vec<_>>();
 
-    let full_keywords_values = &grammar.keywords;
-    let full_keywords =
-        full_keywords_values.iter().map(|kw| format_ident!("{}_KW", to_upper_snake_case(kw)));
+    let x = |&name| match name {
+        "Self" => format_ident!("SELF_TYPE_KW"),
+        name => format_ident!("{}_KW", to_upper_snake_case(name)),
+    };
+    let full_keywords_values = grammar.keywords;
+    let full_keywords = full_keywords_values.iter().map(x);
 
     let contextual_keywords_values = &grammar.contextual_keywords;
-    let contextual_keywords =
-        contextual_keywords_values.iter().map(|kw| format_ident!("{}_KW", to_upper_snake_case(kw)));
+    let contextual_keywords = contextual_keywords_values.iter().map(x);
 
-    let all_keywords_values =
-        grammar.keywords.iter().chain(grammar.contextual_keywords.iter()).collect::<Vec<_>>();
-    let all_keywords_idents = all_keywords_values.iter().map(|kw| format_ident!("{}", kw));
-    let all_keywords = all_keywords_values
+    let all_keywords_values = grammar
+        .keywords
         .iter()
-        .map(|name| format_ident!("{}_KW", to_upper_snake_case(name)))
+        .chain(grammar.contextual_keywords.iter())
+        .copied()
         .collect::<Vec<_>>();
+    let all_keywords_idents = all_keywords_values.iter().map(|kw| format_ident!("{}", kw));
+    let all_keywords = all_keywords_values.iter().map(x).collect::<Vec<_>>();
 
     let literals =
         grammar.literals.iter().map(|name| format_ident!("{}", name)).collect::<Vec<_>>();