From 784d552c1dee2a3cfde4b83e01523d91988bb554 Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Sun, 24 Nov 2024 16:43:45 +0100 Subject: [PATCH] fixing scoping bug --- lang/README.md | 1 + lang/src/lib.rs | 24 +++++++++- lang/src/son.rs | 114 +++++++++++++++++++++--------------------------- 3 files changed, 74 insertions(+), 65 deletions(-) diff --git a/lang/README.md b/lang/README.md index dd314842e..7caa85db5 100644 --- a/lang/README.md +++ b/lang/README.md @@ -225,6 +225,7 @@ Struct := struct { $new := fn(a: uint, b: uint): Self return .(a, b) $swap := fn(s: ^Self): void { + _ = diff(*s) t := s.a s.a = s.b s.b = t diff --git a/lang/src/lib.rs b/lang/src/lib.rs index e8a9446e6..8b79f61b8 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -35,7 +35,7 @@ pub use fs::*; pub use utils::Ent; use { self::{ - parser::{ExprRef, Pos}, + parser::{CommentOr, Expr, ExprRef, Pos}, ty::{ArrayLen, Builtin, Module}, utils::EntVec, }, @@ -1262,6 +1262,28 @@ impl Types { debug_assert_eq!(self.tasks.len(), 0); } + + fn scope_of<'a>(&self, parent: ty::Id, file: &'a parser::Ast) -> Option<&'a [Expr<'a>]> { + match parent.expand() { + ty::Kind::Struct(s) => { + if let Expr::Struct { fields: [.., CommentOr::Or(Err(scope))], .. } = + self.ins.structs[s].ast.get(file) + { + Some(scope) + } else { + Some(&[]) + } + } + _ => None, + } + } + + fn parent_of(&self, ty: ty::Id) -> Option { + match ty.expand() { + ty::Kind::Struct(s) => Some(self.ins.structs[s].file.into()), + _ => None, + } + } } struct OptLayout { diff --git a/lang/src/son.rs b/lang/src/son.rs index 3b7cef51d..df8e60232 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -27,7 +27,7 @@ use { }, hashbrown::hash_map, hbbytecode::DisasmError, - std::intrinsics::vtable_size, + std::panic, }; const VOID: Nid = 0; @@ -2572,7 +2572,7 @@ impl<'a> Codegen<'a> { } pub fn generate(&mut self, entry: Module) { - self.find_type(0, entry, entry, Err("main")); + self.find_type_in_file(0, entry, Err("main")); if self.tys.ins.funcs.is_empty() { return; } @@ -2820,7 +2820,7 @@ impl<'a> Codegen<'a> { Some(Value::var(index).ty(var.ty)) } Expr::Ident { id, pos, .. } => { - let decl = self.find_type(pos, self.ci.file, self.ci.file, Ok(id)); + let decl = self.find_type_in_scope(pos, Ok(id)); match decl.expand() { ty::Kind::NEVER => Value::NEVER, ty::Kind::Global(global) => self.gen_global(global), @@ -4057,12 +4057,14 @@ impl<'a> Codegen<'a> { let tty = vtarget.ty; match self.tys.base_of(tty).unwrap_or(tty).expand() { - ty::Kind::Module(m) => match self.find_type(pos, self.ci.file, m, Err(name)).expand() { - ty::Kind::NEVER => Value::NEVER, - ty::Kind::Global(global) => self.gen_global(global), - ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), - v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())), - }, + ty::Kind::Module(m) => { + match self.find_type(pos, self.ci.file, m, self.ci.parent, Err(name)).expand() { + ty::Kind::NEVER => Value::NEVER, + ty::Kind::Global(global) => self.gen_global(global), + ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), + v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())), + } + } ty::Kind::Enum(e) => { let intrnd = self.tys.names.project(name); self.gen_enum_variant(pos, e, intrnd) @@ -4071,15 +4073,9 @@ impl<'a> Codegen<'a> { let Struct { ast, file, .. } = self.tys.ins.structs[s]; if let Some((offset, ty)) = OffsetIter::offset_of(self.tys, s, name) { Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty)) - } else if let Expr::Struct { fields: [.., CommentOr::Or(Err(scope))], .. } = + } else if let Expr::Struct { fields: [.., CommentOr::Or(Err(_))], .. } = ast.get(&self.files[file.index()]) - && let ty = self.find_type_low( - pos, - self.ci.file, - file, - Some((s.into(), scope)), - Err(name), - ) + && let ty = self.find_type(pos, self.ci.file, file, s.into(), Err(name)) && let ty::Kind::Func(_) = ty.expand() { return Some(Err((ty, vtarget))); @@ -4109,21 +4105,8 @@ impl<'a> Codegen<'a> { .expand() { ty::Kind::Struct(s) => { - let Struct { ast, file, .. } = self.tys.ins.structs[s]; - let Expr::Struct { fields: &[.., CommentOr::Or(Err(scope))], .. } = - ast.get(&self.files[file.index()]) - else { - self.error( - pos, - fa!("'{}' has not declarations", self.ty_display(s.into())), - ); - return Value::NEVER.map(Ok); - }; - - match self - .find_type_low(pos, self.ci.file, file, Some((s.into(), scope)), Err(name)) - .expand() - { + let Struct { file, .. } = self.tys.ins.structs[s]; + match self.find_type(pos, self.ci.file, file, s.into(), Err(name)).expand() { ty::Kind::NEVER => Value::NEVER, ty::Kind::Global(global) => self.gen_global(global), ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), @@ -4131,7 +4114,7 @@ impl<'a> Codegen<'a> { } } ty::Kind::Module(m) => { - match self.find_type(pos, self.ci.file, m, Err(name)).expand() { + match self.find_type(pos, self.ci.file, m, m.into(), Err(name)).expand() { ty::Kind::NEVER => Value::NEVER, ty::Kind::Global(global) => self.gen_global(global), ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), @@ -4265,7 +4248,7 @@ impl<'a> Codegen<'a> { return Value::NEVER; }; - let Func { expr, file, is_inline, .. } = self.tys.ins.funcs[fu]; + let Func { expr, file, is_inline, parent, .. } = self.tys.ins.funcs[fu]; let ast = &self.files[file.index()]; let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() }; @@ -4347,6 +4330,7 @@ impl<'a> Codegen<'a> { self.ci.inline_depth += 1; let prev_ret = self.ci.ret.replace(sig.ret); let prev_file = mem::replace(&mut self.ci.file, file); + let prev_parent = mem::replace(&mut self.ci.parent, parent); let prev_ctrl = self.ci.ctrl.get(); if self.expr(body).is_some() { @@ -4363,6 +4347,7 @@ impl<'a> Codegen<'a> { self.ci.ret = prev_ret; self.ci.file = prev_file; + self.ci.parent = prev_parent; self.ci.inline_depth -= 1; self.ci.inline_var_base = prev_var_base; self.ci.inline_aclass_base = prev_aclass_base; @@ -5354,22 +5339,20 @@ impl<'a> Codegen<'a> { }) } + fn find_type_in_file(&mut self, pos: Pos, file: Module, id: Result) -> ty::Id { + self.find_type(pos, file, file, file.into(), id) + } + + fn find_type_in_scope(&mut self, pos: Pos, id: Result) -> ty::Id { + self.find_type(pos, self.ci.file, self.ci.file, self.ci.parent, id) + } + fn find_type( &mut self, pos: Pos, from_file: Module, file: Module, - id: Result, - ) -> ty::Id { - self.find_type_low(pos, from_file, file, None, id) - } - - fn find_type_low( - &mut self, - pos: Pos, - from_file: Module, - file: Module, - subscope: Option<(ty::Id, &[Expr])>, + parent: ty::Id, id: Result, ) -> ty::Id { let ty = if let Ok(id) = id @@ -5384,9 +5367,24 @@ impl<'a> Codegen<'a> { } else { let f = &self.files[file.index()]; - let Some((expr @ Expr::BinOp { left, right, .. }, name)) = - parser::find_decl(subscope.map(|(_, s)| s).unwrap_or(f.exprs()), &f.file, id) - else { + let mut piter = parent; + let Some((expr @ Expr::BinOp { left, right, .. }, name)) = (loop { + if let Some(f) = + parser::find_decl(self.tys.scope_of(piter, f).unwrap_or(f.exprs()), &f.file, id) + { + break Some(f); + } + + piter = match self.tys.parent_of(piter) { + Some(p) => p, + None => { + if let ty::Kind::Struct(_) = parent.expand() { + panic!(); + } + break None; + } + }; + }) else { return match id { Ok(_) => { debug_assert_eq!(from_file, file); @@ -5421,22 +5419,10 @@ impl<'a> Codegen<'a> { self.tys .ins .consts - .push(Const { - ast: ExprRef::new(expr), - name, - file, - parent: subscope.map(|(p, _)| p).unwrap_or(file.into()), - }) + .push(Const { ast: ExprRef::new(expr), name, file, parent }) .into() } else { - self.parse_ty( - TyScope { - file, - parent: subscope.map(|(p, _)| p).unwrap_or(file.into()), - name: Some(name), - }, - right, - ) + self.parse_ty(TyScope { file, parent, name: Some(name) }, right) }, ) }) @@ -5491,11 +5477,11 @@ impl<'a> Codegen<'a> { self.tys.make_opt(base) } Expr::Ident { id, .. } if let Ok(bt) = ty::Builtin::try_from(id) => bt.into(), - Expr::Ident { id, pos, .. } => self.find_type(pos, sc.file, sc.file, Ok(id)), + Expr::Ident { id, pos, .. } => self.find_type(pos, sc.file, sc.file, sc.parent, Ok(id)), Expr::Field { target, pos, name } if let ty::Kind::Module(inside) = self.parse_ty(sc.anon(), target).expand() => { - self.find_type(pos, sc.file, inside, Err(name)) + self.find_type(pos, sc.file, inside, inside.into(), Err(name)) } Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr), Expr::Slice { size: None, item, .. } => {