Skip to content

Commit

Permalink
small fixes
Browse files Browse the repository at this point in the history
- fixes #31
- renamed hir::Assign.source -> hir::Assign.dest
  because that makes more sense
- fixed some errors in the fuzzer
- few other small improvements

honestly i only intended to push the #31 fix
  • Loading branch information
NotAFlyingGoose committed Jun 19, 2024
1 parent a6ceda8 commit b62dde5
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 74 deletions.
3 changes: 3 additions & 0 deletions crates/capy_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ pub fn define_token_enum(input: TokenStream) -> TokenStream {
};

quote! {
/// Represents a token in a Capy program.
///
/// This enum might appear in different places under different names
#derive
pub enum #enum_name {
#entries
Expand Down
84 changes: 32 additions & 52 deletions crates/codegen/src/compiler/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,21 +152,21 @@ impl FunctionCompiler<'_> {
}
}

// let hir_body = self.bodies_map[&self.module_name].function_body(self.module_name.name);
if return_ty.is_aggregate() {
let return_addr = self.builder.use_var(dest_param.unwrap());
let return_mem = MemoryLoc {
addr: return_addr,
offset: 0,
};

match self.compile_and_cast(function_body, return_ty) {
Some(body) => {
if return_ty.is_aggregate() {
let dest = self.builder.use_var(dest_param.unwrap());
self.build_memcpy_ty(body, dest, return_ty, true);
self.compile_and_cast_into_memory(function_body, return_ty, return_mem);

self.builder.ins().return_(&[dest])
} else {
self.builder.ins().return_(&[body])
}
}
None => self.builder.ins().return_(&[]),
};
self.builder.ins().return_(&[return_addr]);
} else if let Some(val) = self.compile_and_cast(function_body, return_ty) {
self.builder.ins().return_(&[val]);
} else {
self.builder.ins().return_(&[]);
}

if debug_print {
println!("{}", self.builder.func);
Expand Down Expand Up @@ -479,6 +479,7 @@ impl FunctionCompiler<'_> {
)
}

#[allow(unused)]
fn build_memcpy_ty(&mut self, src: Value, dest: Value, ty: Intern<Ty>, non_overlapping: bool) {
self.builder.emit_small_memory_copy(
self.module.target_config(),
Expand All @@ -492,19 +493,6 @@ impl FunctionCompiler<'_> {
)
}

fn build_memcpy_size(&mut self, src: Value, dest: Value, size: u64, non_overlapping: bool) {
self.builder.emit_small_memory_copy(
self.module.target_config(),
dest,
src,
size,
1,
1,
non_overlapping,
MemFlags::trusted(),
)
}

