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)
$swap := fn(s: ^Self): void {
_ = diff(*s)
t := s.a
s.a = s.b
s.b = t

View file

@ -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<ty::Id> {
match ty.expand() {
ty::Kind::Struct(s) => Some(self.ins.structs[s].file.into()),
_ => None,
}
}
}
struct OptLayout {

View file

@ -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<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(
&mut self,
pos: Pos,
from_file: Module,
file: Module,
id: Result<Ident, &str>,
) -> 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<Ident, &str>,
) -> 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, .. } => {