Skip to content

Commit f27220c

Browse files
committed
feat: test test test
1 parent 5c13a9a commit f27220c

22 files changed

Lines changed: 1244 additions & 118 deletions

libs/@local/graph/api/src/rest/hashql/compile.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ impl<'heap> Compilation<'heap> {
130130
HashQlDiagnosticCategory::Mir(MirDiagnosticCategory::Reify(category))
131131
})
132132
.with_diagnostics(advisories)?;
133+
scratch.reset();
133134

134135
// Lower the MIR
135136
let Success {

libs/@local/hashql/mir/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
macro_metavar_expr_concat,
1212
never_type,
1313
const_trait_impl,
14+
stmt_expr_attributes,
1415
1516
// Library Features
1617
allocator_api,

libs/@local/hashql/mir/src/reify/atom.rs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use core::alloc::Allocator;
22

3-
use hashql_core::{id::Id as _, r#type::kind::TypeKind, value::Primitive};
3+
use hashql_core::{id::Id as _, span::Spanned, r#type::kind::TypeKind, value::Primitive};
44
use hashql_hir::{
55
node::{
66
Node,
@@ -23,6 +23,7 @@ use crate::{
2323
operand::Operand,
2424
place::{FieldIndex, Place, Projection, ProjectionKind},
2525
},
26+
def::DefId,
2627
interpret::value::{Int, TryFromPrimitiveError},
2728
reify::{
2829
error::{field_index_too_large, local_variable_unmapped},
@@ -157,16 +158,42 @@ impl<'heap, A: Allocator, S: Allocator> Reifier<'_, '_, '_, '_, 'heap, A, S> {
157158
}
158159
}
159160

160-
pub(super) fn qualified_variable(&mut self, path: QualifiedPath<'heap>, requires_thunk: bool) {
161-
todo!()
161+
pub(super) fn operand_qualified_variable(
162+
&mut self,
163+
node: Node<'heap>,
164+
path: QualifiedPath<'heap>,
165+
) -> Option<DefId> {
166+
let synthetic = self.state.synthetics.find_or_insert(
167+
self.context,
168+
&mut self.state.diagnostics,
169+
Spanned {
170+
span: node.span,
171+
value: node.id,
172+
},
173+
path,
174+
)?;
175+
176+
// The value is called as a thunk, and therefore must be generated as such
177+
let thunk = synthetic.thunk(self.context.bodies, self.context.mir.heap);
178+
Some(thunk)
162179
}
163180

164181
pub(super) fn operand(&mut self, node: Node<'heap>) -> Operand<'heap> {
165182
match node.kind {
166-
NodeKind::Variable(Variable::Qualified(_)) => {
167-
self.state
168-
.diagnostics
169-
.push(external_modules_unsupported(node.span).generalize());
183+
NodeKind::Variable(Variable::Qualified(variable)) => {
184+
let diagnostics = self.state.diagnostics.critical();
185+
186+
if let Some(thunk) = self.operand_qualified_variable(node, variable.path) {
187+
return Operand::Constant(Constant::FnPtr(thunk));
188+
}
189+
190+
// The variable used is not a qualified variable, and therefore we must issue a
191+
// diagnostic.
192+
if diagnostics == self.state.diagnostics.critical() {
193+
self.state
194+
.diagnostics
195+
.push(external_modules_unsupported(node.span).generalize());
196+
}
170197

171198
// Return a bogus value so that lowering can continue
172199
// In the future this would be a simple FnPtr

libs/@local/hashql/mir/src/reify/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ use self::{
4444
error::{
4545
expected_anf_thunk, expected_anf_variable, external_modules_unsupported, local_not_thunk,
4646
},
47+
synthetic::Synthetics,
4748
types::unwrap_closure_type,
4849
};
4950
use crate::{
@@ -107,6 +108,9 @@ struct CrossCompileState<'heap, S: Allocator> {
107108
/// Mapping of variable IDs to their thunk definitions.
108109
thunks: Thunks<S>,
109110

111+
/// Synthetic bodies that have been generated during reification.
112+
synthetics: Synthetics<S>,
113+
110114
/// Collection of diagnostics encountered during reification.
111115
diagnostics: ReifyDiagnosticIssues,
112116

@@ -507,6 +511,7 @@ pub fn from_hir<'heap, A: Allocator, S: Allocator + Clone>(
507511
};
508512
let mut state = CrossCompileState {
509513
thunks,
514+
synthetics: Synthetics::new_in(context.scratch.clone()),
510515
ctor: FastHashMap::default(),
511516
diagnostics: ReifyDiagnosticIssues::new(),
512517
var_pool: MixedBitSetPool::with_recycler_in(

libs/@local/hashql/mir/src/reify/rvalue.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use core::alloc::Allocator;
22

33
use hashql_core::{
44
id::{Id as _, IdVec},
5+
span::Spanned,
56
symbol::sym,
67
r#type::{TypeBuilder, Typed, builder},
78
value::Primitive,
@@ -17,6 +18,7 @@ use hashql_hir::node::{
1718
BinaryOperation, InputOperation, Operation, TypeConstructor, TypeOperation, UnaryOperation,
1819
},
1920
thunk::Thunk,
21+
variable::Variable,
2022
};
2123

2224
use super::{
@@ -200,6 +202,10 @@ impl<'mir, 'heap, A: Allocator, S: Allocator> Reifier<'_, 'mir, '_, '_, 'heap, A
200202
function: Node<'heap>,
201203
call_arguments: &[CallArgument<'heap>],
202204
) -> RValue<'heap> {
205+
if let Some(value) = self.rvalue_call_thin_specialize(function, call_arguments) {
206+
return value;
207+
}
208+
203209
let mut arguments = IdVec::with_capacity_in(call_arguments.len(), self.context.mir.heap);
204210

205211
for CallArgument { span: _, value } in call_arguments {
@@ -214,6 +220,57 @@ impl<'mir, 'heap, A: Allocator, S: Allocator> Reifier<'_, 'mir, '_, '_, 'heap, A
214220
})
215221
}
216222

223+
/// Attempts to beta-reduce a thin call to a qualified intrinsic into a closure aggregate.
224+
///
225+
/// The thunking phase wraps every qualified variable in `Call(Thin, Qualified(...), [])`.
226+
/// When the target is a known intrinsic, this produces the closure aggregate directly
227+
/// instead of going through a thunk body that later passes would eliminate.
228+
///
229+
/// Returns [`None`] if the call has arguments, the target is not a qualified variable,
230+
/// or the path is not a known intrinsic.
231+
fn rvalue_call_thin_specialize(
232+
&mut self,
233+
function: Node<'heap>,
234+
call_arguments: &[CallArgument<'heap>],
235+
) -> Option<RValue<'heap>> {
236+
if !call_arguments.is_empty() {
237+
return None;
238+
}
239+
240+
let NodeKind::Variable(Variable::Qualified(variable)) = function.kind else {
241+
return None;
242+
};
243+
244+
let diagnostics = self.state.diagnostics.critical();
245+
246+
let Some(synthetic) = self.state.synthetics.find_or_insert(
247+
self.context,
248+
&mut self.state.diagnostics,
249+
Spanned {
250+
span: function.span,
251+
value: function.id,
252+
},
253+
variable.path,
254+
) else {
255+
// A diagnostic was already emitted (e.g. non-first-classable intrinsic).
256+
// Return a bogus value to prevent the fallback from emitting a duplicate.
257+
if diagnostics != self.state.diagnostics.critical() {
258+
return Some(RValue::Load(Operand::Constant(Constant::Unit)));
259+
}
260+
261+
return None;
262+
};
263+
264+
let mut operands = IdVec::with_capacity_in(2, self.context.mir.heap);
265+
operands.push(Operand::Constant(Constant::FnPtr(synthetic.body)));
266+
operands.push(Operand::Constant(Constant::Unit));
267+
268+
Some(RValue::Aggregate(Aggregate {
269+
kind: AggregateKind::Closure,
270+
operands,
271+
}))
272+
}
273+
217274
fn rvalue_call_fat(
218275
&mut self,
219276
function: Node<'heap>,

0 commit comments

Comments
 (0)