fn get_func_id(&mut self, fqn: hir::Fqn) -> FuncId {
super::get_func_id(
self.module,
Expand Down Expand Up @@ -600,7 +588,9 @@ impl FunctionCompiler<'_> {
let memory = MemoryLoc::from_stack(stack_slot, 0, &mut self.builder, self.ptr_ty);

if let Some(value) = value {
self.store_expr_in_memory(value, ty, memory);
// the type of the value might not be the same as the type annotation of the
// declaration
self.compile_and_cast_into_memory(value, ty, memory);
} else {
self.store_default_in_memory(ty, memory);
}
Expand All @@ -611,35 +601,17 @@ impl FunctionCompiler<'_> {
hir::Stmt::Assign(assign) => {
let assign_body = &self.world_bodies[self.file_name][assign];

let value_ty = &self.tys[self.file_name][assign_body.value];

let source =
if let Some(val) = self.compile_expr_with_args(assign_body.source, true) {
val
} else {
return;
};

let source_ty = &self.tys[self.file_name][assign_body.source];

let value = if let Some(val) = self.compile_and_cast(assign_body.value, *source_ty)
{
val
} else {
let Some(dest) = self.compile_expr_with_args(assign_body.dest, true) else {
return;
};
let dest = MemoryLoc {
addr: dest,
offset: 0,
};

if value_ty.is_aggregate() {
let size = value_ty.size();
let size = self.builder.ins().iconst(self.ptr_ty, size as i64);
let dest_ty = &self.tys[self.file_name][assign_body.dest];

self.builder
.call_memcpy(self.module.target_config(), source, value, size)
} else {
self.builder
.ins()
.store(MemFlags::trusted(), value, source, 0);
}
self.compile_and_cast_into_memory(assign_body.value, *dest_ty, dest);
}
hir::Stmt::Break {
label: Some(label),
Expand Down Expand Up @@ -2050,6 +2022,14 @@ impl FunctionCompiler<'_> {
cast_to: Intern<Ty>,
memory: MemoryLoc,
) -> Option<Value> {
if self.tys[self.file_name][expr].is_functionally_equivalent_to(&cast_to, true) {
self.store_expr_in_memory(expr, cast_to, memory);

return Some(memory.into_value(&mut self.builder));
}

// todo: there should be a function similar to `store_expr_in_memory` that also casts along
// the way. this would remove an unnecessary memcpy
let value = self.compile_expr(expr);

self.cast_into_memory(value, self.tys[self.file_name][expr], cast_to, memory)
Expand Down
10 changes: 5 additions & 5 deletions crates/hir/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ pub struct LocalDef {

#[derive(Clone, Debug)]
pub struct Assign {
pub source: Idx<Expr>,
pub dest: Idx<Expr>,
pub value: Idx<Expr>,
pub range: TextRange,
pub ast: ast::Assign,
Expand Down Expand Up @@ -786,11 +786,11 @@ impl<'a> Ctx<'a> {
}

fn lower_assignment(&mut self, assign: ast::Assign) -> Stmt {
let source = self.lower_expr(assign.source(self.tree).unwrap().value(self.tree));
let dest = self.lower_expr(assign.source(self.tree).unwrap().value(self.tree));
let value = self.lower_expr(assign.value(self.tree));

let id = self.bodies.assigns.alloc(Assign {
source,
dest,
value,
range: assign.range(self.tree),
ast: assign,
Expand Down Expand Up @@ -1860,7 +1860,7 @@ impl Iterator for Descendants<'_> {
}
Stmt::Assign(assign) => {
let assign = &self.bodies[assign];
self.todo.push(Descendant::Expr(assign.source));
self.todo.push(Descendant::Expr(assign.dest));
self.todo.push(Descendant::Expr(assign.value));
}
Stmt::Expr(expr) => self.todo.push(Descendant::Expr(expr)),
Expand Down Expand Up @@ -2562,7 +2562,7 @@ impl Bodies {
Stmt::Assign(local_set_id) => {
write_expr(
s,
bodies[*local_set_id].source,
bodies[*local_set_id].dest,
show_idx,
bodies,
mod_dir,
Expand Down
12 changes: 6 additions & 6 deletions crates/hir_ty/src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl GlobalInferenceCtx<'_> {
hir::Stmt::Assign(assign) => {
let assign_body = &self.bodies[assign];

self.reinfer_expr(assign_body.source);
self.reinfer_expr(assign_body.dest);
self.reinfer_expr(assign_body.value);
}
hir::Stmt::Expr(expr) => {
Expand Down Expand Up @@ -1789,29 +1789,29 @@ impl GlobalInferenceCtx<'_> {
Stmt::Assign(assign) => {
let assign_body = &self.bodies[assign];

let source_ty = self.tys[self.file][assign_body.source];
let source_ty = self.tys[self.file][assign_body.dest];
let value_ty = self.tys[self.file][assign_body.value];

let help = self
.get_mutability(assign_body.source, true, false)
.get_mutability(assign_body.dest, true, false)
.into_diagnostic();

if help.is_some() {
self.diagnostics.push(TyDiagnostic {
kind: TyDiagnosticKind::CannotMutate,
file: self.file,
// making expr the source isn't technically correct, but it works
expr: Some(assign_body.source),
expr: Some(assign_body.dest),
range: assign_body.range,
help,
})
} else if source_ty.is_weak_replaceable_by(&value_ty) {
self.replace_weak_tys(assign_body.source, source_ty);
self.replace_weak_tys(assign_body.dest, source_ty);
} else if self.expect_match(value_ty, source_ty, assign_body.value) {
self.replace_weak_tys(assign_body.value, source_ty);
}

self.find_usages(&[assign_body.source, assign_body.value], stmt);
self.find_usages(&[assign_body.dest, assign_body.value], stmt);
}
Stmt::Break { label: None, .. } => {}
Stmt::Break {
Expand Down
32 changes: 25 additions & 7 deletions crates/hir_ty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,14 @@ impl<'a, F: EvalComptimeFn> InferenceCtx<'a, F> {
}),
);

if self.to_infer.is_empty() {
return InferenceResult {
tys: self.tys,
diagnostics: self.diagnostics,
any_were_unsafe_to_compile: false,
};
}

const DEBUG: bool = false;

loop {
Expand Down Expand Up @@ -857,10 +865,10 @@ mod tests {
Option<(TyDiagnosticHelpKind, std::ops::Range<u32>)>,
); N],
) {
check_with_entry(input, expect, expected_diagnostics, None)
check_impl(input, expect, expected_diagnostics, None)
}

fn check_with_entry<const N: usize>(
fn check_impl<const N: usize>(
input: &str,
expect: Expect,
expected_diagnostics: impl Fn(
Expand Down Expand Up @@ -1052,6 +1060,16 @@ mod tests {
}
}

#[test]
fn empty_file() {
check(
"",
expect![[r#"
"#]],
|_| [],
)
}

#[test]
fn unit_function() {
check(
Expand Down Expand Up @@ -7330,7 +7348,7 @@ mod tests {

#[test]
fn entry_point_void() {
check_with_entry(
check_impl(
r#"
start :: () {};
"#,
Expand All @@ -7346,7 +7364,7 @@ mod tests {

#[test]
fn entry_point_int() {
check_with_entry(
check_impl(
r#"
entry :: () -> i16 { 0 };
"#,
Expand All @@ -7363,7 +7381,7 @@ mod tests {

#[test]
fn entry_point_uint() {
check_with_entry(
check_impl(
r#"
main :: () -> usize { 0 };
"#,
Expand All @@ -7380,7 +7398,7 @@ mod tests {

#[test]
fn entry_point_non_function() {
check_with_entry(
check_impl(
r#"
main :: 5;
"#,
Expand All @@ -7395,7 +7413,7 @@ mod tests {

#[test]
fn entry_point_bad_params_and_return() {
check_with_entry(
check_impl(
r#"
foo :: (x: i32, y: bool) -> str {
"Hello!"
Expand Down
3 changes: 3 additions & 0 deletions crates/syntax/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ capy_macros::define_token_enum! {
TokenKind, stripped, "../../tokenizer.txt"
}

/// Represents a group of tokens or other nodes.
///
/// For example, StmtExpr might contain an IntLiteral which contains an Int token
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum NodeKind {
Root,
Expand Down
12 changes: 8 additions & 4 deletions fuzz/fuzz_targets/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#![no_main]

extern crate ast;
extern crate codegen;
extern crate hir_ty;
extern crate libfuzzer_sys;
extern crate rustc_hash;
extern crate target_lexicon;

use std::path::Path;

Expand All @@ -27,11 +31,11 @@ fuzz_target!(|s: &str| {
let root = ast::Root::cast(tree.root(), tree).unwrap();
let _diagnostics = ast::validation::validate(root, tree);

let (index, _indexing_diagnostics) = hir::index(root, &tree, &mut interner);
let (index, _indexing_diagnostics) = hir::index(root, tree, &mut interner);

let (bodies, _lowering_diagnostics) = hir::lower(
root,
&tree,
tree,
Path::new("main.capy"),
&index,
&mut uid_gen,
Expand All @@ -48,9 +52,9 @@ fuzz_target!(|s: &str| {
let mut comptime_results = FxHashMap::default();

let InferenceResult {
tys,
tys: _tys,
diagnostics: _type_diagnostics,
any_were_unsafe_to_compile,
any_were_unsafe_to_compile: _any_unsafe,
} = InferenceCtx::new(&world_index, &world_bodies, &interner, |comptime, tys| {
// todo: this might make the fuzzer a lot slower, would it be beneficial to make a separate
// fuzzer for codegen stuff?
Expand Down

0 comments on commit b62dde5

Please sign in to comment.