Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit d073a85

Browse files
When resolving labels in break and continue for the IDE, do not resolve them textually, instead reuse the results of HIR lowering
This fixes a bug where labels inside macros were not resolved, but more importantly this prepares us to a future where we have hygiene, and textual equivalence isn't enough to resolve identifiers.
1 parent 8e4570a commit d073a85

File tree

3 files changed

+40
-24
lines changed

3 files changed

+40
-24
lines changed

src/tools/rust-analyzer/crates/hir/src/semantics.rs

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ use span::{EditionedFileId, FileId, HirFileIdRepr};
3636
use stdx::TupleExt;
3737
use syntax::{
3838
algo::skip_trivia_token,
39-
ast::{self, HasAttrs as _, HasGenericParams, HasLoopBody, IsString as _},
40-
match_ast, AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken,
41-
TextRange, TextSize,
39+
ast::{self, HasAttrs as _, HasGenericParams, IsString as _},
40+
AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange,
41+
TextSize,
4242
};
4343

4444
use crate::{
@@ -1221,26 +1221,10 @@ impl<'db> SemanticsImpl<'db> {
12211221
ToDef::to_def(self, src.as_ref())
12221222
}
12231223

1224-
pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
1225-
let text = lifetime.text();
1226-
let label = lifetime.syntax().ancestors().find_map(|syn| {
1227-
let label = match_ast! {
1228-
match syn {
1229-
ast::ForExpr(it) => it.label(),
1230-
ast::WhileExpr(it) => it.label(),
1231-
ast::LoopExpr(it) => it.label(),
1232-
ast::BlockExpr(it) => it.label(),
1233-
_ => None,
1234-
}
1235-
};
1236-
label.filter(|l| {
1237-
l.lifetime()
1238-
.and_then(|lt| lt.lifetime_ident_token())
1239-
.map_or(false, |lt| lt.text() == text)
1240-
})
1241-
})?;
1242-
let src = self.wrap_node_infile(label);
1243-
ToDef::to_def(self, src.as_ref())
1224+
pub fn resolve_label(&self, label: &ast::Lifetime) -> Option<Label> {
1225+
let (parent, label_id) = self
1226+
.with_ctx(|ctx| ctx.label_ref_to_def(self.wrap_node_infile(label.clone()).as_ref()))?;
1227+
Some(Label { parent, label_id })
12441228
}
12451229

12461230
pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {

src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ use hir_def::{
9292
keys::{self, Key},
9393
DynMap,
9494
},
95-
hir::{BindingId, LabelId},
95+
hir::{BindingId, Expr, LabelId},
9696
AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId,
9797
FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, Lookup, MacroId,
9898
ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, UseId,
@@ -343,6 +343,20 @@ impl SourceToDefCtx<'_, '_> {
343343
Some((container, label_id))
344344
}
345345

346+
pub(super) fn label_ref_to_def(
347+
&mut self,
348+
src: InFile<&ast::Lifetime>,
349+
) -> Option<(DefWithBodyId, LabelId)> {
350+
let break_or_continue = ast::Expr::cast(src.value.syntax().parent()?)?;
351+
let container = self.find_pat_or_label_container(src.syntax_ref())?;
352+
let (body, source_map) = self.db.body_with_source_map(container);
353+
let break_or_continue = source_map.node_expr(src.with_value(&break_or_continue))?;
354+
let (Expr::Break { label, .. } | Expr::Continue { label }) = body[break_or_continue] else {
355+
return None;
356+
};
357+
Some((container, label?))
358+
}
359+
346360
pub(super) fn item_to_macro_call(&mut self, src: InFile<&ast::Item>) -> Option<MacroCallId> {
347361
let map = self.dyn_map(src)?;
348362
map[keys::ATTR_MACRO_CALL].get(&AstPtr::new(src.value)).copied()

src/tools/rust-analyzer/crates/ide/src/goto_definition.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2660,6 +2660,24 @@ fn foo() {
26602660
);
26612661
}
26622662

2663+
#[test]
2664+
fn label_inside_macro() {
2665+
check(
2666+
r#"
2667+
macro_rules! m {
2668+
($s:stmt) => { $s };
2669+
}
2670+
2671+
fn foo() {
2672+
'label: loop {
2673+
// ^^^^^^
2674+
m!(continue 'label$0);
2675+
}
2676+
}
2677+
"#,
2678+
);
2679+
}
2680+
26632681
#[test]
26642682
fn goto_def_on_return_in_try() {
26652683
check(

0 commit comments

Comments
 (0)