Skip to content

Commit 0e71179

Browse files
committed
internal: Resolve labels in body lowering
1 parent e9e5772 commit 0e71179

File tree

13 files changed

+420
-182
lines changed

13 files changed

+420
-182
lines changed

crates/hir-def/src/body.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ use cfg::{CfgExpr, CfgOptions};
1313
use drop_bomb::DropBomb;
1414
use either::Either;
1515
use hir_expand::{
16-
attrs::RawAttrs, hygiene::Hygiene, ExpandError, ExpandResult, HirFileId, InFile, MacroCallId,
16+
attrs::RawAttrs, hygiene::Hygiene, name::Name, ExpandError, ExpandResult, HirFileId, InFile,
17+
MacroCallId,
1718
};
1819
use la_arena::{Arena, ArenaMap};
1920
use limit::Limit;
@@ -343,6 +344,8 @@ pub enum BodyDiagnostic {
343344
MacroError { node: InFile<AstPtr<ast::MacroCall>>, message: String },
344345
UnresolvedProcMacro { node: InFile<AstPtr<ast::MacroCall>>, krate: CrateId },
345346
UnresolvedMacroCall { node: InFile<AstPtr<ast::MacroCall>>, path: ModPath },
347+
UnreachableLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name },
348+
UndeclaredLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name },
346349
}
347350

