From c466b8eb2a2d7787290b9669bbbb877742e39a7a Mon Sep 17 00:00:00 2001 From: sofia Date: Fri, 25 Jul 2025 22:21:11 +0300 Subject: [PATCH] Fix everything except for casts --- examples/arithmetic.reid | 4 +- foo.reid | 469 ++++++++++++++++++++++++ reid/lib/std.reid | 2 +- reid/src/codegen/intrinsics.rs | 12 + reid/src/mir/typecheck/typecheck.rs | 26 +- reid/src/mir/typecheck/typeinference.rs | 18 +- reid/src/mir/typecheck/typerefs.rs | 21 ++ 7 files changed, 533 insertions(+), 19 deletions(-) create mode 100644 foo.reid diff --git a/examples/arithmetic.reid b/examples/arithmetic.reid index fea0607..578a4ca 100644 --- a/examples/arithmetic.reid +++ b/examples/arithmetic.reid @@ -5,5 +5,7 @@ fn main() -> u32 { let value = 0b110; let other = 0o17; - return value * other + 7 * -value; + let b = [5.0, 0.0 -5.0]; + + return value -1; } diff --git a/foo.reid b/foo.reid new file mode 100644 index 0000000..5d6e980 --- /dev/null +++ b/foo.reid @@ -0,0 +1,469 @@ +import std::concat_strings; +import std::print; +import std::from_str; +import std::free_string; +import std::add_num_to_str; + +/////////////////// +/// SDL externs /// +/////////////////// + +// Helper struct for stack allocated const sized strings, because structs are +// easier to create uninit than arrays. +struct SDL_Window {} +struct SDL_Renderer {} +struct SDL_Texture {} +struct SDL_Event { type: u32, reserved: [u8; 124] } +struct SDL_FRect { x: f32, y: f32, w: f32, h: f32 } +struct SDL_Rect { x: i32, y: i32, w: i32, h: i32 } +extern fn SDL_malloc(size: u64) -> *u8; +extern fn SDL_Init(flags: u32) -> bool; +extern fn SDL_Quit(); +extern fn SDL_CreateWindowAndRenderer(title: *char, width: i32, height: i32, flags: i32, + window_out: &mut *SDL_Window, renderer_out: &mut *SDL_Renderer) -> bool; +extern fn SDL_Delay(ms: u32); +extern fn SDL_SetRenderDrawColor(renderer: *SDL_Renderer, r: u8, g: u8, b: u8, a: u8); +extern fn SDL_RenderClear(renderer: *SDL_Renderer); +extern fn SDL_RenderPresent(renderer: *SDL_Renderer); +extern fn SDL_HasEvent(event_type: u32) -> bool; +extern fn SDL_PollEvent(event: &mut SDL_Event) -> bool; +extern fn SDL_PumpEvents(); +extern fn SDL_FlushEvents(min_type: u32, max_type: u32); +extern fn SDL_GetTicks() -> u64; +extern fn SDL_SetWindowTitle(window: *SDL_Window, title: *char) -> bool; +extern fn SDL_CreateTexture(renderer: *SDL_Renderer, + pixel_format: u32, texture_access: u32, width: u32, height: u32) -> *SDL_Texture; +extern fn SDL_RenderTexture(renderer: *SDL_Renderer, + texture: *SDL_Texture, srcfrect: &SDL_FRect, dstfrect: &SDL_FRect) -> bool; +extern fn SDL_UpdateTexture(texture: *SDL_Texture, rect: &SDL_Rect, pixels: *u8, pitch: u32) -> bool; +extern fn SDL_GetError() -> *char; +extern fn SDL_GetWindowSize(window: *SDL_Window, w: &mut i32, h: &mut i32) -> bool; +extern fn SDL_rand(max_exclusive: u32) -> u32; +extern fn SDL_SetTextureScaleMode(texture: *SDL_Texture, scale_mode: i32) -> bool; +extern fn SDL_sqrtf(value: f32) -> f32; +extern fn SDL_randf() -> f32; +extern fn SDL_powf(value: f32, power: f32) -> f32; + +// SDL error reporting helper +fn print_sdl_error(context: *char) { + let mut message = from_str(context); + + let delim = from_str(": "); + concat_strings(&mut message, delim); + free_string(&delim); + + let error_msg = from_str(SDL_GetError()); + concat_strings(&mut message, error_msg); + free_string(&error_msg); + + print(message); + + free_string(&message); +} + +///////////////////////////////// +/// Main setup and frame loop /// +///////////////////////////////// + +struct GameState { + renderer: *SDL_Renderer, + window: *SDL_Window, + render_texture: *SDL_Texture, + frame_counter: u32, + last_fps_reset: u64, + pixels: *u8, + pixels_w: u32, + pixels_h: u32, + pixels_bpp: u32, +} + +fn main() -> i32 { + let SDL_INIT_VIDEO = 32; + let SDL_WINDOW_RESIZABLE = 32; + let SDL_PIXELFORMAT_RGBA8888 = 373694468; + let SDL_PIXELFORMAT_ABGR8888 = 376840196; + let SDL_PIXELFORMAT_RGB24 = 386930691; + let SDL_PIXELFORMAT_BGR24 = 390076419; + let SDL_PIXELFORMAT_RGB96_FLOAT = 454057996; + let SDL_PIXELFORMAT_BGR96_FLOAT = 457203724; + let SDL_TEXTUREACCESS_STREAMING = 1; + let SDL_SCALEMODE_NEAREST = 0; + let SDL_SCALEMODE_LINEAR = 1; + let SDL_SCALEMODE_PIXELART = 2; + + let init_success = SDL_Init(SDL_INIT_VIDEO); + if init_success == false { + print_sdl_error("SDL init failed"); + return 1; + } + + let mut window = SDL_malloc(1) as *SDL_Window; + let mut renderer = SDL_malloc(1) as *SDL_Renderer; + let gfx_init_success = SDL_CreateWindowAndRenderer( + "graphical reid program", 640, 480, SDL_WINDOW_RESIZABLE, + &mut window, &mut renderer + ); + if gfx_init_success == false { + print_sdl_error("SDL renderer and window creation failed"); + return 1; + } + + let width = 320; + let height = 240; + let bpp = 4; + let render_texture = SDL_CreateTexture(renderer, + SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, width, height); + SDL_SetTextureScaleMode(render_texture, SDL_SCALEMODE_NEAREST); + + let pixels_len = (width * height * bpp) as u64; + let pixels = SDL_malloc(pixels_len); + let mut game_state = GameState { + renderer: renderer, + window: window, + render_texture: render_texture, + frame_counter: 0, + last_fps_reset: 0, + pixels: pixels, + pixels_w: width, + pixels_h: height, + pixels_bpp: bpp, + }; + + while frame_loop(&mut game_state) {} + + SDL_Quit(); + return 0; +} + +fn frame_loop(game_state: &mut GameState) -> bool { + let mut event = SDL_Event {}; + while (SDL_PollEvent(&mut event)) { + if event.type == 256 { // SDL_EVENT_QUIT + return false; + } + } + + let mut screen_width = 0; + let mut screen_height = 0; + SDL_GetWindowSize(*game_state.window, &mut screen_width, &mut screen_height); + + let renderer = *game_state.renderer; + SDL_SetRenderDrawColor(renderer, 0, 50, 90, 255); + SDL_RenderClear(renderer); + + let w = *game_state.pixels_w; + let h = *game_state.pixels_h; + let bpp = *game_state.pixels_bpp; + for y in 0..h { + for x in 0..w { + render_pixel(x, y, game_state); + } + } + + let texture_area = SDL_Rect { x: 0, y: 0, w: w as i32, h: h as i32 }; + if SDL_UpdateTexture(*game_state.render_texture, &texture_area, *game_state.pixels as *u8, bpp * w) == false { + print_sdl_error("UpdateTexture error"); + } + let src = SDL_FRect { x: 0.0, y: 0.0, w: w as f32, h: h as f32 }; + let aspect_ratio = src.w / src.h; + let scaled_width = screen_height as f32 * aspect_ratio; + let dst = SDL_FRect { x: (screen_width as f32 - scaled_width) / 2.0, y: 0.0, w: scaled_width, h: screen_height as f32 }; + if SDL_RenderTexture(renderer, *game_state.render_texture, &src, &dst) == false { + print_sdl_error("RenderTexture error"); + } + + SDL_RenderPresent(renderer); + SDL_Delay(1); + + *game_state.frame_counter = *game_state.frame_counter + 1; + let t = SDL_GetTicks(); + if (t - *game_state.last_fps_reset) >= 1000 { + let mut title = from_str("graphical reid program "); + add_num_to_str(&mut title, *game_state.frame_counter as u64); + let fps_unit = from_str(" fps"); + concat_strings(&mut title, fps_unit); + free_string(&fps_unit); + SDL_SetWindowTitle(*game_state.window, title.inner); + free_string(&title); + *game_state.frame_counter = 0; + *game_state.last_fps_reset = t; + } + + return true; +} + +fn render_pixel(x: u32, y: u32, game_state: &mut GameState) { + let w = *game_state.pixels_w; + let h = *game_state.pixels_h; + let bpp = *game_state.pixels_bpp; + + let samples = 1; + let old_sample_weight = 0.75; + let new_sample_weight = 0.25 / samples as f32; + let mut rgb = vec_mul_scalar(old_sample_weight, [ + srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 0]), + srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 1]), + srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 2]) + ]); + for sample in 0..samples { + rgb = vec_add(rgb, vec_mul_scalar(new_sample_weight, shade(x, y, *game_state.frame_counter, w, h))); + } + *game_state.pixels[(x + y * w) * bpp + 0] = linear_to_srgb(rgb[0]); + *game_state.pixels[(x + y * w) * bpp + 1] = linear_to_srgb(rgb[1]); + *game_state.pixels[(x + y * w) * bpp + 2] = linear_to_srgb(rgb[2]); + *game_state.pixels[(x + y * w) * bpp + 3] = 255; +} + + +///////////////// +/// Rendering /// +///////////////// + +struct Ray { + origin: [f32; 3], + direction: [f32; 3], +} + +struct Material { + // 0 = lambertian diffuse + // 1 = mirror + type: u32, + // Generally the "color" of the surface (linear factors of how much of each + // color channel this surface does not absorb), but the idea is that the + // type governs what this means. + linear_color: [f32; 3], +} + +struct Hit { + hit: bool, + front_face: bool, + distance: f32, + normal: [f32; 3], + position: [f32; 3], + material: Material, +} + +struct Sphere { + center: [f32; 3], + radius: f32, + material: Material, +} + +fn shade(x: u32, y: u32, t: u32, w: u32, h: u32) -> [f32; 3] { + let jitter_x = SDL_randf() - 0.5; + let jitter_y = SDL_randf() - 0.5; + + let pixel_scale = 1.0 / h as f32; + let pixel_pos = [ + (x as f32 + jitter_x) * pixel_scale, + 1.0 - (y as f32 + jitter_y) * pixel_scale, + 0.0 - 1.0 + ]; + let camera_pos = [w as f32 * 0.5f32 * pixel_scale, h as f32 * 0.5f32 * pixel_scale, 0.0f32]; + let dir = vec_normalize(vec_sub(pixel_pos, camera_pos)); + let ray = Ray { origin: camera_pos, direction: dir }; + let beige_lambertian = Material { type: 0, linear_color: [0.3, 0.2, 0.1] }; + let green_lambertian = Material { type: 0, linear_color: [0.1, 0.5, 0.06] }; + let greenish_mirror = Material { type: 1, linear_color: [0.9, 1.0, 0.95] }; + let spheres = [ + // Ground + Sphere { center: vec_sub(camera_pos, [0.0, 100001.0, 0.0]), radius: 100000.0, material: beige_lambertian }, + // Centered unit sphere + Sphere { center: vec_add(camera_pos, [0.0, 0.0, 0.0 - 5.0]), radius: 1.0, material: green_lambertian }, + // The unit sphere on the right + Sphere { center: vec_add(camera_pos, [2.0, 0.0, 0.0 - 6.0]), radius: 1.0, material: greenish_mirror } + ]; + return shade_world(ray, &spheres, 3); +} + +fn shade_world(ray: Ray, spheres: &[Sphere; 3], bounces_left: u8) -> [f32; 3] { + if bounces_left == 0 { + return [0.0, 0.0, 0.0]; + } + + let ray_distance = 100.0; + let mut closest_hit = Hit { hit: false, front_face: false, distance: ray_distance }; + for i in 0..3 { + let sphere_hit = ray_sphere_closest_hit(ray, *spheres[i], [0.001, closest_hit.distance]); + if sphere_hit.hit { + closest_hit = sphere_hit; + } + } + + if closest_hit.hit { + //return vec_mul_scalar(0.5, vec_add(closest_hit.normal, [1.0, 1.0, 1.0])); // normal + //return vec_mul_scalar(closest_hit.distance / 10.0, [1.0, 1.0, 1.0]); // depth + if closest_hit.material.type == 0 { + let bounce_dir = vec_normalize(vec_add(closest_hit.normal, random_unit_vec())); + let bounce_ray = Ray { origin: closest_hit.position, direction: bounce_dir }; + return vec_mul_componentwise( + closest_hit.material.linear_color, + shade_world(bounce_ray, spheres, bounces_left - 1) + ); + } else if closest_hit.material.type == 1 { + let bounce_dir = vec_reflect(ray.direction, closest_hit.normal); + let bounce_ray = Ray { origin: closest_hit.position, direction: bounce_dir }; + return vec_mul_componentwise( + closest_hit.material.linear_color, + shade_world(bounce_ray, spheres, bounces_left - 1) + ); + } else { + return [1.0, 0.0, 1.0]; + } + } + + return shade_sky(ray); +} + +fn shade_sky(ray: Ray) -> [f32; 3] { + let a = 0.5 * (ray.direction[1] + 1.0); + return vec_add( + vec_mul_scalar(1.0 - a, [1.0, 1.0, 1.0]), + vec_mul_scalar(a, [0.5, 0.7, 1.0]) + ); +} + +// Returns the distance from the ray origin to the sphere, or -1.0 if the ray doesn't hit. +fn ray_sphere_closest_hit(ray: Ray, sphere: Sphere, interval: [f32; 2]) -> Hit { + let to_sphere = vec_sub(sphere.center, ray.origin); + let h = vec_dot(ray.direction, to_sphere); + let c = vec_length_squared(to_sphere) - sphere.radius * sphere.radius; + let discriminant = h * h - c; + if discriminant < 0.0 { + return Hit { hit: false }; + } + + let discriminant_sqrt = SDL_sqrtf(discriminant); + let mut distance = h - discriminant_sqrt; + if interval_surrounds(interval, distance) == false { + distance = h - discriminant_sqrt; + if interval_surrounds(interval, distance) == false { + return Hit { hit: false }; + } + } + let hit_position = vec_add(ray.origin, vec_mul_scalar(distance, ray.direction)); + let mut front_face = true; + let mut normal = vec_normalize(vec_sub(hit_position, sphere.center)); + if vec_dot(normal, ray.direction) > 0.0 { + normal = vec_mul_scalar(0.0 - 1.0, normal); + front_face = false; + } + + return Hit { + hit: true, + front_face: front_face, + distance: distance, + normal: normal, + position: hit_position, + material: sphere.material, + }; +} + + +////////////////// +/// Other math /// +////////////////// + +fn clamp(min: f32, max: f32, value: f32) -> f32 { + if value > max { + return max; + } + if value < min { + return min; + } + return value; +} + +fn abs(f: f32) -> f32 { + if f < 0.0 { + return f * (0.0 - 1.0); + } + return f; +} + +fn vec_add(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] { + return [lhs[0] + rhs[0], lhs[1] + rhs[1], lhs[2] + rhs[2]]; +} + +fn vec_sub(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] { + return [lhs[0] - rhs[0], lhs[1] - rhs[1], lhs[2] - rhs[2]]; +} + +fn vec_dot(lhs: [f32; 3], rhs: [f32; 3]) -> f32 { + return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2]; +} + +fn vec_mul_componentwise(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] { + return [lhs[0] * rhs[0], lhs[1] * rhs[1], lhs[2] * rhs[2]]; +} + +fn vec_mul_scalar(lhs: f32, rhs: [f32; 3]) -> [f32; 3] { + return [lhs * rhs[0], lhs * rhs[1], lhs * rhs[2]]; +} + +fn vec_normalize(v: [f32; 3]) -> [f32; 3] { + let len_reciprocal = 1.0f32 / SDL_sqrtf(vec_length_squared(v)); + return vec_mul_scalar(len_reciprocal, v); +} + +fn vec_length_squared(v: [f32; 3]) -> f32 { + return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; +} + +fn vec_abs(v: [f32; 3]) -> [f32; 3] { + return [abs(v[0]), abs(v[1]), abs(v[2])]; +} + +fn vec_reflect(direction: [f32; 3], normal: [f32; 3]) -> [f32; 3] { + return vec_sub(direction, vec_mul_scalar(2.0f32 * vec_dot(direction, normal), normal)); +} + +fn interval_surrounds(interval: [f32; 2], value: f32) -> bool { + return (interval[0] < value) && (value < interval[1]); +} + +fn random_unit_vec() -> [f32; 3] { + let mut point = [ + SDL_randf() * 2.0f32 - 1.0f32, + SDL_randf() * 2.0f32 - 1.0f32, + SDL_randf() * 2.0f32 - 1.0f32 + ]; + let mut lensq = vec_length_squared(point); + while lensq > 1.0 { + point = [ + SDL_randf() * 2.0f32 - 1.0f32, + SDL_randf() * 2.0f32 - 1.0f32, + SDL_randf() * 2.0f32 - 1.0f32 + ]; + lensq = vec_length_squared(point); + } + let len_reciprocal = 1.0f32 / SDL_sqrtf(lensq); + return vec_mul_scalar(len_reciprocal, point); +} + +fn random_unit_vec_on_hemi(normal: [f32; 3]) -> [f32; 3] { + let rand_vec = random_unit_vec(); + if vec_dot(rand_vec, normal) < 0.0f32 { + return vec_mul_scalar(0.0f32 - 1.0f32, rand_vec); + } + return rand_vec; +} + +fn linear_to_srgb(linear: f32) -> u8 { + let mut floating_srgb = 0.0; + if linear <= 0.0031308f32 { + floating_srgb = 12.92f32 * linear; + } else { + floating_srgb = SDL_powf(linear as f32, 1.0 / 2.4) * 1.055f32 - 0.055f32; + } + let clamped = clamp(0.0, 1.0, floating_srgb); + return (clamped * 255.999) as u8; +} + +fn srgb_to_linear(srgb: u8) -> f32 { + let floating_srgb = srgb as f32 / 255.0; + if floating_srgb <= 0.04045f32 { + return floating_srgb / 12.92f32; + } + return SDL_powf((floating_srgb as f32 + 0.055) / 1.055, 2.4); +} diff --git a/reid/lib/std.reid b/reid/lib/std.reid index 0c8501e..d5089af 100644 --- a/reid/lib/std.reid +++ b/reid/lib/std.reid @@ -38,7 +38,7 @@ pub fn new_string() -> String { } pub fn from_str(str: *char) -> String { - let length = str_length(str); + let length = str_length(str) as u64; let mut new = new_string(); let static = String { inner: str, diff --git a/reid/src/codegen/intrinsics.rs b/reid/src/codegen/intrinsics.rs index 53657f2..3ad2184 100644 --- a/reid/src/codegen/intrinsics.rs +++ b/reid/src/codegen/intrinsics.rs @@ -131,6 +131,14 @@ pub fn form_intrinsic_binops() -> Vec { intrinsics.push(simple_binop_def(BinaryOperator::Minus, &ty, |scope, lhs, rhs| { scope.block.build(Instr::FSub(lhs, rhs)).unwrap() })); + intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| { + scope.block.build(Instr::FDiv(lhs, rhs)).unwrap() + })); + intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| { + let div = scope.block.build(Instr::FDiv(lhs, rhs)).unwrap(); + let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap(); + scope.block.build(Instr::Sub(lhs, mul)).unwrap() + })); intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| { scope.block.build(Instr::FCmp(CmpPredicate::EQ, lhs, rhs)).unwrap() })); @@ -151,6 +159,10 @@ pub fn form_intrinsic_binops() -> Vec { })); } + intrinsics.push(boolean_binop_def(And, &TypeKind::Bool, |scope, lhs, rhs| { + scope.block.build(Instr::And(lhs, rhs)).unwrap() + })); + intrinsics } diff --git a/reid/src/mir/typecheck/typecheck.rs b/reid/src/mir/typecheck/typecheck.rs index ec6488f..9b0ff25 100644 --- a/reid/src/mir/typecheck/typecheck.rs +++ b/reid/src/mir/typecheck/typecheck.rs @@ -217,9 +217,10 @@ impl Block { variable_reference.2, ); + dbg!(&var_t_resolved); + // Typecheck (and coerce) expression with said type let res = expression.typecheck(&mut state, &typerefs, Some(&var_t_resolved)); - // If expression resolution itself was erronous, resolve as // Unknown and note error. let res = state.or_else(res, TypeKind::Vague(Vague::Unknown), expression.1); @@ -413,10 +414,18 @@ impl Expression { ExprKind::BinOp(op, lhs, rhs, ret_ty) => { // First find unfiltered parameters to binop let lhs_res = lhs.typecheck(state, &typerefs, None); - let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1); let rhs_res = rhs.typecheck(state, &typerefs, None); + let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1); let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1); - let expected_return_ty = ret_ty.resolve_ref(typerefs); + + let mut expected_return_ty = ret_ty.resolve_ref(typerefs); + if let Some(hint_t) = hint_t { + expected_return_ty = state.or_else( + expected_return_ty.narrow_into(hint_t), + TypeKind::Vague(VagueType::Unknown), + self.1, + ); + }; let binops = state.scope.binops.filter(&pass::ScopeBinopKey { params: (lhs_type.clone(), rhs_type.clone()), @@ -433,11 +442,6 @@ impl Expression { *ret_ty = binop.narrow(&lhs_type, &rhs_type).unwrap().2; Ok(ret_ty.clone()) } else { - dbg!(&binops); - dbg!(&op, &lhs, &rhs); - dbg!(&lhs_type); - dbg!(&rhs_type); - dbg!(&expected_return_ty); panic!() } } @@ -537,7 +541,7 @@ impl Expression { }); // Typecheck and narrow index-expression - let idx_expr_res = idx_expr.typecheck(state, typerefs, Some(&TypeKind::U32)); + let idx_expr_res = idx_expr.typecheck(state, typerefs, Some(&TypeKind::Vague(VagueType::Integer))); state.ok(idx_expr_res, idx_expr.1); // TODO it could be possible to check length against constants.. @@ -559,7 +563,7 @@ impl Expression { ExprKind::Array(expressions) => { // Try to unwrap hint type from array if possible let hint_t = hint_t.map(|t| match t { - TypeKind::Array(type_kind, _) => &type_kind, + TypeKind::Array(type_kind, _) => type_kind, _ => t, }); @@ -704,7 +708,7 @@ impl Expression { Ok(*inner) } ExprKind::CastTo(expression, type_kind) => { - let expr = expression.typecheck(state, typerefs, Some(&type_kind))?; + let expr = expression.typecheck(state, typerefs, None)?; expr.resolve_ref(typerefs).cast_into(type_kind) } } diff --git a/reid/src/mir/typecheck/typeinference.rs b/reid/src/mir/typecheck/typeinference.rs index cdc6010..ca72bba 100644 --- a/reid/src/mir/typecheck/typeinference.rs +++ b/reid/src/mir/typecheck/typeinference.rs @@ -197,6 +197,9 @@ impl Block { let mut state = state.inner(); let inner_refs = outer_refs.inner(); + // Keep track of variables created in this scope + let mut scope_variables = Vec::new(); + for statement in &mut self.statements { match &mut statement.0 { StmtKind::Let(var, mutable, expr) => { @@ -217,6 +220,9 @@ impl Block { if let (Some(var_ref), Some(expr_ty_ref)) = (var_ref.as_mut(), expr_ty_ref.as_mut()) { var_ref.narrow(&expr_ty_ref); } + + // Add variable to list of tracked variables + scope_variables.push(var.clone()); } StmtKind::Set(lhs, rhs) => { // Infer hints for the expression itself @@ -266,6 +272,12 @@ impl Block { } } + // if variables aren't known at this time, they will never be. Default + // their types. + for variable in scope_variables { + inner_refs.try_default_deep(&variable.0); + } + Ok((kind, ret_type_ref)) } } @@ -328,15 +340,9 @@ impl Expression { widened_rhs = widened_rhs.widen_into(&binop.hands.1); } let binop_res = type_refs.from_binop(*op, &lhs_ref, &rhs_ref); - dbg!(&type_refs.types.type_refs); - dbg!(&type_refs.types.hints); lhs_ref.narrow(&type_refs.from_type(&widened_lhs).unwrap()); rhs_ref.narrow(&type_refs.from_type(&widened_rhs).unwrap()); - dbg!(&lhs_ref, &rhs_ref); *return_ty = binop_res.as_type(); - dbg!(&type_refs.types.hints, &type_refs.types.type_refs); - dbg!(&return_ty); - dbg!(&type_refs.from_type(&return_ty)); Ok(binop_res) } else { Err(ErrorKind::InvalidBinop( diff --git a/reid/src/mir/typecheck/typerefs.rs b/reid/src/mir/typecheck/typerefs.rs index c4865cd..08d934f 100644 --- a/reid/src/mir/typecheck/typerefs.rs +++ b/reid/src/mir/typecheck/typerefs.rs @@ -302,6 +302,27 @@ impl<'outer> ScopeTypeRefs<'outer> { } } + pub fn try_default_deep(&self, ty: &TypeKind) -> Option { + Some(match &ty { + TypeKind::Array(type_kind, _) => self.try_default_deep(type_kind)?, + TypeKind::CustomType(_) => ty.clone(), + TypeKind::Borrow(type_kind, _) => self.try_default_deep(type_kind)?, + TypeKind::UserPtr(type_kind) => self.try_default_deep(type_kind)?, + TypeKind::CodegenPtr(type_kind) => self.try_default_deep(type_kind)?, + TypeKind::Vague(vague_type) => match vague_type { + VagueType::Unknown => ty.clone(), + VagueType::Integer => ty.or_default().unwrap(), + VagueType::Decimal => ty.or_default().unwrap(), + VagueType::TypeRef(idx) => { + let typeref = TypeRef(Rc::new(RefCell::new(*idx)), self); + self.narrow_to_type(&typeref, &self.try_default_deep(&typeref.resolve_deep()?)?)? + .resolve_deep()? + } + }, + _ => ty.clone(), + }) + } + fn combine_vars(&'outer self, hint1: &TypeRef, hint2: &TypeRef) -> Option> { unsafe { let ty = self