CodeBlanks Logo Icon CodeBlanks

HIR

Learn what High-level IR (HIR) is and what it does.

HIR

rustc passes code through several intermediate representations: text → tokens → AST (macro expansion, name resolution) → HIR → THIR → MIR → LLVM IR → machine code. HIR (High-level IR) is the AST with its "sugar" removed: for, while let, ? and async are lowered to more basic constructs. Type checking and trait resolution happen on HIR.

for x in v { .. }
// roughly, in HIR:
match IntoIterator::into_iter(v) {
    mut it => loop {
        match Iterator::next(&mut it) {
            Some(x) => { .. }
            None => break,
        }
    },
}

Lowering the ? operator

? also becomes a match in HIR; the From conversion is added at this step:

let n = s.parse::<i32>()?;
// roughly:
let n = match s.parse::<i32>() {
    Ok(v) => v,
    Err(e) => return Err(From::from(e)),
};

That's why sugared and lowered code produce the same machine code; syntactic conveniences have no runtime cost.

Practice Hand-lowered for

Sum the vector vec![1, 2, 3] without for, as in HIR, using IntoIterator::into_iter, loop and Iterator::next, and print the result.

Starter code

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
fn main() {
    let v = vec![1, 2, 3];
    let mut toplam = 0;
    let mut it = IntoIterator::into_iter(v);
    loop {
        match Iterator::next(&mut it) {
            Some(x) => toplam += x,
            None => break,
        }
    }
    println!("{}", toplam);
}

Expected output

6

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What is the easiest way to see a macro's expanded form?

  • cargo expand (or rustc -Zunpretty=expanded) Correct answer
  • cargo build --verbose
  • rustfmt
  • cargo doc

Explanation: Macro expansion happens at the AST stage; by the time HIR is reached, macros no longer exist.

2 Lowered loop

Question
let mut it = IntoIterator::into_iter(v);
loop {
    match Iterator::____(&mut it) {
        Some(x) => toplam += x,
        None => break,
    }
}
Answer
let mut it = IntoIterator::into_iter(v);
loop {
    match Iterator::next(&mut it) {
        Some(x) => toplam += x,
        None => break,
    }
}

Explanation: A for loop calls Iterator::next each round.

3 Stage and role

Term Meaning
AST Macro expansion
HIR Type checking
MIR Borrow checking
LLVM IR Optimization and codegen

All lessons in Expert