348351
impl Body {

crates/hir-def/src/body/lower.rs

Lines changed: 199 additions & 76 deletions
Large diffs are not rendered by default.

crates/hir-def/src/body/pretty.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,14 +219,14 @@ impl<'a> Printer<'a> {
219219
}
220220
Expr::Continue { label } => {
221221
w!(self, "continue");
222-
if let Some(label) = label {
223-
w!(self, " {}", label);
222+
if let Some(lbl) = label {
223+
w!(self, " {}", self.body[*lbl].name);
224224
}
225225
}
226226
Expr::Break { expr, label } => {
227227
w!(self, "break");
228-
if let Some(label) = label {
229-
w!(self, " {}", label);
228+
if let Some(lbl) = label {
229+
w!(self, " {}", self.body[*lbl].name);
230230
}
231231
if let Some(expr) = expr {
232232
self.whitespace();

crates/hir-def/src/expr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,11 @@ pub enum Expr {
168168
arms: Box<[MatchArm]>,
169169
},
170170
Continue {
171-
label: Option<Name>,
171+
label: Option<LabelId>,
172172
},
173173
Break {
174174
expr: Option<ExprId>,
175-
label: Option<Name>,
175+
label: Option<LabelId>,
176176
},
177177
Return {
178178
expr: Option<ExprId>,

crates/hir-expand/src/name.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,7 @@ impl Name {
120120
use std::sync::atomic::{AtomicUsize, Ordering};
121121
static CNT: AtomicUsize = AtomicUsize::new(0);
122122
let c = CNT.fetch_add(1, Ordering::Relaxed);
123-
// FIXME: Currently a `__RA_generated_name` in user code will break our analysis
124-
Name::new_text(format!("__RA_geneated_name_{c}").into())
123+
Name::new_text(format!("<ra@gennew>{c}").into())
125124
}
126125

127126
/// Returns the tuple index this name represents if it is a tuple field.

crates/hir-ty/src/infer.rs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use std::{convert::identity, ops::Index};
1818

1919
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
2020
use either::Either;
21+
use hir_def::expr::LabelId;
2122
use hir_def::{
2223
body::Body,
2324
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
@@ -188,12 +189,6 @@ pub enum InferenceDiagnostic {
188189
/// Contains the type the field resolves to
189190
field_with_same_name: Option<Ty>,
190191
},
191-
// FIXME: Make this proper
192-
BreakOutsideOfLoop {
193-
expr: ExprId,
194-
is_break: bool,
195-
bad_value_break: bool,
196-
},
197192
MismatchedArgCount {
198193
call_expr: ExprId,
199194
expected: usize,
@@ -468,7 +463,7 @@ struct BreakableContext {
468463
/// The coercion target of the context.
469464
coerce: Option<CoerceMany>,
470465
/// The optional label of the context.
471-
label: Option<name::Name>,
466+
label: Option<LabelId>,
472467
kind: BreakableKind,
473468
}
474469

@@ -483,28 +478,18 @@ enum BreakableKind {
483478

484479
fn find_breakable<'c>(
485480
ctxs: &'c mut [BreakableContext],
486-
label: Option<&name::Name>,
481+
label: Option<LabelId>,
487482
) -> Option<&'c mut BreakableContext> {
488483
let mut ctxs = ctxs
489484
.iter_mut()
490485
.rev()
491486
.take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop));
492487
match label {
493-
Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label),
488+
Some(_) => ctxs.find(|ctx| ctx.label == label),
494489
None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)),
495490
}
496491
}
497492

498-
fn find_continuable<'c>(
499-
ctxs: &'c mut [BreakableContext],
500-
label: Option<&name::Name>,
501-
) -> Option<&'c mut BreakableContext> {
502-
match label {
503-
Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
504-
None => find_breakable(ctxs, label),
505-
}
506-
}
507-
508493
impl<'a> InferenceContext<'a> {
509494
fn new(
510495
db: &'a dyn HirDatabase,

crates/hir-ty/src/infer/expr.rs

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@ use syntax::ast::RangeOp;
2525
use crate::{
2626
autoderef::{builtin_deref, deref_by_trait, Autoderef},
2727
consteval,
28-
infer::{
29-
coerce::CoerceMany, find_continuable, pat::contains_explicit_ref_binding, BreakableKind,
30-
},
28+
infer::{coerce::CoerceMany, pat::contains_explicit_ref_binding, BreakableKind},
3129
lang_items::lang_items_for_bin_op,
3230
lower::{
3331
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
@@ -459,29 +457,13 @@ impl<'a> InferenceContext<'a> {
459457
self.resolver.reset_to_guard(g);
460458
ty
461459
}
462-
Expr::Continue { label } => {
463-
if let None = find_continuable(&mut self.breakables, label.as_ref()) {
464-
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
465-
expr: tgt_expr,
466-
is_break: false,
467-
bad_value_break: false,
468-
});
469-
};
470-
self.result.standard_types.never.clone()
471-
}
472-
Expr::Break { expr, label } => {
473-
let val_ty = if let Some(expr) = *expr {
474-
let opt_coerce_to = match find_breakable(&mut self.breakables, label.as_ref()) {
460+
Expr::Continue { .. } => self.result.standard_types.never.clone(),
461+
&Expr::Break { expr, label } => {
462+
let val_ty = if let Some(expr) = expr {
463+
let opt_coerce_to = match find_breakable(&mut self.breakables, label) {
475464
Some(ctxt) => match &ctxt.coerce {
476465
Some(coerce) => coerce.expected_ty(),
477-
None => {
478-
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
479-
expr: tgt_expr,
480-
is_break: true,
481-
bad_value_break: true,
482-
});
483-
self.err_ty()
484-
}
466+
None => self.err_ty(),
485467
},
486468
None => self.err_ty(),
487469
};
@@ -490,26 +472,20 @@ impl<'a> InferenceContext<'a> {
490472
TyBuilder::unit()
491473
};
492474

493-
match find_breakable(&mut self.breakables, label.as_ref()) {
475+
match find_breakable(&mut self.breakables, label) {
494476
Some(ctxt) => match ctxt.coerce.take() {
495477
Some(mut coerce) => {
496-
coerce.coerce(self, *expr, &val_ty);
478+
coerce.coerce(self, expr, &val_ty);
497479

498480
// Avoiding borrowck
499-
let ctxt = find_breakable(&mut self.breakables, label.as_ref())
481+
let ctxt = find_breakable(&mut self.breakables, label)
500482
.expect("breakable stack changed during coercion");
501483
ctxt.may_break = true;
502484
ctxt.coerce = Some(coerce);
503485
}
504486
None => ctxt.may_break = true,
505487
},
506-
None => {
507-
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
508-
expr: tgt_expr,
509-
is_break: true,
510-
bad_value_break: false,
511-
});
512-
}
488+
None => {}
513489
}
514490
self.result.standard_types.never.clone()
515491
}
@@ -1900,7 +1876,6 @@ impl<'a> InferenceContext<'a> {
19001876
cb: impl FnOnce(&mut Self) -> T,
19011877
) -> (Option<Ty>, T) {
19021878
self.breakables.push({
1903-
let label = label.map(|label| self.body[label].name.clone());
19041879
BreakableContext { kind, may_break: false, coerce: ty.map(CoerceMany::new), label }
19051880
});
19061881
let res = cb(self);

crates/hir-ty/src/mir/lower.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ struct MirLowerCtx<'a> {
4747
current_loop_blocks: Option<LoopBlocks>,
4848
// FIXME: we should resolve labels in HIR lowering and always work with label id here, not
4949
// with raw names.
50-
labeled_loop_blocks: FxHashMap<Name, LoopBlocks>,
50+
labeled_loop_blocks: FxHashMap<LabelId, LoopBlocks>,
5151
discr_temp: Option<Place>,
5252
db: &'a dyn HirDatabase,
5353
body: &'a Body,
@@ -579,19 +579,19 @@ impl MirLowerCtx<'_> {
579579
Ok(None)
580580
}
581581
},
582-
Expr::Break { expr, label } => {
582+
&Expr::Break { expr, label } => {
583583
if let Some(expr) = expr {
584584
let loop_data = match label {
585-
Some(l) => self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)?,
585+
Some(l) => self.labeled_loop_blocks.get(&l).ok_or(MirLowerError::UnresolvedLabel)?,
586586
None => self.current_loop_blocks.as_ref().ok_or(MirLowerError::BreakWithoutLoop)?,
587587
};
588-
let Some(c) = self.lower_expr_to_place(*expr, loop_data.place.clone(), current)? else {
588+
let Some(c) = self.lower_expr_to_place(expr, loop_data.place.clone(), current)? else {
589589
return Ok(None);
590590
};
591591
current = c;
592592
}
593593
let end = match label {
594-
Some(l) => self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)?.end.expect("We always generate end for labeled loops"),
594+
Some(l) => self.labeled_loop_blocks.get(&l).ok_or(MirLowerError::UnresolvedLabel)?.end.expect("We always generate end for labeled loops"),
595595
None => self.current_loop_end()?,
596596
};
597597
self.set_goto(current, end);
@@ -1119,10 +1119,8 @@ impl MirLowerCtx<'_> {
11191119
// bad as we may emit end (unneccessary unreachable block) for unterminating loop, but
11201120
// it should not affect correctness.
11211121
self.current_loop_end()?;
1122-
self.labeled_loop_blocks.insert(
1123-
self.body.labels[label].name.clone(),
1124-
self.current_loop_blocks.as_ref().unwrap().clone(),
1125-
)
1122+
self.labeled_loop_blocks
1123+
.insert(label, self.current_loop_blocks.as_ref().unwrap().clone())
11261124
} else {
11271125
None
11281126
};
@@ -1131,7 +1129,7 @@ impl MirLowerCtx<'_> {
11311129
let my = mem::replace(&mut self.current_loop_blocks, prev)
11321130
.ok_or(MirLowerError::ImplementationError("current_loop_blocks is corrupt"))?;
11331131
if let Some(prev) = prev_label {
1134-
self.labeled_loop_blocks.insert(self.body.labels[label.unwrap()].name.clone(), prev);
1132+
self.labeled_loop_blocks.insert(label.unwrap(), prev);
11351133
}
11361134
Ok(my.end)
11371135
}

crates/hir/src/diagnostics.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ macro_rules! diagnostics {
3232
}
3333

3434
diagnostics![
35-
BreakOutsideOfLoop,
3635
ExpectedFunction,
3736
InactiveCode,
3837
IncorrectCase,
@@ -50,7 +49,9 @@ diagnostics![
5049
PrivateField,
5150
ReplaceFilterMapNextWithFindMap,
5251
TypeMismatch,
52+
UndeclaredLabel,
5353
UnimplementedBuiltinMacro,
54+
UnreachableLabel,
5455
UnresolvedExternCrate,
5556
UnresolvedField,
5657
UnresolvedImport,
@@ -84,6 +85,17 @@ pub struct UnresolvedMacroCall {
8485
pub path: ModPath,
8586
pub is_bang: bool,
8687
}
88+
#[derive(Debug, Clone, Eq, PartialEq)]
89+
pub struct UnreachableLabel {
90+
pub node: InFile<AstPtr<ast::Lifetime>>,
91+
pub name: Name,
92+
}
93+
94+
#[derive(Debug, Clone, Eq, PartialEq)]
95+
pub struct UndeclaredLabel {
96+
pub node: InFile<AstPtr<ast::Lifetime>>,
97+
pub name: Name,
98+
}
8799

88100
#[derive(Debug, Clone, Eq, PartialEq)]
89101
pub struct InactiveCode {
@@ -166,13 +178,6 @@ pub struct PrivateField {
166178
pub field: Field,
167179
}
168180

169-
#[derive(Debug)]
170-
pub struct BreakOutsideOfLoop {
171-
pub expr: InFile<AstPtr<ast::Expr>>,
172-
pub is_break: bool,
173-
pub bad_value_break: bool,
174-
}
175-
176181
#[derive(Debug)]
177182
pub struct MissingUnsafe {
178183
pub expr: InFile<AstPtr<ast::Expr>>,

crates/hir/src/lib.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,13 @@ use crate::db::{DefDatabase, HirDatabase};
8585
pub use crate::{
8686
attrs::{HasAttrs, Namespace},
8787
diagnostics::{
88-
AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl,
89-
IncorrectCase, InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount,
90-
MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem,
91-
PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
92-
UnresolvedExternCrate, UnresolvedField, UnresolvedImport, UnresolvedMacroCall,
93-
UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro, UnusedMut,
88+
AnyDiagnostic, ExpectedFunction, InactiveCode, IncoherentImpl, IncorrectCase,
89+
InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
90+
MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem, PrivateField,
91+
ReplaceFilterMapNextWithFindMap, TypeMismatch, UndeclaredLabel, UnimplementedBuiltinMacro,
92+
UnreachableLabel, UnresolvedExternCrate, UnresolvedField, UnresolvedImport,
93+
UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro,
94+
UnusedMut,
9495
},
9596
has_source::HasSource,
9697
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
@@ -1393,6 +1394,12 @@ impl DefWithBody {
13931394
}
13941395
.into(),
13951396
),
1397+
BodyDiagnostic::UnreachableLabel { node, name } => {
1398+
acc.push(UnreachableLabel { node: node.clone(), name: name.clone() }.into())
1399+
}
1400+
BodyDiagnostic::UndeclaredLabel { node, name } => {
1401+
acc.push(UndeclaredLabel { node: node.clone(), name: name.clone() }.into())
1402+
}
13961403
}
13971404
}
13981405

@@ -1405,14 +1412,6 @@ impl DefWithBody {
14051412
let field = source_map.field_syntax(expr);
14061413
acc.push(NoSuchField { field }.into())
14071414
}
1408-
&hir_ty::InferenceDiagnostic::BreakOutsideOfLoop {
1409-
expr,
1410-
is_break,
1411-
bad_value_break,
1412-
} => {
1413-
let expr = expr_syntax(expr);
1414-
acc.push(BreakOutsideOfLoop { expr, is_break, bad_value_break }.into())
1415-
}
14161415
&hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
14171416
acc.push(
14181417
MismatchedArgCount { call_expr: expr_syntax(call_expr), expected, found }

0 commit comments

Comments
 (0)