]> git.lizzy.rs Git - rust.git/commitdiff
Merge #7128
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>
Sun, 3 Jan 2021 08:49:59 +0000 (08:49 +0000)
committerGitHub <noreply@github.com>
Sun, 3 Jan 2021 08:49:59 +0000 (08:49 +0000)
7128: Implement HasAttrs for GenericParam r=matklad a=Veykril

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
17 files changed:
crates/assists/src/handlers/extract_assignment.rs [new file with mode: 0644]
crates/assists/src/lib.rs
crates/assists/src/tests/generated.rs
crates/assists/src/utils.rs
crates/hir_def/src/attr.rs
crates/hir_def/src/path/lower.rs
crates/hir_expand/src/db.rs
crates/hir_expand/src/hygiene.rs
crates/hir_expand/src/lib.rs
crates/hir_ty/src/tests/macros.rs
crates/hir_ty/src/tests/regression.rs
crates/mbe/src/mbe_expander/matcher.rs
crates/mbe/src/mbe_expander/transcriber.rs
crates/mbe/src/parser.rs
crates/rust-analyzer/src/config.rs
crates/syntax/src/ast/edit.rs
xtask/src/dist.rs

diff --git a/crates/assists/src/handlers/extract_assignment.rs b/crates/assists/src/handlers/extract_assignment.rs
new file mode 100644 (file)
index 0000000..281cf5d
--- /dev/null
@@ -0,0 +1,325 @@
+use hir::AsName;
+use syntax::{
+    ast::{self, edit::AstNodeEdit, make},
+    AstNode,
+};
+use test_utils::mark;
+
+use crate::{
+    assist_context::{AssistContext, Assists},
+    AssistId, AssistKind,
+};
+
+// Assist: extract_assignment
+//
+// Extracts variable assigment to outside an if or match statement.
+//
+// ```
+// fn main() {
+//     let mut foo = 6;
+//
+//     if true {
+//         <|>foo = 5;
+//     } else {
+//         foo = 4;
+//     }
+// }
+// ```
+// ->
+// ```
+// fn main() {
+//     let mut foo = 6;
+//
+//     foo = if true {
+//         5
+//     } else {
+//         4
+//     };
+// }
+// ```
+pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+    let name = ctx.find_node_at_offset::<ast::NameRef>()?.as_name();
+
+    let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() {
+        (
+            ast::Expr::cast(if_expr.syntax().to_owned())?,
+            exprify_if(&if_expr, &name)?.indent(if_expr.indent_level()),
+        )
+    } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() {
+        (ast::Expr::cast(match_expr.syntax().to_owned())?, exprify_match(&match_expr, &name)?)
+    } else {
+        return None;
+    };
+
+    let expr_stmt = make::expr_stmt(new_stmt);
+
+    acc.add(
+        AssistId("extract_assignment", AssistKind::RefactorExtract),
+        "Extract assignment",
+        old_stmt.syntax().text_range(),
+        move |edit| {
+            edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name, expr_stmt));
+        },
+    )
+}
+
+fn exprify_match(match_expr: &ast::MatchExpr, name: &hir::Name) -> Option<ast::Expr> {
+    let new_arm_list = match_expr
+        .match_arm_list()?
+        .arms()
+        .map(|arm| {
+            if let ast::Expr::BlockExpr(block) = arm.expr()? {
+                let new_block = exprify_block(&block, name)?.indent(block.indent_level());
+                Some(arm.replace_descendant(block, new_block))
+            } else {
+                None
+            }
+        })
+        .collect::<Option<Vec<_>>>()?;
+    let new_arm_list = match_expr
+        .match_arm_list()?
+        .replace_descendants(match_expr.match_arm_list()?.arms().zip(new_arm_list));
+    Some(make::expr_match(match_expr.expr()?, new_arm_list))
+}
+
+fn exprify_if(statement: &ast::IfExpr, name: &hir::Name) -> Option<ast::Expr> {
+    let then_branch = exprify_block(&statement.then_branch()?, name)?;
+    let else_branch = match statement.else_branch()? {
+        ast::ElseBranch::Block(ref block) => ast::ElseBranch::Block(exprify_block(block, name)?),
+        ast::ElseBranch::IfExpr(expr) => {
+            mark::hit!(test_extract_assigment_chained_if);
+            ast::ElseBranch::IfExpr(ast::IfExpr::cast(
+                exprify_if(&expr, name)?.syntax().to_owned(),
+            )?)
+        }
+    };
+    Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch)))
+}
+
+fn exprify_block(block: &ast::BlockExpr, name: &hir::Name) -> Option<ast::BlockExpr> {
+    if block.expr().is_some() {
+        return None;
+    }
+
+    let mut stmts: Vec<_> = block.statements().collect();
+    let stmt = stmts.pop()?;
+
+    if let ast::Stmt::ExprStmt(stmt) = stmt {
+        if let ast::Expr::BinExpr(expr) = stmt.expr()? {
+            if expr.op_kind()? == ast::BinOp::Assignment
+                && &expr.lhs()?.name_ref()?.as_name() == name
+            {
+                // The last statement in the block is an assignment to the name we want
+                return Some(make::block_expr(stmts, Some(expr.rhs()?)));
+            }
+        }
+    }
+    None
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    #[test]
+    fn test_extract_assignment_if() {
+        check_assist(
+            extract_assigment,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    if true {
+        <|>a = 2;
+    } else {
+        a = 3;
+    }
+}"#,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    a = if true {
+        2
+    } else {
+        3
+    };
+}"#,
+        );
+    }
+
+    #[test]
+    fn test_extract_assignment_match() {
+        check_assist(
+            extract_assigment,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    match 1 {
+        1 => {
+            <|>a = 2;
+        },
+        2 => {
+            a = 3;
+        },
+        3 => {
+            a = 4;
+        }
+    }
+}"#,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    a = match 1 {
+        1 => {
+            2
+        },
+        2 => {
+            3
+        },
+        3 => {
+            4
+        }
+    };
+}"#,
+        );
+    }
+
+    #[test]
+    fn test_extract_assignment_not_last_not_applicable() {
+        check_assist_not_applicable(
+            extract_assigment,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    if true {
+        <|>a = 2;
+        b = a;
+    } else {
+        a = 3;
+    }
+}"#,
+        )
+    }
+
+    #[test]
+    fn test_extract_assignment_chained_if() {
+        mark::check!(test_extract_assigment_chained_if);
+        check_assist(
+            extract_assigment,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    if true {
+        <|>a = 2;
+    } else if false {
+        a = 3;
+    } else {
+        a = 4;
+    }
+}"#,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    a = if true {
+        2
+    } else if false {
+        3
+    } else {
+        4
+    };
+}"#,
+        );
+    }
+
+    #[test]
+    fn test_extract_assigment_retains_stmts() {
+        check_assist(
+            extract_assigment,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    if true {
+        let b = 2;
+        <|>a = 2;
+    } else {
+        let b = 3;
+        a = 3;
+    }
+}"#,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    a = if true {
+        let b = 2;
+        2
+    } else {
+        let b = 3;
+        3
+    };
+}"#,
+        )
+    }
+
+    #[test]
+    fn extract_assignment_let_stmt_not_applicable() {
+        check_assist_not_applicable(
+            extract_assigment,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    let b = if true {
+        <|>a = 2
+    } else {
+        a = 3
+    };
+}"#,
+        )
+    }
+
+    #[test]
+    fn extract_assignment_if_missing_assigment_not_applicable() {
+        check_assist_not_applicable(
+            extract_assigment,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    if true {
+        <|>a = 2;
+    } else {}
+}"#,
+        )
+    }
+
+    #[test]
+    fn extract_assignment_match_missing_assigment_not_applicable() {
+        check_assist_not_applicable(
+            extract_assigment,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    match 1 {
+        1 => {
+            <|>a = 2;
+        },
+        2 => {
+            a = 3;
+        },
+        3 => {},
+    }
+}"#,
+        )
+    }
+}
index fdec886e9d80fc13d61a6fbd5b6cbc1a32e259b3..212464f859d48dddb341f2b96455621784d7d3e2 100644 (file)
@@ -116,6 +116,7 @@ mod handlers {
     mod convert_integer_literal;
     mod early_return;
     mod expand_glob_import;
+    mod extract_assignment;
     mod extract_module_to_file;
     mod extract_struct_from_enum_variant;
     mod extract_variable;
@@ -167,6 +168,7 @@ pub(crate) fn all() -> &'static [Handler] {
             convert_integer_literal::convert_integer_literal,
             early_return::convert_to_guarded_return,
             expand_glob_import::expand_glob_import,
+            extract_assignment::extract_assigment,
             extract_module_to_file::extract_module_to_file,
             extract_struct_from_enum_variant::extract_struct_from_enum_variant,
             extract_variable::extract_variable,
index d3dfe24e7c6834358d917f06b4aa3e9f5028395c..b91a816e89892504a1c0181a691f29cb486edf2b 100644 (file)
@@ -237,6 +237,35 @@ fn qux(bar: Bar, baz: Baz) {}
     )
 }
 
