Coverage Report

Created: 2024-07-06 06:44

/src/starlark-rust/starlark/src/eval/bc/compiler/assign.rs
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2019 The Starlark in Rust Authors.
3
 * Copyright (c) Facebook, Inc. and its affiliates.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     https://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
//! Compile assignment lhs.
19
20
use starlark_syntax::slice_vec_ext::SliceExt;
21
22
use crate::collections::symbol::symbol::Symbol;
23
use crate::eval::bc::compiler::expr::write_n_exprs;
24
use crate::eval::bc::instr_impl::InstrSetArrayIndex;
25
use crate::eval::bc::instr_impl::InstrSetObjectField;
26
use crate::eval::bc::instr_impl::InstrStoreModuleAndExport;
27
use crate::eval::bc::instr_impl::InstrUnpack;
28
use crate::eval::bc::stack_ptr::BcSlotIn;
29
use crate::eval::bc::stack_ptr::BcSlotOut;
30
use crate::eval::bc::writer::BcWriter;
31
use crate::eval::compiler::span::IrSpanned;
32
use crate::eval::compiler::stmt::AssignCompiledValue;
33
34
impl AssignCompiledValue {
35
    /// After evaluation of `(x, y[z]) = ...`, variables `x`, `y` and `z` as definitely assigned.
36
16
    pub(crate) fn mark_definitely_assigned_after(&self, bc: &mut BcWriter) {
37
16
        match self {
38
0
            AssignCompiledValue::Dot(object, field) => {
39
0
                object.mark_definitely_assigned_after(bc);
40
0
                let _ = field;
41
0
            }
42
8
            AssignCompiledValue::Module(..) => {}
43
0
            AssignCompiledValue::Index(array, index) => {
44
0
                array.mark_definitely_assigned_after(bc);
45
0
                index.mark_definitely_assigned_after(bc);
46
0
            }
47
0
            AssignCompiledValue::LocalCaptured(_slot) => {}
48
8
            AssignCompiledValue::Local(slot) => {
49
8
                bc.mark_definitely_assigned(*slot);
50
8
            }
51
0
            AssignCompiledValue::Tuple(xs) => {
52
0
                for x in xs {
53
0
                    x.mark_definitely_assigned_after(bc);
54
0
                }
55
            }
56
        }
57
16
    }
58
}
59
60
impl IrSpanned<AssignCompiledValue> {
61
8
    pub(crate) fn write_bc(&self, value: BcSlotIn, bc: &mut BcWriter) {
62
8
        let span = self.span;
63
8
        match self.node {
64
0
            AssignCompiledValue::Dot(ref object, ref field) => {
65
0
                object.write_bc_cb(bc, |object, bc| {
66
0
                    let symbol = Symbol::new(field.as_str());
67
0
                    bc.write_instr::<InstrSetObjectField>(span, (value, object, symbol));
68
0
                });
69
0
            }
70
0
            AssignCompiledValue::Index(ref array, ref index) => {
71
0
                write_n_exprs([array, index], bc, |[array, index], bc| {
72
0
                    bc.write_instr::<InstrSetArrayIndex>(span, (value, array, index));
73
0
                });
74
0
            }
75
0
            AssignCompiledValue::Tuple(ref xs) => {
76
0
                // All assignments are to local variables, e. g.
77
0
                // ```
78
0
                // (x, y, z) = ...
79
0
                // ```
80
0
                // so we can avoid using intermediate register.
81
0
                let all_local = xs
82
0
                    .try_map(|x| {
83
0
                        x.as_local_non_captured()
84
0
                            .map(|l| l.to_bc_slot().to_out())
85
0
                            .ok_or(())
86
0
                    })
87
0
                    .ok();
88
0
                if let Some(all_local) = all_local {
89
0
                    let args = bc.heap.alloc_any_slice(&all_local);
90
0
                    bc.write_instr::<InstrUnpack>(span, (value, args));
91
0
                } else {
92
0
                    bc.alloc_slots(xs.len() as u32, |slots, bc| {
93
0
                        let args: Vec<BcSlotOut> = slots.iter().map(|s| s.to_out()).collect();
94
0
                        let args = bc.heap.alloc_any_slice(&args);
95
0
                        bc.write_instr::<InstrUnpack>(span, (value, args));
96
97
0
                        for (x, slot) in xs.iter().zip(slots.iter()) {
98
0
                            x.write_bc(slot.to_in(), bc);
99
0
                        }
100
0
                    });
101
0
                }
102
            }
103
0
            AssignCompiledValue::Local(slot) => {
104
0
                bc.write_mov(span, value, slot.to_bc_slot().to_out());
105
0
            }
106
0
            AssignCompiledValue::LocalCaptured(slot) => {
107
0
                bc.write_store_local_captured(span, value, slot);
108
0
            }
109
8
            AssignCompiledValue::Module(slot, ref name) => {
110
8
                bc.write_instr::<InstrStoreModuleAndExport>(span, (value, slot, name.clone()));
111
8
            }
112
        }
113
8
    }
114
}