Repository: rust-analyzer/rust-analyzer
Pull request #4246 (2020-05-01 16:10:00)

Validate uses of self and super
This change follows on the validation of the `crate` keyword in paths. It verifies the following things:

`super`:
 - May only be preceded by other `super` segments
 - If in a `UseItem` then all semantically preceding paths also consist only of `super`

`self`
 - May only be the start of a path


Just a note, a couple times while working on this I found myself really wanting a Visitor of some sort so that I could traverse descendants while skipping sub-trees that are unimportant. Iterators don't really work for this, so as you can see I reached for recursion. Considering paths are generally small a fancy debounced visitor probably isn't important but figured I'd say something in case we had something like this lying around and I wasn't using it.


Patch:
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index f467ed3fe2..5716038543 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -182,6 +182,10 @@ impl ExprCollector<'_> {
 
                 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
             }
+            ast::Expr::TryBlockExpr(e) => {
+                let body = self.collect_block_opt(e.body());
+                self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
+            }
             ast::Expr::BlockExpr(e) => self.collect_block(e),
             ast::Expr::LoopExpr(e) => {
                 let body = self.collect_block_opt(e.loop_body());
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs
index aad12e1235..a0cdad529b 100644
--- a/crates/ra_hir_def/src/expr.rs
+++ b/crates/ra_hir_def/src/expr.rs
@@ -101,6 +101,9 @@ pub enum Expr {
     Try {
         expr: ExprId,
     },
+    TryBlock {
+        body: ExprId,
+    },
     Cast {
         expr: ExprId,
         type_ref: TypeRef,
@@ -236,6 +239,7 @@ impl Expr {
                     f(*expr);
                 }
             }
+            Expr::TryBlock { body } => f(*body),
             Expr::Loop { body } => f(*body),
             Expr::While { condition, body } => {
                 f(*condition);
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index efc60986bd..83f946eeea 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -73,6 +73,11 @@ impl<'a> InferenceContext<'a> {
                 self.coerce_merge_branch(&then_ty, &else_ty)
             }
             Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected),
+            Expr::TryBlock { body } => {
+                let _inner = self.infer_expr(*body, expected);
+                // FIXME should be std::result::Result<{inner}, _>
+                Ty::Unknown
+            }
             Expr::Loop { body } => {
                 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
                 // FIXME handle break with value
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index 76aa601cb5..166dfc472b 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -84,7 +84,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
         T![box] => box_expr(p, None),
         T![for] => for_expr(p, None),
         T![while] => while_expr(p, None),
-        T![try] => try_expr(p, None),
+        T![try] => try_block_expr(p, None),
         LIFETIME if la == T![:] => {
             let m = p.start();
             label(p);
@@ -134,7 +134,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
         }
     };
     let blocklike = match done.kind() {
-        IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR | TRY_EXPR => {
+        IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR | TRY_BLOCK_EXPR => {
             BlockLike::Block
         }
         _ => BlockLike::NotBlock,
@@ -532,7 +532,7 @@ fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
 // fn foo() {
 //     let _ = try {};
 // }
-fn try_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
+fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
     assert!(p.at(T![try]));
     let m = m.unwrap_or_else(|| p.start());
     // Special-case `try!` as macro.
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs
index ab727ed7e1..524e7d784e 100644
--- a/crates/ra_parser/src/syntax_kind/generated.rs
+++ b/crates/ra_parser/src/syntax_kind/generated.rs
@@ -191,6 +191,7 @@ pub enum SyntaxKind {
     RECORD_LIT,
     RECORD_FIELD_LIST,
     RECORD_FIELD,
+    TRY_BLOCK_EXPR,
     BOX_EXPR,
     CALL_EXPR,
     INDEX_EXPR,
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 521ca8ab8e..a716e525b9 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -16,9 +16,7 @@ use crate::{
 };
 
 pub use self::{
-    expr_extensions::{
-        ArrayExprKind, BinOp, BlockModifier, ElseBranch, LiteralKind, PrefixOp, RangeOp,
-    },
+    expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp, RangeOp},
     extensions::{
         AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents,
         StructKind, TypeBoundKind, VisibilityKind,
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs
index 352c0d2c57..ecf74fd366 100644
--- a/crates/ra_syntax/src/ast/expr_extensions.rs
+++ b/crates/ra_syntax/src/ast/expr_extensions.rs
@@ -16,7 +16,7 @@ impl ast::Expr {
             | ast::Expr::WhileExpr(_)
             | ast::Expr::BlockExpr(_)
             | ast::Expr::MatchExpr(_)
-            | ast::Expr::TryExpr(_) => true,
+            | ast::Expr::TryBlockExpr(_) => true,
             _ => false,
         }
     }
@@ -359,22 +359,7 @@ impl ast::Literal {
     }
 }
 
-pub enum BlockModifier {
-    Async(SyntaxToken),
-    Unsafe(SyntaxToken),
-}
-
 impl ast::BlockExpr {
-    pub fn modifier(&self) -> Option<BlockModifier> {
-        if let Some(token) = self.async_token() {
-            return Some(BlockModifier::Async(token));
-        }
-        if let Some(token) = self.unsafe_token() {
-            return Some(BlockModifier::Unsafe(token));
-        }
-        None
-    }
-
     /// false if the block is an intrinsic part of the syntax and can't be
     /// replaced with arbitrary expression.
     ///
@@ -383,15 +368,15 @@ impl ast::BlockExpr {
     /// const FOO: () = { stand_alone };
     /// ```
     pub fn is_standalone(&self) -> bool {
-        if self.modifier().is_some() {
+        if self.unsafe_token().is_some() || self.async_token().is_some() {
             return false;
         }
-        let parent = match self.syntax().parent() {
-            Some(it) => it,
+        let kind = match self.syntax().parent() {
             None => return true,
+            Some(it) => it.kind(),
         };
-        match parent.kind() {
-            FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR => false,
+        match kind {
+            FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR | TRY_BLOCK_EXPR => false,
             _ => true,
         }
     }
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs
index 81260680f9..2096f12f1b 100644
--- a/crates/ra_syntax/src/ast/generated/nodes.rs
+++ b/crates/ra_syntax/src/ast/generated/nodes.rs
@@ -475,6 +475,16 @@ impl LoopExpr {
     pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) }
 }
 
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct TryBlockExpr {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::AttrsOwner for TryBlockExpr {}
+impl TryBlockExpr {
+    pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) }
+    pub fn body(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct ForExpr {
     pub(crate) syntax: SyntaxNode,
@@ -1241,6 +1251,8 @@ pub struct PathSegment {
 impl PathSegment {
     pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
     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]) }
+    pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) }
     pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
     pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
     pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) }
@@ -1465,6 +1477,7 @@ pub enum Expr {
     FieldExpr(FieldExpr),
     AwaitExpr(AwaitExpr),
     TryExpr(TryExpr),
+    TryBlockExpr(TryBlockExpr),
     CastExpr(CastExpr),
     RefExpr(RefExpr),
     PrefixExpr(PrefixExpr),
@@ -1947,6 +1960,17 @@ impl AstNode for LoopExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for TryBlockExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_BLOCK_EXPR }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
 impl AstNode for ForExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3288,6 +3312,9 @@ impl From<AwaitExpr> for Expr {
 impl From<TryExpr> for Expr {
     fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) }
 }
+impl From<TryBlockExpr> for Expr {
+    fn from(node: TryBlockExpr) -> Expr { Expr::TryBlockExpr(node) }
+}
 impl From<CastExpr> for Expr {
     fn from(node: CastExpr) -> Expr { Expr::CastExpr(node) }
 }
@@ -3318,8 +3345,9 @@ impl AstNode for Expr {
             TUPLE_EXPR | ARRAY_EXPR | PAREN_EXPR | PATH_EXPR | LAMBDA_EXPR | IF_EXPR
             | LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL
             | BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | RECORD_LIT | CALL_EXPR | INDEX_EXPR
-            | METHOD_CALL_EXPR | FIELD_EXPR | AWAIT_EXPR | TRY_EXPR | CAST_EXPR | REF_EXPR
-            | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL | BOX_EXPR => true,
+            | METHOD_CALL_EXPR | FIELD_EXPR | AWAIT_EXPR | TRY_EXPR | TRY_BLOCK_EXPR
+            | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL
+            | BOX_EXPR => true,
             _ => false,
         }
     }
@@ -3347,6 +3375,7 @@ impl AstNode for Expr {
             FIELD_EXPR => Expr::FieldExpr(FieldExpr { syntax }),
             AWAIT_EXPR => Expr::AwaitExpr(AwaitExpr { syntax }),
             TRY_EXPR => Expr::TryExpr(TryExpr { syntax }),
+            TRY_BLOCK_EXPR => Expr::TryBlockExpr(TryBlockExpr { syntax }),
             CAST_EXPR => Expr::CastExpr(CastExpr { syntax }),
             REF_EXPR => Expr::RefExpr(RefExpr { syntax }),
             PREFIX_EXPR => Expr::PrefixExpr(PrefixExpr { syntax }),
@@ -3383,6 +3412,7 @@ impl AstNode for Expr {
             Expr::FieldExpr(it) => &it.syntax,
             Expr::AwaitExpr(it) => &it.syntax,
             Expr::TryExpr(it) => &it.syntax,
+            Expr::TryBlockExpr(it) => &it.syntax,
             Expr::CastExpr(it) => &it.syntax,
             Expr::RefExpr(it) => &it.syntax,
             Expr::PrefixExpr(it) => &it.syntax,
@@ -3863,6 +3893,11 @@ impl std::fmt::Display for LoopExpr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for TryBlockExpr {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for ForExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index f0b3dec631..e075cd8017 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -96,7 +96,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
                 ast::RecordField(it) => validate_numeric_name(it.name_ref(), &mut errors),
                 ast::Visibility(it) => validate_visibility(it, &mut errors),
                 ast::RangeExpr(it) => validate_range_expr(it, &mut errors),
-                ast::PathSegment(it) => validate_crate_keyword_in_path_segment(it, &mut errors),
+                ast::PathSegment(it) => validate_path_keywords(it, &mut errors),
                 _ => (),
             }
         }
@@ -224,59 +224,82 @@ fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) {
     }
 }
 
-fn validate_crate_keyword_in_path_segment(
-    segment: ast::PathSegment,
-    errors: &mut Vec<SyntaxError>,
-) {
-    const ERR_MSG: &str = "The `crate` keyword is only allowed as the first segment of a path";
+fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxError>) {
+    use ast::PathSegmentKind;
 
-    let crate_token = match segment.crate_token() {
-        None => return,
-        Some(it) => it,
-    };
+    let path = segment.parent_path();
+    let is_path_start = segment.coloncolon_token().is_none() && path.qualifier().is_none();
+
+    if let Some(token) = segment.self_token() {
+        if !is_path_start {
+            errors.push(SyntaxError::new(
+                "The `self` keyword is only allowed as the first segment of a path",
+                token.text_range(),
+            ));
+        }
+    } else if let Some(token) = segment.crate_token() {
+        if !is_path_start || use_prefix(path).is_some() {
+            errors.push(SyntaxError::new(
+                "The `crate` keyword is only allowed as the first segment of a path",
+                token.text_range(),
+            ));
+        }
+    } else if let Some(token) = segment.super_token() {
+        if !all_supers(&path) {
+            errors.push(SyntaxError::new(
+                "The `super` keyword may only be preceded by other `super`s",
+                token.text_range(),
+            ));
+            return;
+        }
 
-    // Disallow both ::crate and foo::crate
-    let mut path = segment.parent_path();
-    if segment.coloncolon_token().is_some() || path.qualifier().is_some() {
-        errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range()));
-        return;
+        let mut curr_path = path;
+        while let Some(prefix) = use_prefix(curr_path) {
+            if !all_supers(&prefix) {
+                errors.push(SyntaxError::new(
+                    "The `super` keyword may only be preceded by other `super`s",
+                    token.text_range(),
+                ));
+                return;
+            }
+            curr_path = prefix;
+        }
     }
 
-    // For expressions and types, validation is complete, but we still have
-    // to handle invalid UseItems like this:
-    //
-    //      use foo:{crate::bar::baz};
-    //
-    // To handle this we must inspect the parent `UseItem`s and `UseTree`s
-    // but right now we're looking deep inside the nested `Path` nodes because
-    // `Path`s are left-associative:
-    //
-    //   ((crate)::bar)::baz)
-    //       ^ current value of path
-    //
-    // So we need to climb to the top
-    while let Some(parent) = path.parent_path() {
-        path = parent;
+    fn use_prefix(mut path: ast::Path) -> Option<ast::Path> {
+        for node in path.syntax().ancestors().skip(1) {
+            match_ast! {
+                match node {
+                    ast::UseTree(it) => if let Some(tree_path) = it.path() {
+                        // Even a top-level path exists within a `UseTree` so we must explicitly
+                        // allow our path but disallow anything else
+                        if tree_path != path {
+                            return Some(tree_path);
+                        }
+                    },
+                    ast::UseTreeList(_it) => continue,
+                    ast::Path(parent) => path = parent,
+                    _ => return None,
+                }
+            };
+        }
+        return None;
     }
 
-    // Now that we've found the whole path we need to see if there's a prefix
-    // somewhere in the UseTree hierarchy. This check is arbitrarily deep
-    // because rust allows arbitrary nesting like so:
-    //
-    // use {foo::{{{{crate::bar::baz}}}}};
-    for node in path.syntax().ancestors().skip(1) {
-        match_ast! {
-            match node {
-                ast::UseTree(it) => if let Some(tree_path) = it.path() {
-                    // Even a top-level path exists within a `UseTree` so we must explicitly
-                    // allow our path but disallow anything else
-                    if tree_path != path {
-                        errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range()));
-                    }
-                },
-                ast::UseTreeList(_it) => continue,
-                _ => return,
-            }
+    fn all_supers(path: &ast::Path) -> bool {
+        let segment = match path.segment() {
+            Some(it) => it,
+            None => return false,
         };
+
+        if segment.kind() != Some(PathSegmentKind::SuperKw) {
+            return false;
+        }
+
+        if let Some(ref subpath) = path.qualifier() {
+            return all_supers(subpath);
+        }
+
+        return true;
     }
 }
diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md
index 33973ffecb..4dd1de6592 100644
--- a/docs/dev/syntax.md
+++ b/docs/dev/syntax.md
@@ -35,7 +35,7 @@ The syntax tree consists of three layers:
 * AST
 
 Of these, only GreenNodes store the actual data, the other two layers are (non-trivial) views into green tree.
-Red-green terminology comes from Roslyn ([link](https://ericlippert.com/2012/06/08/red-green-trees/)) and gives the name to the `rowan` library. Green and syntax nodes are defined in rowan, ast is defined in rust-analyzer.
+Red-green terminology comes from Roslyn ([link](https://docs.microsoft.com/en-ie/archive/blogs/ericlippert/persistence-facades-and-roslyns-red-green-trees)) and gives the name to the `rowan` library. Green and syntax nodes are defined in rowan, ast is defined in rust-analyzer.
 
 Syntax trees are a semi-transient data structure.
 In general, frontend does not keep syntax trees for all files in memory.
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc
index 4cb1e23e8d..54342026bd 100644
--- a/docs/user/readme.adoc
+++ b/docs/user/readme.adoc
@@ -111,7 +111,7 @@ Here are some useful self-diagnostic commands:
 === rust-analyzer Language Server Binary
 
 Other editors generally require the `rust-analyzer` binary to be in `$PATH`.
-You can download the pre-built binary from the https://github.com/rust-analyzer/rust-analyzer/releases[releases] page. Typically, you then need to rename the binary for your platform, e.g. `rust-analyzer-mac` if you're on Mac OS, to `rust-analyzer` and make it executable in addition to moving it into a directory in your `$PATH`.
+You can download the pre-built binary from the https://github.com/rust-analyzer/rust-analyzer/releases[releases] page. Typically, you then need to rename the binary for your platform, e.g. `rust-analyzer-mac` if you're on Mac OS, to `rust-analzyer` and make it executable in addition to moving it into a directory in your `$PATH`.
 
 On Linux to install the `rust-analyzer` binary into `~/.local/bin`, this commands could be used
 
@@ -246,9 +246,9 @@ You also need the `LSP` package. To install it:
    * Type `Install Package Control`, press enter
 2. In the command palette, run `Package control: Install package`, and in the list that pops up, type `LSP` and press enter.
 
-Finally, with your Rust project open, in the command palette, run `LSP: Enable Language Server In Project` or `LSP: Enable Language Server Globally`, then select `rust-analyzer` in the list that pops up to enable the rust-analyzer LSP. The latter means that rust-analyzer is enabled by default in Rust projects.
+Finally, with your Rust project open, in the command palette, run `LSP: Enable Language Server In Project` or `LSP: Enable Language Server Globally`, then select `rust-analyzer` in the list that pops up to enable the rust-analyzer LSP. The latter means that rust-analzyer is enabled by default in Rust projects.
 
-If it worked, you should see "rust-analyzer, Line X, Column Y" on the left side of the bottom bar, and after waiting a bit, functionality like tooltips on hovering over variables should become available.
+If it worked, you should see "rust-analzyer, Line X, Column Y" on the left side of the bottom bar, and after waiting a bit, functionality like tooltips on hovering over variables should become available.
 
 If you get an error saying `No such file or directory: 'rust-analyzer'`, see the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>> section on installing the language server binary.
 
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index bdd42cb769..1abb62f6fa 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -162,6 +162,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
         "RECORD_LIT",
         "RECORD_FIELD_LIST",
         "RECORD_FIELD",
+        "TRY_BLOCK_EXPR",
         "BOX_EXPR",
         // postfix
         "CALL_EXPR",
@@ -439,6 +440,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
         }
         struct IfExpr: AttrsOwner { T![if], Condition }
         struct LoopExpr: AttrsOwner, LoopBodyOwner { T![loop] }
+        struct TryBlockExpr: AttrsOwner { T![try], body: BlockExpr }
         struct ForExpr: AttrsOwner, LoopBodyOwner {
             T![for],
             Pat,
@@ -449,7 +451,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
         struct ContinueExpr: AttrsOwner { T![continue], T![lifetime] }
         struct BreakExpr: AttrsOwner { T![break], T![lifetime], Expr }
         struct Label { T![lifetime] }
-        struct BlockExpr: AttrsOwner { Label, T![unsafe], T![async], Block }
+        struct BlockExpr: AttrsOwner { Label, T![unsafe], T![async], Block  }
         struct ReturnExpr: AttrsOwner { Expr }
         struct CallExpr: ArgListOwner { Expr }
         struct MethodCallExpr: AttrsOwner, ArgListOwner {
@@ -593,7 +595,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
             qualifier: Path,
         }
         struct PathSegment {
-            T![::], T![crate], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>]
+            T![::], T![crate], T![self], T![super], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>]
         }
         struct TypeArgList {
             T![::],
@@ -720,6 +722,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
             FieldExpr,
             AwaitExpr,
             TryExpr,
+            TryBlockExpr,
             CastExpr,
             RefExpr,
             PrefixExpr,


Test patch:
diff --git a/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast
new file mode 100644
index 0000000000..d0360c4679
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast
@@ -0,0 +1,70 @@
+SOURCE_FILE@0..67
+  USE_ITEM@0..12
+    USE_KW@0..3 "use"
+    WHITESPACE@3..4 " "
+    USE_TREE@4..11
+      PATH@4..11
+        PATH_SEGMENT@4..11
+          COLON2@4..6 "::"
+          SUPER_KW@6..11 "super"
+    SEMICOLON@11..12 ";"
+  WHITESPACE@12..13 "\n"
+  USE_ITEM@13..26
+    USE_KW@13..16 "use"
+    WHITESPACE@16..17 " "
+    USE_TREE@17..25
+      PATH@17..25
+        PATH@17..18
+          PATH_SEGMENT@17..18
+            NAME_REF@17..18
+              IDENT@17..18 "a"
+        COLON2@18..20 "::"
+        PATH_SEGMENT@20..25
+          SUPER_KW@20..25 "super"
+    SEMICOLON@25..26 ";"
+  WHITESPACE@26..27 "\n"
+  USE_ITEM@27..47
+    USE_KW@27..30 "use"
+    WHITESPACE@30..31 " "
+    USE_TREE@31..46
+      PATH@31..46
+        PATH@31..39
+          PATH@31..36
+            PATH_SEGMENT@31..36
+              SUPER_KW@31..36 "super"
+          COLON2@36..38 "::"
+          PATH_SEGMENT@38..39
+            NAME_REF@38..39
+              IDENT@38..39 "a"
+        COLON2@39..41 "::"
+        PATH_SEGMENT@41..46
+          SUPER_KW@41..46 "super"
+    SEMICOLON@46..47 ";"
+  WHITESPACE@47..48 "\n"
+  USE_ITEM@48..66
+    USE_KW@48..51 "use"
+    WHITESPACE@51..52 " "
+    USE_TREE@52..65
+      PATH@52..53
+        PATH_SEGMENT@52..53
+          NAME_REF@52..53
+            IDENT@52..53 "a"
+      COLON2@53..55 "::"
+      USE_TREE_LIST@55..65
+        L_CURLY@55..56 "{"
+        USE_TREE@56..64
+          PATH@56..64
+            PATH@56..61
+              PATH_SEGMENT@56..61
+                SUPER_KW@56..61 "super"
+            COLON2@61..63 "::"
+            PATH_SEGMENT@63..64
+              NAME_REF@63..64
+                IDENT@63..64 "b"
+        R_CURLY@64..65 "}"
+    SEMICOLON@65..66 ";"
+  WHITESPACE@66..67 "\n"
+error 6..11: The `super` keyword may only be preceded by other `super`s
+error 20..25: The `super` keyword may only be preceded by other `super`s
+error 41..46: The `super` keyword may only be preceded by other `super`s
+error 56..61: The `super` keyword may only be preceded by other `super`s
diff --git a/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rs b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rs
new file mode 100644
index 0000000000..bd4d580426
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rs
@@ -0,0 +1,4 @@
+use ::super;
+use a::super;
+use super::a::super;
+use a::{super::b};
diff --git a/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast
new file mode 100644
index 0000000000..4f382b06c4
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast
@@ -0,0 +1,27 @@
+SOURCE_FILE@0..25
+  USE_ITEM@0..11
+    USE_KW@0..3 "use"
+    WHITESPACE@3..4 " "
+    USE_TREE@4..10
+      PATH@4..10
+        PATH_SEGMENT@4..10
+          COLON2@4..6 "::"
+          SELF_KW@6..10 "self"
+    SEMICOLON@10..11 ";"
+  WHITESPACE@11..12 "\n"
+  USE_ITEM@12..24
+    USE_KW@12..15 "use"
+    WHITESPACE@15..16 " "
+    USE_TREE@16..23
+      PATH@16..23
+        PATH@16..17
+          PATH_SEGMENT@16..17
+            NAME_REF@16..17
+              IDENT@16..17 "a"
+        COLON2@17..19 "::"
+        PATH_SEGMENT@19..23
+          SELF_KW@19..23 "self"
+    SEMICOLON@23..24 ";"
+  WHITESPACE@24..25 "\n"
+error 6..10: The `self` keyword is only allowed as the first segment of a path
+error 19..23: The `self` keyword is only allowed as the first segment of a path
diff --git a/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rs b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rs
new file mode 100644
index 0000000000..b9e1d7d8be
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rs
@@ -0,0 +1,2 @@
+use ::self;
+use a::self;
diff --git a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast
index a5a90df7b2..05d9c05ad5 100644
--- a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast
@@ -1,4 +1,4 @@
-SOURCE_FILE@0..65
+SOURCE_FILE@0..38
   USE_ITEM@0..14
     USE_KW@0..3 "use"
     WHITESPACE@3..4 " "
@@ -31,27 +31,3 @@ SOURCE_FILE@0..65
             IDENT@33..36 "bar"
     SEMICOLON@36..37 ";"
   WHITESPACE@37..38 "\n"
-  USE_ITEM@38..64
-    USE_KW@38..41 "use"
-    WHITESPACE@41..42 " "
-    USE_TREE@42..63
-      PATH@42..63
-        PATH@42..58
-          PATH@42..51
-            PATH@42..48
-              PATH_SEGMENT@42..48
-                COLON2@42..44 "::"
-                SELF_KW@44..48 "self"
-            COLON2@48..50 "::"
-            PATH_SEGMENT@50..51
-              NAME_REF@50..51
-                IDENT@50..51 "a"
-          COLON2@51..53 "::"
-          PATH_SEGMENT@53..58
-            SUPER_KW@53..58 "super"
-        COLON2@58..60 "::"
-        PATH_SEGMENT@60..63
-          NAME_REF@60..63
-            IDENT@60..63 "bar"
-    SEMICOLON@63..64 ";"
-  WHITESPACE@64..65 "\n"
diff --git a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rs b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rs
index faf6a42c7b..9d9eb99175 100644
--- a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rs
+++ b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rs
@@ -1,3 +1,2 @@
 use self::foo;
 use super::super::bar;
-use ::self::a::super::bar;