Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Borrow checking

Borrow checking lives under check/borrow_check/. Its top-level judgment is borrow_check, which checks that the loans issued while executing a basic block are respected.

borrow_check

borrow_check [src]
borrow_check(env: TypeckEnv, assumptions: Wcs, state: FlowState, block: Block,) => ()

At the top level, borrow checking works over a TypeckEnv, a set of assumptions, a FlowState, and a Block. It delegates to borrow_check_block, which walks the block and updates the flow state statement by statement:

borrow_check_block [src]
borrow_check_block(env: TypeckEnv, assumptions: Wcs, state: FlowState, block: Block, places_live_on_exit: LivePlaces,) => FlowState

Statements

borrow_check_statement handles each kind of statement. Here are some representative rules:

let bindings

borrow_check_statement::let [src]
(prove_ty_is_wf(env, assumptions, state, ty) => state)
(for_all(init in init.into_iter()) with (state) // FIXME: should make syntax for this
    (let Init { expr } = init)
    (borrow_check_expr_has_ty(env,
        assumptions,
        state,
        expr,
        ty,
        LiveBefore::live_before(&Assignment(id), env, &state, &places_live_on_exit),
    ) => state))

(let state = state.with_local_in_scope(&env.env, label, id, ty)?)
------------------------------------------------------------ ("let")
(borrow_check_statement(env, assumptions, state, Stmt::Let { label, id, ty, init }, places_live_on_exit) => (env, state))

if expressions

borrow_check_statement::if [src]
(borrow_check_expr_has_ty(
    env,
    assumptions,
    state,
    condition,
    Ty::bool(),
    Either(then_block, else_block).live_before(env, &state, places_live_on_exit),
) => state)

(borrow_check_block(env, assumptions, state, then_block, places_live_on_exit) => then_state)
(borrow_check_block(env, assumptions, state, else_block, places_live_on_exit) => else_state)

(let state: FlowState = Union((then_state, else_state)).upcast())
------------------------------------------------------------ ("if")
(borrow_check_statement(env, assumptions, state, Stmt::If { condition, then_block, else_block }, places_live_on_exit) => (env, state))

loop

borrow_check_statement::loop [src]
(let continue_live = Stmt::loop_(label, body).live_before(&env, &state, places_live_on_exit))
(let state = state.push_continue_scope(&env.env, label, places_live_on_exit, continue_live)?)
(borrow_check_loop(env, assumptions, state, body, places_live_on_exit) => state)
(let state = state.pop_scope(label))
------------------------------------------------------------ ("loop")
(borrow_check_statement(env, assumptions, state, Stmt::Loop { label, body }, places_live_on_exit) => (env, state))

break and continue

borrow_check_statement::break [src]
(if state.scope_has_label(label))!
(let locals_to_drop = state.locals_dropped_to_label(label))
(drop_places(env, assumptions, state, locals_to_drop, places_live_on_exit) => state)
(let state = state.with_break(label))
(let state = state.diverges())
------------------------------------------------------------ ("break")
(borrow_check_statement(env, assumptions, state, Stmt::Break { label }, places_live_on_exit) => (env, state))
borrow_check_statement::continue [src]
(if state.scope_has_label(label))!
(if let Some(places_live_on_continue) = state.live_after_continue(label))
(let locals_to_drop = state.locals_dropped_to_label(label))
(drop_places(env, assumptions, state, locals_to_drop, places_live_on_continue) => state)
(let state = state.with_continue(label))
(let state = state.diverges())
------------------------------------------------------------ ("continue")
(borrow_check_statement(env, assumptions, state, Stmt::Continue { label }, places_live_on_exit) => (env, state))

return

borrow_check_statement::return [src]
(borrow_check_expr(env, assumptions, state, expr, LivePlaces::default()) => (expr_ty, state))
(if let Some(output_ty) = &env.output_ty)
(prove_assignable(env, assumptions, state, expr_ty, output_ty) => state)
(let state = state.diverges())
------------------------------------------------------------ ("return")
(borrow_check_statement(env, assumptions, state, Stmt::Return { expr }, _places_live_on_exit) => (env, state))

Expressions

Borrow checking of value expressions is handled by borrow_check_expr:

borrow_check_expr [src]
borrow_check_expr(env: TypeckEnv, assumptions: Wcs, state: FlowState, expr: Expr, places_live_on_exit: LivePlaces,) => (Ty, FlowState)

Outlives

Borrow checking also accumulates pending outlives constraints. The outlives.rs code verifies these constraints:

verify_universal_outlives [src]
verify_universal_outlives(env: TypeckEnv, assumptions: Wcs, outlives: Set<PendingOutlives>,) => ()

Existential variables succeed trivially; universal variables must be justified by the assumptions:

only_assumed_outlives [src]
only_assumed_outlives(env: TypeckEnv, assumptions: Wcs, outlives: Set<PendingOutlives>, v: Variable,) => ()