+#[test]
+fn doctest_extract_assignment() {
+    check_doc_test(
+        "extract_assignment",
+        r#####"
+fn main() {
+    let mut foo = 6;
+
+    if true {
+        <|>foo = 5;
+    } else {
+        foo = 4;
+    }
+}
+"#####,
+        r#####"
+fn main() {
+    let mut foo = 6;
+
+    foo = if true {
+        5
+    } else {
+        4
+    };
+}
+"#####,
+    )
+}
+
 #[test]
 fn doctest_extract_module_to_file() {
     check_doc_test(
index d41084b59944daad1b91e6827bd2c3119b7ef730..5a6125534f8b3860c6e20b462a53e5c63e787856 100644 (file)
@@ -94,7 +94,7 @@ fn has_def_name(item: &ast::AssocItem) -> bool {
             ast::AssocItem::MacroCall(_) => None,
         }
         .is_some()
-    };
+    }
 
     items
         .iter()
index 86ae2f0fa9d648778f9063d231864ffa4ea36bb5..6b79e7badf3287f832bee82edaab27f39c75fd5b 100644 (file)
@@ -279,14 +279,13 @@ pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
     }
 
     pub fn docs(&self) -> Option<Documentation> {
-        let docs = self
-            .by_key("doc")
-            .attrs()
-            .flat_map(|attr| match attr.input.as_ref()? {
-                AttrInput::Literal(s) => Some(s),
-                AttrInput::TokenTree(_) => None,
-            })
-            .intersperse(&SmolStr::new_inline("\n"))
+        let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? {
+            AttrInput::Literal(s) => Some(s),
+            AttrInput::TokenTree(_) => None,
+        });
+        // FIXME: Replace `Itertools::intersperse` with `Iterator::intersperse[_with]` until the
+        // libstd api gets stabilized (https://github.com/rust-lang/rust/issues/79524).
+        let docs = Itertools::intersperse(docs, &SmolStr::new_inline("\n"))
             .map(|it| it.as_str())
             .collect::<String>();
         if docs.is_empty() {
index 8a01e6eead0fa41c9997df1e04398222ceab1736..9518ac109be5f6f4858fecc0839bc6617be9225e 100644 (file)
@@ -123,7 +123,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
     // We follow what it did anyway :)
     if segments.len() == 1 && kind == PathKind::Plain {
         if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
-            if let Some(crate_id) = hygiene.local_inner_macros() {
+            if let Some(crate_id) = hygiene.local_inner_macros(path) {
                 kind = PathKind::DollarCrate(crate_id);
             }
         }
index 06f0a3ed9cc423f76b86298523bb0137f78c2489..0a0d021e055381e871162f938dc8739e16242ac7 100644 (file)
@@ -404,7 +404,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
         TRY_EXPR => FragmentKind::Expr,
         TUPLE_EXPR => FragmentKind::Expr,
         PAREN_EXPR => FragmentKind::Expr,
-
+        ARRAY_EXPR => FragmentKind::Expr,
         FOR_EXPR => FragmentKind::Expr,
         PATH_EXPR => FragmentKind::Expr,
         CLOSURE_EXPR => FragmentKind::Expr,
index 7ab0a5e52eb071751df865f6d9cb4d9448cd8460..6042e15b2280b0d9d2a9a97bbd0c04ccebcccd20 100644 (file)
@@ -2,30 +2,94 @@
 //!
 //! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at
 //! this moment, this is horribly incomplete and handles only `$crate`.
+use std::sync::Arc;
+
+use arena::{Arena, Idx};
 use base_db::CrateId;
 use either::Either;
-use syntax::ast;
+use mbe::Origin;
+use syntax::{ast, AstNode};
 
 use crate::{
     db::AstDatabase,
     name::{AsName, Name},
-    HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind,
+    ExpansionInfo, HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind,
 };
 
 #[derive(Clone, Debug)]
 pub struct Hygiene {
-    // This is what `$crate` expands to
-    def_crate: Option<CrateId>,
+    frames: Option<Arc<HygieneFrames>>,
+}
+
+impl Hygiene {
+    pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene {
+        Hygiene { frames: Some(Arc::new(HygieneFrames::new(db, file_id.clone()))) }
+    }
+
+    pub fn new_unhygienic() -> Hygiene {
+        Hygiene { frames: None }
+    }
+
+    // FIXME: this should just return name
+    pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> {
+        if let Some(frames) = &self.frames {
+            if name_ref.text() == "$crate" {
+                if let Some(krate) = frames.root_crate(&name_ref) {
+                    return Either::Right(krate);
+                }
+            }
+        }
+
+        Either::Left(name_ref.as_name())
+    }
+
+    pub fn local_inner_macros(&self, path: ast::Path) -> Option<CrateId> {
+        let frames = self.frames.as_ref()?;
+
+        let mut token = path.syntax().first_token()?;
+        let mut current = frames.first();
+
+        while let Some((frame, data)) =
+            current.and_then(|it| Some((it, it.expansion.as_ref()?.map_token_up(&token)?)))
+        {
+            let (mapped, origin) = data;
+            if origin == Origin::Def {
+                return if frame.local_inner { frame.krate } else { None };
+            }
+            current = Some(&frames.0[frame.call_site?]);
+            token = mapped.value;
+        }
+        None
+    }
+}
+
+#[derive(Default, Debug)]
+struct HygieneFrames(Arena<HygieneFrame>);
+
+#[derive(Clone, Debug)]
+struct HygieneFrame {
+    expansion: Option<ExpansionInfo>,
 
     // Indicate this is a local inner macro
     local_inner: bool,
+    krate: Option<CrateId>,
+
+    call_site: Option<Idx<HygieneFrame>>,
+    def_site: Option<Idx<HygieneFrame>>,
 }
 
-impl Hygiene {
-    pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene {
-        let (def_crate, local_inner) = match file_id.0 {
+impl HygieneFrames {
+    fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self {
+        let mut frames = HygieneFrames::default();
+        frames.add(db, file_id);
+        frames
+    }
+
+    fn add(&mut self, db: &dyn AstDatabase, file_id: HirFileId) -> Option<Idx<HygieneFrame>> {
+        let (krate, local_inner) = match file_id.0 {
             HirFileIdRepr::FileId(_) => (None, false),
             HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id {
+                MacroCallId::EagerMacro(_id) => (None, false),
                 MacroCallId::LazyMacro(id) => {
                     let loc = db.lookup_intern_macro(id);
                     match loc.def.kind {
@@ -36,31 +100,68 @@ pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene {
                         MacroDefKind::ProcMacro(_) => (None, false),
                     }
                 }
-                MacroCallId::EagerMacro(_id) => (None, false),
             },
         };
-        Hygiene { def_crate, local_inner }
-    }
 
-    pub fn new_unhygienic() -> Hygiene {
-        Hygiene { def_crate: None, local_inner: false }
+        let expansion = file_id.expansion_info(db);
+        let expansion = match expansion {
+            None => {
+                return Some(self.0.alloc(HygieneFrame {
+                    expansion: None,
+                    local_inner,
+                    krate,
+                    call_site: None,
+                    def_site: None,
+                }));
+            }
+            Some(it) => it,
+        };
+
+        let def_site = expansion.def.clone();
+        let call_site = expansion.arg.file_id;
+        let idx = self.0.alloc(HygieneFrame {
+            expansion: Some(expansion),
+            local_inner,
+            krate,
+            call_site: None,
+            def_site: None,
+        });
+
+        self.0[idx].call_site = self.add(db, call_site);
+        self.0[idx].def_site = def_site.and_then(|it| self.add(db, it.file_id));
+
+        Some(idx)
     }
 
-    // FIXME: this should just return name
-    pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> {
-        if let Some(def_crate) = self.def_crate {
-            if name_ref.text() == "$crate" {
-                return Either::Right(def_crate);
-            }
-        }
-        Either::Left(name_ref.as_name())
+    fn first(&self) -> Option<&HygieneFrame> {
+        self.0.iter().next().map(|it| it.1)
     }
 
-    pub fn local_inner_macros(&self) -> Option<CrateId> {
-        if self.local_inner {
-            self.def_crate
-        } else {
-            None
+    fn root_crate(&self, name_ref: &ast::NameRef) -> Option<CrateId> {
+        let mut token = name_ref.syntax().first_token()?;
+        let first = self.first()?;
+        let mut result = first.krate;
+        let mut current = Some(first);
+
+        while let Some((frame, (mapped, origin))) =
+            current.and_then(|it| Some((it, it.expansion.as_ref()?.map_token_up(&token)?)))
+        {
+            result = frame.krate;
+
+            let site = match origin {
+                Origin::Def => frame.def_site,
+                Origin::Call => frame.call_site,
+            };
+
+            let site = match site {
+                None => break,
+                Some(it) => it,
+            };
+
+            current = Some(&self.0[site]);
+            token = mapped.value;
         }
+
+        result
     }
 }
index 3fa1b1d776f8302c45a1e4de7bd9d8cce114ff52..5b6734a5f4e7d573f49209ba02913b6d3fd414a6 100644 (file)
@@ -340,11 +340,8 @@ pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option<InFile<Synta
         Some(self.expanded.with_value(token))
     }
 
-    pub fn map_token_up(
-        &self,
-        token: InFile<&SyntaxToken>,
-    ) -> Option<(InFile<SyntaxToken>, Origin)> {
-        let token_id = self.exp_map.token_by_range(token.value.text_range())?;
+    pub fn map_token_up(&self, token: &SyntaxToken) -> Option<(InFile<SyntaxToken>, Origin)> {
+        let token_id = self.exp_map.token_by_range(token.text_range())?;
 
         let (token_id, origin) = self.macro_def.0.map_id_up(token_id);
         let (token_map, tt) = match origin {
@@ -359,7 +356,7 @@ pub fn map_token_up(
             ),
         };
 
-        let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
+        let range = token_map.range_by_token(token_id)?.by_kind(token.kind())?;
         let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start())
             .into_token()?;
         Some((tt.with_value(token), origin))
@@ -495,7 +492,7 @@ fn ascend_call_token(
     expansion: &ExpansionInfo,
     token: InFile<SyntaxToken>,
 ) -> Option<InFile<SyntaxToken>> {
-    let (mapped, origin) = expansion.map_token_up(token.as_ref())?;
+    let (mapped, origin) = expansion.map_token_up(&token.value)?;
     if origin != Origin::Call {
         return None;
     }
index a7656b864865cc832075467f4ae03211b52eb7b8..23b79abc45f2437250f4df50b41f2ecddd755263 100644 (file)
@@ -370,6 +370,37 @@ fn deref(&self) ->  &Self::Target {
     );
 }
 
+#[test]
+fn infer_macro_with_dollar_crate_in_def_site() {
+    check_types(
+        r#"
+//- /main.rs crate:main deps:foo
+use foo::expand;
+
+macro_rules! list {
+    ($($tt:tt)*) => { $($tt)* }
+}
+
+fn test() {
+    let r = expand!();
+    r;
+  //^ u128
+}
+
+//- /lib.rs crate:foo
+#[macro_export]
+macro_rules! expand {
+    () => { list!($crate::m!()) };
+}
+
+#[macro_export]
+macro_rules! m {
+    () => { 0u128 };
+}
+"#,
+    );
+}
+
 #[test]
 fn infer_type_value_non_legacy_macro_use_as() {
     check_infer(
index 307a257b177098e8637854c8e325e3e128345328..cffe8630b47350215e2c43930953c4ffac523636 100644 (file)
@@ -325,6 +325,24 @@ fn test() {
     );
 }
 
+#[test]
+fn infer_array_macro_call() {
+    check_infer(
+        r#"
+        macro_rules! bar { () => {0u32} }
+        fn test() {
+            let a = [bar!()];
+        }
+        "#,
+        expect![[r#"
+            !0..4 '0u32': u32
+            44..69 '{     ...()]; }': ()
+            54..55 'a': [u32; _]
+            58..66 '[bar!()]': [u32; _]
+        "#]],
+    );
+}
+
 #[test]
 fn bug_1030() {
     check_infer(
index ab5f87c487ce6b910fdff0eb7ac6012340a7803f..385b4660187f8f29a369cac5c1d2dc146e8ed41f 100644 (file)
@@ -150,7 +150,7 @@ fn match_subtree(
                     res.add_err(err!("leftover tokens"));
                 }
             }
-            Op::Var { name, kind } => {
+            Op::Var { name, kind, .. } => {
                 let kind = match kind {
                     Some(k) => k,
                     None => {
index 7205312371d16686392dac48c7921e0d75b52258..57f3f104dcaa77707c5be1f53bc63299086cf1aa 100644 (file)
@@ -100,8 +100,8 @@ fn expand_subtree(
                 err = err.or(e);
                 arena.push(tt.into());
             }
-            Op::Var { name, .. } => {
-                let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name);
+            Op::Var { name, id, .. } => {
+                let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name, *id);
                 err = err.or(e);
                 push_fragment(arena, fragment);
             }
@@ -118,12 +118,10 @@ fn expand_subtree(
     ExpandResult { value: tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err }
 }
 
-fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> {
+fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> {
     if v == "crate" {
         // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.
-        let tt =
-            tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() })
-                .into();
+        let tt = tt::Leaf::from(tt::Ident { text: "$crate".into(), id }).into();
         ExpandResult::ok(Fragment::Tokens(tt))
     } else if !ctx.bindings.contains(v) {
         // Note that it is possible to have a `$var` inside a macro which is not bound.
@@ -142,14 +140,8 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> {
         let tt = tt::Subtree {
             delimiter: None,
             token_trees: vec![
-                tt::Leaf::from(tt::Punct {
-                    char: '$',
-                    spacing: tt::Spacing::Alone,
-                    id: tt::TokenId::unspecified(),
-                })
-                .into(),
-                tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() })
-                    .into(),
+                tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, id }).into(),
+                tt::Leaf::from(tt::Ident { text: v.clone(), id }).into(),
             ],
         }
         .into();
index 2f3ebc831397675f95741762ac11eaa3280acb50..77cc739b65707d6a3e09df2d955bb361df466451 100644 (file)
@@ -8,7 +8,7 @@
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum Op {
-    Var { name: SmolStr, kind: Option<SmolStr> },
+    Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId },
     Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> },
     Leaf(tt::Leaf),
     Subtree(MetaTemplate),
@@ -106,18 +106,21 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
                         }
                         let name = UNDERSCORE.clone();
                         let kind = eat_fragment_kind(src, mode)?;
-                        Op::Var { name, kind }
+                        let id = punct.id;
+                        Op::Var { name, kind, id }
                     }
                     tt::Leaf::Ident(ident) => {
                         let name = ident.text.clone();
                         let kind = eat_fragment_kind(src, mode)?;
-                        Op::Var { name, kind }
+                        let id = ident.id;
+                        Op::Var { name, kind, id }
                     }
                     tt::Leaf::Literal(lit) => {
                         if is_boolean_literal(&lit) {
                             let name = lit.text.clone();
                             let kind = eat_fragment_kind(src, mode)?;
-                            Op::Var { name, kind }
+                            let id = lit.id;
+                            Op::Var { name, kind, id }
                         } else {
                             bail!("bad var 2");
                         }
index 1db5b4e7dd9b9757359f542a4a83ae9af2fde67d..685a9fdf09683431bd68cc18f4a5677078d50962 100644 (file)
@@ -679,7 +679,7 @@ fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json:
     for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) {
         fn key(f: &str) -> &str {
             f.splitn(2, "_").next().unwrap()
-        };
+        }
         assert!(key(f1) <= key(f2), "wrong field order: {:?} {:?}", f1, f2);
     }
 
index 77233ab31a30424686c1c1535f55988c9cca1b49..824ebf41cf9575654f2637b46c1ecf16eae340ec 100644 (file)
@@ -220,7 +220,7 @@ macro_rules! after_field {
                     InsertPosition::After($anchor.syntax().clone().into())
                 }
             };
-        };
+        }
 
         let position = match position {
             InsertPosition::First => after_l_curly!(),
@@ -533,7 +533,7 @@ macro_rules! after_field {
                     InsertPosition::After($anchor.syntax().clone().into())
                 }
             };
-        };
+        }
 
         let position = match self.generic_params().last() {
             Some(it) => after_field!(it),
index d59b88131a23765c81c5df817076c4b9ac10ac6e..6bc34106b66c4e41825ccadfdb3f04682fd5c9ea 100644 (file)
@@ -63,8 +63,7 @@ fn dist_server() -> Result<()> {
         env::set_var("CC", "clang");
     }
 
-    let toolchain = toolchain(&target);
-    cmd!("cargo +{toolchain} build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --release").run()?;
+    cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --release").run()?;
 
     let suffix = exe_suffix(&target);
     let src =
@@ -118,13 +117,6 @@ fn exe_suffix(target: &str) -> String {
     }
 }
 
-fn toolchain(target: &str) -> String {
-    match target {
-        "aarch64-apple-darwin" => "beta".to_string(),
-        _ => "stable".to_string(),
-    }
-}
-
 fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
     let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
     let mut input = io::BufReader::new(File::open(src_path)?);