fixing scoping bug

This commit is contained in:
Jakub Doka 2024-11-24 16:43:45 +01:00
parent 24a3aed360
commit 784d552c1d
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
3 changed files with 74 additions and 65 deletions

View file

@ -225,6 +225,7 @@ Struct := struct {
$new := fn(a: uint, b: uint): Self return .(a, b) $new := fn(a: uint, b: uint): Self return .(a, b)
$swap := fn(s: ^Self): void { $swap := fn(s: ^Self): void {
_ = diff(*s)
t := s.a t := s.a
s.a = s.b s.a = s.b
s.b = t s.b = t

View file

@ -35,7 +35,7 @@ pub use fs::*;
pub use utils::Ent; pub use utils::Ent;
use { use {
self::{ self::{
parser::{ExprRef, Pos}, parser::{CommentOr, Expr, ExprRef, Pos},
ty::{ArrayLen, Builtin, Module}, ty::{ArrayLen, Builtin, Module},
utils::EntVec, utils::EntVec,
}, },
@ -1262,6 +1262,28 @@ impl Types {
debug_assert_eq!(self.tasks.len(), 0); 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<ty::Id> {
match ty.expand() {
ty::Kind::Struct(s) => Some(self.ins.structs[s].file.into()),
_ => None,
}
}
} }
struct OptLayout { struct OptLayout {

View file

@ -27,7 +27,7 @@ use {
}, },
hashbrown::hash_map, hashbrown::hash_map,
hbbytecode::DisasmError, hbbytecode::DisasmError,
std::intrinsics::vtable_size, std::panic,
}; };
const VOID: Nid = 0; const VOID: Nid = 0;
@ -2572,7 +2572,7 @@ impl<'a> Codegen<'a> {
} }
pub fn generate(&mut self, entry: Module) { 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() { if self.tys.ins.funcs.is_empty() {
return; return;
} }
@ -2820,7 +2820,7 @@ impl<'a> Codegen<'a> {
Some(Value::var(index).ty(var.ty)) Some(Value::var(index).ty(var.ty))
} }
Expr::Ident { id, pos, .. } => { 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() { match decl.expand() {
ty::Kind::NEVER => Value::NEVER, ty::Kind::NEVER => Value::NEVER,
ty::Kind::Global(global) => self.gen_global(global), ty::Kind::Global(global) => self.gen_global(global),
@ -4057,12 +4057,14 @@ impl<'a> Codegen<'a> {
let tty = vtarget.ty; let tty = vtarget.ty;
match self.tys.base_of(tty).unwrap_or(tty).expand() { 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::Module(m) => {
match self.find_type(pos, self.ci.file, m, self.ci.parent, Err(name)).expand() {
ty::Kind::NEVER => Value::NEVER, ty::Kind::NEVER => Value::NEVER,
ty::Kind::Global(global) => self.gen_global(global), ty::Kind::Global(global) => self.gen_global(global),
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())), v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())),
}, }
}
ty::Kind::Enum(e) => { ty::Kind::Enum(e) => {
let intrnd = self.tys.names.project(name); let intrnd = self.tys.names.project(name);
self.gen_enum_variant(pos, e, intrnd) self.gen_enum_variant(pos, e, intrnd)
@ -4071,15 +4073,9 @@ impl<'a> Codegen<'a> {
let Struct { ast, file, .. } = self.tys.ins.structs[s]; let Struct { ast, file, .. } = self.tys.ins.structs[s];
if let Some((offset, ty)) = OffsetIter::offset_of(self.tys, s, name) { if let Some((offset, ty)) = OffsetIter::offset_of(self.tys, s, name) {
Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty)) 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()]) ast.get(&self.files[file.index()])
&& let ty = self.find_type_low( && let ty = self.find_type(pos, self.ci.file, file, s.into(), Err(name))
pos,
self.ci.file,
file,
Some((s.into(), scope)),
Err(name),
)
&& let ty::Kind::Func(_) = ty.expand() && let ty::Kind::Func(_) = ty.expand()
{ {
return Some(Err((ty, vtarget))); return Some(Err((ty, vtarget)));
@ -4109,21 +4105,8 @@ impl<'a> Codegen<'a> {
.expand() .expand()
{ {
ty::Kind::Struct(s) => { ty::Kind::Struct(s) => {
let Struct { ast, file, .. } = self.tys.ins.structs[s]; let Struct { file, .. } = self.tys.ins.structs[s];
let Expr::Struct { fields: &[.., CommentOr::Or(Err(scope))], .. } = match self.find_type(pos, self.ci.file, file, s.into(), Err(name)).expand() {
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()
{
ty::Kind::NEVER => Value::NEVER, ty::Kind::NEVER => Value::NEVER,
ty::Kind::Global(global) => self.gen_global(global), ty::Kind::Global(global) => self.gen_global(global),
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
@ -4131,7 +4114,7 @@ impl<'a> Codegen<'a> {
} }
} }
ty::Kind::Module(m) => { 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::NEVER => Value::NEVER,
ty::Kind::Global(global) => self.gen_global(global), ty::Kind::Global(global) => self.gen_global(global),
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
@ -4265,7 +4248,7 @@ impl<'a> Codegen<'a> {
return Value::NEVER; 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 ast = &self.files[file.index()];
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() }; let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() };
@ -4347,6 +4330,7 @@ impl<'a> Codegen<'a> {
self.ci.inline_depth += 1; self.ci.inline_depth += 1;
let prev_ret = self.ci.ret.replace(sig.ret); let prev_ret = self.ci.ret.replace(sig.ret);
let prev_file = mem::replace(&mut self.ci.file, file); 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(); let prev_ctrl = self.ci.ctrl.get();
if self.expr(body).is_some() { if self.expr(body).is_some() {
@ -4363,6 +4347,7 @@ impl<'a> Codegen<'a> {
self.ci.ret = prev_ret; self.ci.ret = prev_ret;
self.ci.file = prev_file; self.ci.file = prev_file;
self.ci.parent = prev_parent;
self.ci.inline_depth -= 1; self.ci.inline_depth -= 1;
self.ci.inline_var_base = prev_var_base; self.ci.inline_var_base = prev_var_base;
self.ci.inline_aclass_base = prev_aclass_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<Ident, &str>) -> ty::Id {
self.find_type(pos, file, file, file.into(), id)
}
fn find_type_in_scope(&mut self, pos: Pos, id: Result<Ident, &str>) -> ty::Id {
self.find_type(pos, self.ci.file, self.ci.file, self.ci.parent, id)
}
fn find_type( fn find_type(
&mut self, &mut self,
pos: Pos, pos: Pos,
from_file: Module, from_file: Module,
file: Module, file: Module,
id: Result<Ident, &str>, parent: ty::Id,
) -> 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])>,
id: Result<Ident, &str>, id: Result<Ident, &str>,
) -> ty::Id { ) -> ty::Id {
let ty = if let Ok(id) = id let ty = if let Ok(id) = id
@ -5384,9 +5367,24 @@ impl<'a> Codegen<'a> {
} else { } else {
let f = &self.files[file.index()]; let f = &self.files[file.index()];
let Some((expr @ Expr::BinOp { left, right, .. }, name)) = let mut piter = parent;
parser::find_decl(subscope.map(|(_, s)| s).unwrap_or(f.exprs()), &f.file, id) let Some((expr @ Expr::BinOp { left, right, .. }, name)) = (loop {
else { 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 { return match id {
Ok(_) => { Ok(_) => {
debug_assert_eq!(from_file, file); debug_assert_eq!(from_file, file);
@ -5421,22 +5419,10 @@ impl<'a> Codegen<'a> {
self.tys self.tys
.ins .ins
.consts .consts
.push(Const { .push(Const { ast: ExprRef::new(expr), name, file, parent })
ast: ExprRef::new(expr),
name,
file,
parent: subscope.map(|(p, _)| p).unwrap_or(file.into()),
})
.into() .into()
} else { } else {
self.parse_ty( self.parse_ty(TyScope { file, parent, name: Some(name) }, right)
TyScope {
file,
parent: subscope.map(|(p, _)| p).unwrap_or(file.into()),
name: Some(name),
},
right,
)
}, },
) )
}) })
@ -5491,11 +5477,11 @@ impl<'a> Codegen<'a> {
self.tys.make_opt(base) self.tys.make_opt(base)
} }
Expr::Ident { id, .. } if let Ok(bt) = ty::Builtin::try_from(id) => bt.into(), 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 } Expr::Field { target, pos, name }
if let ty::Kind::Module(inside) = self.parse_ty(sc.anon(), target).expand() => 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::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr),
Expr::Slice { size: None, item, .. } => { Expr::Slice { size: None, item, .. } => {