saving
This commit is contained in:
parent
acacd10ee9
commit
9ed3c7ab9e
|
@ -161,6 +161,27 @@ drop := fn(a: uint): void {
|
|||
}
|
||||
```
|
||||
|
||||
#### nullable_types
|
||||
```hb
|
||||
main := fn(): int {
|
||||
a := &1
|
||||
|
||||
b := @as(?^uint, null)
|
||||
if decide() b = a
|
||||
|
||||
if b == null return 9001
|
||||
|
||||
c := @as(?uint, *b)
|
||||
if decide() c = null
|
||||
|
||||
if c != null return 42
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
decide := fn(): bool return true
|
||||
```
|
||||
|
||||
#### structs
|
||||
```hb
|
||||
Ty := struct {
|
||||
|
@ -1196,3 +1217,4 @@ main := fn(): int {
|
|||
opaque := fn(): Foo {
|
||||
return .(3, 2)
|
||||
}
|
||||
```
|
||||
|
|
131
lang/src/lib.rs
131
lang/src/lib.rs
|
@ -290,6 +290,7 @@ mod ty {
|
|||
|
||||
pub type Builtin = u32;
|
||||
pub type Struct = u32;
|
||||
pub type Opt = u32;
|
||||
pub type Ptr = u32;
|
||||
pub type Func = u32;
|
||||
pub type Global = u32;
|
||||
|
@ -373,6 +374,7 @@ mod ty {
|
|||
crate::SymKey::Struct(st.file, st.pos, st.captures)
|
||||
}
|
||||
Kind::Ptr(p) => crate::SymKey::Pointer(&ctx.ptrs[p as usize]),
|
||||
Kind::Opt(p) => crate::SymKey::Optional(&ctx.opts[p as usize]),
|
||||
Kind::Func(f) => {
|
||||
let fc = &ctx.funcs[f as usize];
|
||||
if let Some(base) = fc.base {
|
||||
|
@ -441,6 +443,10 @@ mod ty {
|
|||
matches!(self.expand(), Kind::Ptr(_)) || self.is_never()
|
||||
}
|
||||
|
||||
pub fn is_optional(self) -> bool {
|
||||
matches!(self.expand(), Kind::Opt(_)) || self.is_never()
|
||||
}
|
||||
|
||||
pub fn try_upcast(self, ob: Self) -> Option<Self> {
|
||||
let (oa, ob) = (Self(self.0.min(ob.0)), Self(self.0.max(ob.0)));
|
||||
let (a, b) = (oa.strip_pointer(), ob.strip_pointer());
|
||||
|
@ -490,9 +496,16 @@ mod ty {
|
|||
|
||||
pub(crate) fn loc(&self, tys: &Types) -> Loc {
|
||||
match self.expand() {
|
||||
Kind::Opt(o)
|
||||
if let ty = tys.ins.opts[o as usize].base
|
||||
&& ty.loc(tys) == Loc::Reg
|
||||
&& (ty.is_pointer() || tys.size_of(ty) < 8) =>
|
||||
{
|
||||
Loc::Reg
|
||||
}
|
||||
Kind::Ptr(_) | Kind::Builtin(_) => Loc::Reg,
|
||||
Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg,
|
||||
Kind::Struct(_) | Kind::Slice(_) => Loc::Stack,
|
||||
Kind::Struct(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack,
|
||||
Kind::Func(_) | Kind::Global(_) | Kind::Module(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -633,6 +646,7 @@ mod ty {
|
|||
pub enum Kind {
|
||||
Builtin,
|
||||
Struct,
|
||||
Opt,
|
||||
Ptr,
|
||||
Func,
|
||||
Global,
|
||||
|
@ -675,6 +689,10 @@ mod ty {
|
|||
f.write_str("]")
|
||||
}
|
||||
TK::Builtin(ty) => f.write_str(to_str(ty)),
|
||||
TK::Opt(ty) => {
|
||||
f.write_str("?")?;
|
||||
self.rety(self.tys.ins.opts[ty as usize].base).fmt(f)
|
||||
}
|
||||
TK::Ptr(ty) => {
|
||||
f.write_str("^")?;
|
||||
self.rety(self.tys.ins.ptrs[ty as usize].base).fmt(f)
|
||||
|
@ -730,6 +748,7 @@ type Size = u32;
|
|||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum SymKey<'a> {
|
||||
Pointer(&'a Ptr),
|
||||
Optional(&'a Opt),
|
||||
Struct(FileId, Pos, ty::Tuple),
|
||||
FuncInst(ty::Func, ty::Tuple),
|
||||
Decl(FileId, Ident),
|
||||
|
@ -840,7 +859,12 @@ struct Struct {
|
|||
field_start: u32,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct Opt {
|
||||
base: ty::Id,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct Ptr {
|
||||
base: ty::Id,
|
||||
}
|
||||
|
@ -935,6 +959,7 @@ pub struct TypeIns {
|
|||
structs: Vec<Struct>,
|
||||
fields: Vec<Field>,
|
||||
ptrs: Vec<Ptr>,
|
||||
opts: Vec<Opt>,
|
||||
slices: Vec<Array>,
|
||||
}
|
||||
|
||||
|
@ -1065,6 +1090,10 @@ trait TypeParser {
|
|||
let base = self.parse_ty(file, val, None, files);
|
||||
self.tys().make_ptr(base)
|
||||
}
|
||||
Expr::UnOp { op: TokenKind::Que, val, .. } => {
|
||||
let base = self.parse_ty(file, val, None, files);
|
||||
self.tys().make_opt(base)
|
||||
}
|
||||
Expr::Ident { id, .. } if id.is_null() => id.len().into(),
|
||||
Expr::Ident { id, pos, .. } => self.find_type(pos, file, file, Ok(id), files),
|
||||
Expr::Field { target, pos, name }
|
||||
|
@ -1206,64 +1235,44 @@ impl Types {
|
|||
(ret, iter)
|
||||
}
|
||||
|
||||
fn make_ptr(&mut self, base: ty::Id) -> ty::Id {
|
||||
ty::Kind::Ptr(self.make_ptr_low(base)).compress()
|
||||
}
|
||||
|
||||
fn make_ptr_low(&mut self, base: ty::Id) -> ty::Ptr {
|
||||
let ptr = Ptr { base };
|
||||
let (entry, hash) = self.syms.entry(SymKey::Pointer(&ptr), &self.ins);
|
||||
match entry {
|
||||
hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value,
|
||||
hash_map::RawEntryMut::Vacant(v) => {
|
||||
self.ins.ptrs.push(ptr);
|
||||
v.insert(
|
||||
ctx_map::Key {
|
||||
value: ty::Kind::Ptr(self.ins.ptrs.len() as u32 - 1).compress(),
|
||||
hash,
|
||||
},
|
||||
(),
|
||||
fn make_opt(&mut self, base: ty::Id) -> ty::Id {
|
||||
self.make_generic_ty(
|
||||
Opt { base },
|
||||
|ins| &mut ins.opts,
|
||||
|e| SymKey::Optional(e),
|
||||
ty::Kind::Opt,
|
||||
)
|
||||
.0
|
||||
.value
|
||||
}
|
||||
}
|
||||
.expand()
|
||||
.inner()
|
||||
}
|
||||
|
||||
fn make_array(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Id {
|
||||
ty::Kind::Slice(self.make_array_low(ty, len)).compress()
|
||||
fn make_ptr(&mut self, base: ty::Id) -> ty::Id {
|
||||
self.make_generic_ty(
|
||||
Ptr { base },
|
||||
|ins| &mut ins.ptrs,
|
||||
|e| SymKey::Pointer(e),
|
||||
ty::Kind::Ptr,
|
||||
)
|
||||
}
|
||||
|
||||
fn make_array_low(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Slice {
|
||||
self.syms
|
||||
.get_or_insert(SymKey::Array(&Array { elem: ty, len }), &mut self.ins, |ins| {
|
||||
ins.slices.push(Array { elem: ty, len });
|
||||
ty::Kind::Slice(ins.slices.len() as u32 - 1).compress()
|
||||
fn make_array(&mut self, elem: ty::Id, len: ArrayLen) -> ty::Id {
|
||||
self.make_generic_ty(
|
||||
Array { elem, len },
|
||||
|ins| &mut ins.slices,
|
||||
|e| SymKey::Array(e),
|
||||
ty::Kind::Slice,
|
||||
)
|
||||
}
|
||||
|
||||
fn make_generic_ty<T: Copy>(
|
||||
&mut self,
|
||||
ty: T,
|
||||
get_col: fn(&mut TypeIns) -> &mut Vec<T>,
|
||||
key: fn(&T) -> SymKey,
|
||||
kind: fn(u32) -> ty::Kind,
|
||||
) -> ty::Id {
|
||||
*self.syms.get_or_insert(key(&{ ty }), &mut self.ins, |ins| {
|
||||
get_col(ins).push(ty);
|
||||
kind(get_col(ins).len() as u32 - 1).compress()
|
||||
})
|
||||
.expand()
|
||||
.inner()
|
||||
|
||||
//let array = Array { ty, len };
|
||||
//let (entry, hash) = self.syms.entry(SymKey::Array(&array), &self.ins);
|
||||
//match entry {
|
||||
// hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value,
|
||||
// hash_map::RawEntryMut::Vacant(v) => {
|
||||
// self.ins.arrays.push(array);
|
||||
// v.insert(
|
||||
// ctx_map::Key {
|
||||
// value: ty::Kind::Slice(self.ins.ptrs.len() as u32 - 1).compress(),
|
||||
// hash,
|
||||
// },
|
||||
// (),
|
||||
// )
|
||||
// .0
|
||||
// .value
|
||||
// }
|
||||
//}
|
||||
//.expand()
|
||||
//.inner()
|
||||
}
|
||||
|
||||
fn size_of(&self, ty: ty::Id) -> Size {
|
||||
|
@ -1328,6 +1337,20 @@ impl Types {
|
|||
}
|
||||
}
|
||||
|
||||
fn inner_of(&self, ty: ty::Id) -> Option<ty::Id> {
|
||||
match ty.expand() {
|
||||
ty::Kind::Opt(o) => Some(self.ins.opts[o as usize].base),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn opt_flag_field(&self, ty: ty::Id) -> (Offset, ty::Id) {
|
||||
match ty.expand() {
|
||||
ty::Kind::Ptr(_) => (0, ty::Id::UINT),
|
||||
_ => todo!("{ty:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn find_struct_field(&self, s: ty::Struct, name: &str) -> Option<usize> {
|
||||
let name = self.names.project(name)?;
|
||||
self.struct_fields(s).iter().position(|f| f.name == name)
|
||||
|
|
|
@ -443,7 +443,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
pos
|
||||
},
|
||||
},
|
||||
T::Band | T::Mul | T::Xor | T::Sub => E::UnOp {
|
||||
T::Band | T::Mul | T::Xor | T::Sub | T::Que => E::UnOp {
|
||||
pos,
|
||||
op: token.kind,
|
||||
val: {
|
||||
|
|
107
lang/src/son.rs
107
lang/src/son.rs
|
@ -654,6 +654,14 @@ impl Nodes {
|
|||
}
|
||||
}
|
||||
|
||||
fn new_const(&mut self, ty: ty::Id, value: impl Into<i64>) -> Nid {
|
||||
self.new_node_nop(ty, Kind::CInt { value: value.into() }, [VOID])
|
||||
}
|
||||
|
||||
fn new_const_lit(&mut self, ty: ty::Id, value: impl Into<i64>) -> Value {
|
||||
self.new_node_lit(ty, Kind::CInt { value: value.into() }, [VOID])
|
||||
}
|
||||
|
||||
fn new_node_lit(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Value {
|
||||
Value::new(self.new_node(ty, kind, inps)).ty(ty)
|
||||
}
|
||||
|
@ -772,18 +780,14 @@ impl Nodes {
|
|||
if let (&K::CInt { value: a }, &K::CInt { value: b }) =
|
||||
(&self[lhs].kind, &self[rhs].kind)
|
||||
{
|
||||
return Some(self.new_node(
|
||||
ty,
|
||||
K::CInt { value: op.apply_binop(a, b, is_float) },
|
||||
[ctrl],
|
||||
));
|
||||
return Some(self.new_const(ty, op.apply_binop(a, b, is_float)));
|
||||
}
|
||||
|
||||
if lhs == rhs {
|
||||
match op {
|
||||
T::Sub => return Some(self.new_node(ty, K::CInt { value: 0 }, [ctrl])),
|
||||
T::Sub => return Some(self.new_const(ty, 0)),
|
||||
T::Add => {
|
||||
let rhs = self.new_node_nop(ty, K::CInt { value: 2 }, [ctrl]);
|
||||
let rhs = self.new_const(ty, 2);
|
||||
return Some(
|
||||
self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs]),
|
||||
);
|
||||
|
@ -813,11 +817,7 @@ impl Nodes {
|
|||
&& let K::CInt { value: bv } = self[rhs].kind
|
||||
{
|
||||
// (a op #b) op #c => a op (#b op #c)
|
||||
let new_rhs = self.new_node_nop(
|
||||
ty,
|
||||
K::CInt { value: op.apply_binop(av, bv, is_float) },
|
||||
[ctrl],
|
||||
);
|
||||
let new_rhs = self.new_const(ty, op.apply_binop(av, bv, is_float));
|
||||
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
|
||||
}
|
||||
|
||||
|
@ -834,7 +834,7 @@ impl Nodes {
|
|||
&& let K::CInt { value } = self[self[lhs].inputs[2]].kind
|
||||
{
|
||||
// a * #n + a => a * (#n + 1)
|
||||
let new_rhs = self.new_node_nop(ty, K::CInt { value: value + 1 }, [ctrl]);
|
||||
let new_rhs = self.new_const(ty, value + 1);
|
||||
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs]));
|
||||
}
|
||||
|
||||
|
@ -843,7 +843,7 @@ impl Nodes {
|
|||
&& let K::CInt { value: a } = self[rhs].kind
|
||||
&& let K::CInt { value: b } = self[self[lhs].inputs[2]].kind
|
||||
{
|
||||
let new_rhs = self.new_node_nop(ty, K::CInt { value: b - a }, [ctrl]);
|
||||
let new_rhs = self.new_const(ty, b - a);
|
||||
return Some(self.new_node(ty, K::BinOp { op: T::Add }, [
|
||||
ctrl,
|
||||
self[lhs].inputs[1],
|
||||
|
@ -864,17 +864,13 @@ impl Nodes {
|
|||
}
|
||||
}
|
||||
K::UnOp { op } => {
|
||||
let &[ctrl, oper] = self[target].inputs.as_slice() else { unreachable!() };
|
||||
let &[_, oper] = self[target].inputs.as_slice() else { unreachable!() };
|
||||
let ty = self[target].ty;
|
||||
|
||||
let is_float = self[oper].ty.is_float();
|
||||
|
||||
if let K::CInt { value } = self[oper].kind {
|
||||
return Some(self.new_node(
|
||||
ty,
|
||||
K::CInt { value: op.apply_unop(value, is_float) },
|
||||
[ctrl],
|
||||
));
|
||||
return Some(self.new_const(ty, op.apply_unop(value, is_float)));
|
||||
}
|
||||
}
|
||||
K::If => {
|
||||
|
@ -2307,21 +2303,31 @@ impl<'a> Codegen<'a> {
|
|||
// ordered by complexity of the expression
|
||||
match *expr {
|
||||
Expr::Null { pos } => {
|
||||
inference!(ty, ctx, self, pos, "null pointer", "@as(^<ty>, null)");
|
||||
inference!(oty, ctx, self, pos, "null pointer", "@as(^<ty>, null)");
|
||||
|
||||
if !ty.is_pointer() {
|
||||
let Some(ty) = self.tys.inner_of(oty) else {
|
||||
self.report(
|
||||
pos,
|
||||
fa!(
|
||||
"'null' expression was inferred to be '{}',
|
||||
which is not a pointer (and that is not supported yet)",
|
||||
self.ty_display(ty)
|
||||
which is not optional",
|
||||
self.ty_display(oty)
|
||||
),
|
||||
);
|
||||
return Value::NEVER;
|
||||
}
|
||||
};
|
||||
|
||||
Some(self.ci.nodes.new_node_lit(ty, Kind::CInt { value: 0 }, [VOID]))
|
||||
match oty.loc(self.tys) {
|
||||
Loc::Reg => Some(self.ci.nodes.new_const_lit(oty, 0)),
|
||||
Loc::Stack => {
|
||||
let (off, flag_ty) = self.tys.opt_flag_field(ty);
|
||||
let stack = self.new_stack(oty);
|
||||
let offset = self.offset(stack, off);
|
||||
let value = self.ci.nodes.new_const(flag_ty, 0);
|
||||
self.store_mem(offset, flag_ty, value);
|
||||
Some(Value::ptr(stack).ty(oty))
|
||||
}
|
||||
}
|
||||
}
|
||||
Expr::Idk { pos } => {
|
||||
inference!(ty, ctx, self, pos, "value", "@as(<ty>, idk)");
|
||||
|
@ -2340,20 +2346,14 @@ impl<'a> Codegen<'a> {
|
|||
Value::NEVER
|
||||
}
|
||||
}
|
||||
Expr::Bool { value, .. } => Some(self.ci.nodes.new_node_lit(
|
||||
ty::Id::BOOL,
|
||||
Kind::CInt { value: value as i64 },
|
||||
[VOID],
|
||||
)),
|
||||
Expr::Number { value, .. } => Some(self.ci.nodes.new_node_lit(
|
||||
Expr::Bool { value, .. } => Some(self.ci.nodes.new_const_lit(ty::Id::BOOL, value)),
|
||||
Expr::Number { value, .. } => Some(self.ci.nodes.new_const_lit(
|
||||
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
||||
Kind::CInt { value },
|
||||
[VOID],
|
||||
value,
|
||||
)),
|
||||
Expr::Float { value, .. } => Some(self.ci.nodes.new_node_lit(
|
||||
Expr::Float { value, .. } => Some(self.ci.nodes.new_const_lit(
|
||||
ctx.ty.filter(|ty| ty.is_float()).unwrap_or(ty::Id::F32),
|
||||
Kind::CInt { value: value as _ },
|
||||
[VOID],
|
||||
value as i64,
|
||||
)),
|
||||
Expr::Ident { id, .. }
|
||||
if let Some(index) = self.ci.scope.vars.iter().rposition(|v| v.id == id) =>
|
||||
|
@ -2551,11 +2551,7 @@ impl<'a> Codegen<'a> {
|
|||
if val.ty.is_integer() {
|
||||
Some(self.ci.nodes.new_node_lit(val.ty, Kind::UnOp { op }, [VOID, val.id]))
|
||||
} else if val.ty.is_float() {
|
||||
let value = self.ci.nodes.new_node_nop(
|
||||
val.ty,
|
||||
Kind::CInt { value: (-1f64).to_bits() as _ },
|
||||
[VOID],
|
||||
);
|
||||
let value = self.ci.nodes.new_const(val.ty, (-1f64).to_bits() as i64);
|
||||
Some(self.ci.nodes.new_node_lit(val.ty, Kind::BinOp { op: TokenKind::Mul }, [
|
||||
VOID, val.id, value,
|
||||
]))
|
||||
|
@ -2669,8 +2665,7 @@ impl<'a> Codegen<'a> {
|
|||
let elem = self.tys.ins.slices[s as usize].elem;
|
||||
let mut idx = self.expr_ctx(index, Ctx::default().with_ty(ty::Id::DEFAULT_INT))?;
|
||||
self.assert_ty(index.pos(), &mut idx, ty::Id::DEFAULT_INT, "subscript");
|
||||
let value = self.tys.size_of(elem) as i64;
|
||||
let size = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value }, [VOID]);
|
||||
let size = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem));
|
||||
let inps = [VOID, idx.id, size];
|
||||
let offset =
|
||||
self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps);
|
||||
|
@ -2690,18 +2685,16 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
Expr::Directive { name: "sizeof", args: [ty], .. } => {
|
||||
let ty = self.ty(ty);
|
||||
Some(self.ci.nodes.new_node_lit(
|
||||
Some(self.ci.nodes.new_const_lit(
|
||||
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
||||
Kind::CInt { value: self.tys.size_of(ty) as _ },
|
||||
[VOID],
|
||||
self.tys.size_of(ty),
|
||||
))
|
||||
}
|
||||
Expr::Directive { name: "alignof", args: [ty], .. } => {
|
||||
let ty = self.ty(ty);
|
||||
Some(self.ci.nodes.new_node_lit(
|
||||
Some(self.ci.nodes.new_const_lit(
|
||||
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
||||
Kind::CInt { value: self.tys.align_of(ty) as _ },
|
||||
[VOID],
|
||||
self.tys.align_of(ty),
|
||||
))
|
||||
}
|
||||
Expr::Directive { name: "bitcast", args: [val], pos } => {
|
||||
|
@ -3166,8 +3159,8 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
}
|
||||
Expr::Struct { .. } => {
|
||||
let value = self.ty(expr).repr() as i64;
|
||||
Some(self.ci.nodes.new_node_lit(ty::Id::TYPE, Kind::CInt { value }, [VOID]))
|
||||
let value = self.ty(expr).repr();
|
||||
Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, value))
|
||||
}
|
||||
Expr::Ctor { pos, ty, fields, .. } => {
|
||||
ctx.ty = ty.map(|ty| self.ty(ty)).or(ctx.ty);
|
||||
|
@ -3729,7 +3722,7 @@ impl<'a> Codegen<'a> {
|
|||
return val;
|
||||
}
|
||||
|
||||
let off = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value: off as i64 }, [VOID]);
|
||||
let off = self.ci.nodes.new_const(ty::Id::INT, off);
|
||||
let (aclass, mem) = self.ci.nodes.aclass_index(val);
|
||||
let inps = [VOID, val, off];
|
||||
let seted = self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps);
|
||||
|
@ -3914,9 +3907,7 @@ impl<'a> Codegen<'a> {
|
|||
if matches!(op, TokenKind::Add | TokenKind::Sub)
|
||||
&& let Some(elem) = self.tys.base_of(upcasted)
|
||||
{
|
||||
let value = self.tys.size_of(elem) as i64;
|
||||
let cnst =
|
||||
self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value }, [VOID]);
|
||||
let cnst = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem));
|
||||
oper.id =
|
||||
self.ci.nodes.new_node(upcasted, Kind::BinOp { op: TokenKind::Mul }, [
|
||||
VOID, oper.id, cnst,
|
||||
|
@ -3975,9 +3966,8 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
fn extend(&mut self, value: &mut Value, to: ty::Id) {
|
||||
self.strip_ptr(value);
|
||||
let val = (1i64 << (self.tys.size_of(value.ty) * 8)) - 1;
|
||||
value.ty = to;
|
||||
let mask = self.ci.nodes.new_node_nop(to, Kind::CInt { value: val }, [VOID]);
|
||||
let mask = self.ci.nodes.new_const(to, (1i64 << (self.tys.size_of(value.ty) * 8)) - 1);
|
||||
let inps = [VOID, value.id, mask];
|
||||
*value = self.ci.nodes.new_node_lit(to, Kind::BinOp { op: TokenKind::Band }, inps);
|
||||
}
|
||||
|
@ -4137,6 +4127,7 @@ mod tests {
|
|||
variables;
|
||||
loops;
|
||||
pointers;
|
||||
nullable_types;
|
||||
structs;
|
||||
hex_octal_binary_literals;
|
||||
struct_operators;
|
||||
|
|
0
lang/tests/son_tests_nullable_types.txt
Normal file
0
lang/tests/son_tests_nullable_types.txt
Normal file
Loading…
Reference in a new issue