conlang: add lang items, remove Empty
, and shuffle typeck
This commit is contained in:
parent
ead1f351a7
commit
f41e5fc49a
@ -224,7 +224,6 @@ pub struct Ty {
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum TyKind {
|
||||
Never,
|
||||
Empty,
|
||||
Infer,
|
||||
Path(Path),
|
||||
Array(TyArray),
|
||||
|
@ -165,7 +165,6 @@ impl Display for Function {
|
||||
let Self { name, gens, sign: sign @ TyFn { args, rety }, bind, body } = self;
|
||||
let types = match args.kind {
|
||||
TyKind::Tuple(TyTuple { ref types }) => types.as_slice(),
|
||||
TyKind::Empty => Default::default(),
|
||||
_ => {
|
||||
write!(f, "Invalid function signature: {sign}")?;
|
||||
Default::default()
|
||||
@ -191,7 +190,9 @@ impl Display for Function {
|
||||
write!(f, "{arg}: {ty}")?;
|
||||
}
|
||||
}
|
||||
if TyKind::Empty != rety.kind {
|
||||
if let TyKind::Tuple(TyTuple { types }) = &rety.kind
|
||||
&& !types.as_slice().is_empty()
|
||||
{
|
||||
write!(f, " -> {rety}")?
|
||||
}
|
||||
|
||||
@ -295,7 +296,6 @@ impl Display for TyKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
TyKind::Never => "!".fmt(f),
|
||||
TyKind::Empty => "()".fmt(f),
|
||||
TyKind::Infer => "_".fmt(f),
|
||||
TyKind::Path(v) => v.fmt(f),
|
||||
TyKind::Array(v) => v.fmt(f),
|
||||
@ -349,8 +349,10 @@ impl Display for TyFn {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Self { args, rety } = self;
|
||||
write!(f, "fn {args}")?;
|
||||
if TyKind::Empty != rety.kind {
|
||||
write!(f, " -> {rety}")?;
|
||||
if let TyKind::Tuple(TyTuple { types }) = &rety.kind
|
||||
&& !types.as_slice().is_empty()
|
||||
{
|
||||
write!(f, " -> {rety}")?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ impl WeightOf for Ty {
|
||||
impl WeightOf for TyKind {
|
||||
fn weight_of(&self) -> usize {
|
||||
match self {
|
||||
TyKind::Never | TyKind::Empty | TyKind::Infer => size_of_val(self),
|
||||
TyKind::Never | TyKind::Infer => size_of_val(self),
|
||||
TyKind::Path(v) => v.weight_of(),
|
||||
TyKind::Array(v) => v.weight_of(),
|
||||
TyKind::Slice(v) => v.weight_of(),
|
||||
|
@ -531,7 +531,6 @@ pub fn or_fold_use_tree<F: Fold + ?Sized>(folder: &mut F, tree: UseTree) -> UseT
|
||||
pub fn or_fold_ty_kind<F: Fold + ?Sized>(folder: &mut F, kind: TyKind) -> TyKind {
|
||||
match kind {
|
||||
TyKind::Never => TyKind::Never,
|
||||
TyKind::Empty => TyKind::Empty,
|
||||
TyKind::Infer => TyKind::Infer,
|
||||
TyKind::Path(p) => TyKind::Path(folder.fold_path(p)),
|
||||
TyKind::Array(a) => TyKind::Array(folder.fold_ty_array(a)),
|
||||
|
@ -369,7 +369,6 @@ impl Walk for TyKind {
|
||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
||||
match self {
|
||||
TyKind::Never => {}
|
||||
TyKind::Empty => {}
|
||||
TyKind::Infer => {}
|
||||
TyKind::Path(value) => value.visit_in(v),
|
||||
TyKind::Array(value) => value.visit_in(v),
|
||||
|
@ -723,9 +723,12 @@ impl Interpret for Cast {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Cast { head, ty } = self;
|
||||
let value = head.interpret(env)?;
|
||||
if TyKind::Empty == ty.kind {
|
||||
|
||||
if let TyKind::Tuple(TyTuple { types }) = &ty.kind
|
||||
&& types.as_slice().is_empty()
|
||||
{
|
||||
return Ok(ConValue::Empty);
|
||||
};
|
||||
}
|
||||
let TyKind::Path(Path { absolute: false, parts }) = &ty.kind else {
|
||||
Err(Error::TypeError())?
|
||||
};
|
||||
|
@ -464,13 +464,18 @@ impl Parse<'_> for Function {
|
||||
let gens = Generics::parse(p)?;
|
||||
let ((bind, types), span) = delim(Spanned::<FnSig>::parse, PARENS, P)(p)?;
|
||||
let sign = TyFn {
|
||||
args: Box::new(match types.len() {
|
||||
0 => Ty { span, kind: TyKind::Empty, gens: Default::default() },
|
||||
_ => Ty { span, kind: TyKind::Tuple(TyTuple { types }), gens: Default::default() },
|
||||
args: Box::new(Ty {
|
||||
span,
|
||||
kind: TyKind::Tuple(TyTuple { types }),
|
||||
gens: Default::default(),
|
||||
}),
|
||||
rety: Box::new(match p.match_type(TokenKind::Arrow, Parsing::TyFn) {
|
||||
Ok(_) => Ty::parse(p)?,
|
||||
Err(_) => Ty { span, kind: TyKind::Empty, gens: Generics { vars: vec![] } },
|
||||
Err(_) => Ty {
|
||||
span,
|
||||
kind: TyKind::Tuple(TyTuple { types: vec![] }),
|
||||
gens: Generics { vars: vec![] },
|
||||
},
|
||||
}),
|
||||
};
|
||||
Ok(Function {
|
||||
@ -736,10 +741,7 @@ impl Parse<'_> for TyKind {
|
||||
}
|
||||
TokenKind::LParen => {
|
||||
let out = TyTuple::parse(p)?;
|
||||
match out.types.is_empty() {
|
||||
true => TyKind::Empty,
|
||||
false => TyKind::Tuple(out),
|
||||
}
|
||||
TyKind::Tuple(out)
|
||||
}
|
||||
TokenKind::Fn => TyFn::parse(p)?.into(),
|
||||
path_like!() => {
|
||||
@ -802,15 +804,18 @@ impl Parse<'_> for TyFn {
|
||||
let span = Span(head, p.loc());
|
||||
|
||||
Ok(TyFn {
|
||||
args: Box::new(match args {
|
||||
t if t.is_empty() => Ty { kind: TyKind::Empty, span, gens: Default::default() },
|
||||
types => {
|
||||
Ty { kind: TyKind::Tuple(TyTuple { types }), span, gens: Default::default() }
|
||||
}
|
||||
args: Box::new(Ty {
|
||||
kind: TyKind::Tuple(TyTuple { types: args }),
|
||||
span,
|
||||
gens: Default::default(),
|
||||
}),
|
||||
rety: Box::new(match p.match_type(TokenKind::Arrow, Parsing::TyFn) {
|
||||
Ok(_) => Ty::parse(p)?,
|
||||
Err(_) => Ty { span, kind: TyKind::Empty, gens: Generics { vars: vec![] } },
|
||||
Err(_) => Ty {
|
||||
span,
|
||||
kind: TyKind::Tuple(TyTuple { types: vec![] }),
|
||||
gens: Generics { vars: vec![] },
|
||||
},
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
@ -275,7 +275,6 @@ pub mod clangify {
|
||||
let TyFn { args, rety } = sign;
|
||||
let types = match &args.kind {
|
||||
TyKind::Tuple(TyTuple { types }) => types.as_slice(),
|
||||
TyKind::Empty => &[],
|
||||
_ => panic!("Unsupported function args: {args}"),
|
||||
};
|
||||
let bind = match bind {
|
||||
@ -472,7 +471,6 @@ pub mod clangify {
|
||||
TyKind::Fn(TyFn { args, rety }) => {
|
||||
y.nest("(").p(rety).p(" *").p(mutable).p(name).p(")(");
|
||||
match &args.kind {
|
||||
TyKind::Empty => {}
|
||||
TyKind::Tuple(TyTuple { types }) => {
|
||||
for (idx, ty) in types.iter().enumerate() {
|
||||
if idx > 0 {
|
||||
@ -799,7 +797,6 @@ pub mod clangify {
|
||||
fn print(&self, y: &mut CLangifier) {
|
||||
match self {
|
||||
TyKind::Never => y.p("Never"),
|
||||
TyKind::Empty => y.p("Empty"),
|
||||
TyKind::Infer => y.p("auto"),
|
||||
TyKind::Path(t) => y.p(t),
|
||||
TyKind::Tuple(t) => y.p(t),
|
||||
@ -880,7 +877,6 @@ pub mod clangify {
|
||||
// TODO: function pointer syntax
|
||||
y.nest("(").p(rety).p(" *)(");
|
||||
match &args.kind {
|
||||
TyKind::Empty => y,
|
||||
TyKind::Tuple(TyTuple { types }) => {
|
||||
for (idx, ty) in types.iter().enumerate() {
|
||||
if idx > 0 {
|
||||
|
@ -649,7 +649,6 @@ pub mod yamlify {
|
||||
fn yaml(&self, y: &mut Yamler) {
|
||||
match self {
|
||||
TyKind::Never => y.value("Never"),
|
||||
TyKind::Empty => y.value("Empty"),
|
||||
TyKind::Infer => y.value("_"),
|
||||
TyKind::Path(t) => y.yaml(t),
|
||||
TyKind::Tuple(t) => y.yaml(t),
|
||||
@ -713,8 +712,7 @@ pub mod yamlify {
|
||||
impl Yamlify for TyPtr {
|
||||
fn yaml(&self, y: &mut Yamler) {
|
||||
let Self { to } = self;
|
||||
y.key("TyPtr")
|
||||
.pair("to", to);
|
||||
y.key("TyPtr").pair("to", to);
|
||||
}
|
||||
}
|
||||
impl Yamlify for TyFn {
|
||||
|
@ -205,4 +205,8 @@ impl<'t, 'a> EntryMut<'t, 'a> {
|
||||
pub fn mark_impl_item(&mut self) {
|
||||
self.table.mark_impl_item(self.id)
|
||||
}
|
||||
|
||||
pub fn mark_lang_item(&mut self, lang_item: &'static str) {
|
||||
self.table.mark_lang_item(lang_item, self.id)
|
||||
}
|
||||
}
|
||||
|
@ -55,8 +55,6 @@ impl fmt::Display for Entry<'_, '_> {
|
||||
write!(f, "fn {} -> ", self.with_id(*args))?;
|
||||
write_name_or(self.with_id(*rety), f)
|
||||
}
|
||||
TypeKind::Empty => write!(f, "()"),
|
||||
TypeKind::Never => write!(f, "!"),
|
||||
TypeKind::Module => write!(f, "module?"),
|
||||
}
|
||||
} else {
|
||||
|
@ -17,8 +17,6 @@ pub fn categorize(table: &mut Table, node: Handle) -> CatResult<()> {
|
||||
};
|
||||
|
||||
match source {
|
||||
Source::Alias(a) => cat_alias(table, node, a)?,
|
||||
Source::Enum(e) => cat_enum(table, node, e)?,
|
||||
Source::Variant(v) => cat_variant(table, node, v)?,
|
||||
Source::Struct(s) => cat_struct(table, node, s)?,
|
||||
Source::Const(c) => cat_const(table, node, c)?,
|
||||
@ -26,21 +24,8 @@ pub fn categorize(table: &mut Table, node: Handle) -> CatResult<()> {
|
||||
Source::Function(f) => cat_function(table, node, f)?,
|
||||
Source::Local(l) => cat_local(table, node, l)?,
|
||||
Source::Impl(i) => cat_impl(table, node, i)?,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let Some(meta) = table.meta(node) {
|
||||
for meta @ Meta { name, kind } in meta {
|
||||
if let ("lang", MetaKind::Equals(Literal::String(s))) = (&**name, kind) {
|
||||
if let Ok(prim) = s.parse() {
|
||||
table.set_ty(node, TypeKind::Primitive(prim));
|
||||
} else {
|
||||
table.mark_lang_item(s.into(), node);
|
||||
continue;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
// Source::Alias(_) => {table.mark_unchecked(node)},
|
||||
_ => return Ok(()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -49,20 +34,6 @@ fn parent(table: &Table, node: Handle) -> Handle {
|
||||
table.parent(node).copied().unwrap_or(node)
|
||||
}
|
||||
|
||||
fn cat_alias(table: &mut Table, node: Handle, a: &Alias) -> CatResult<()> {
|
||||
let parent = parent(table, node);
|
||||
let kind = match &a.from {
|
||||
Some(ty) => TypeKind::Instance(
|
||||
ty.evaluate(table, parent)
|
||||
.map_err(|e| Error::TypeEval(e, " while categorizing an alias"))?,
|
||||
),
|
||||
None => TypeKind::Empty,
|
||||
};
|
||||
table.set_ty(node, kind);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cat_struct(table: &mut Table, node: Handle, s: &Struct) -> CatResult<()> {
|
||||
let Struct { name: _, gens: _, kind } = s;
|
||||
// TODO: Generics
|
||||
@ -99,7 +70,6 @@ fn cat_member(
|
||||
|
||||
fn cat_enum<'a>(_table: &mut Table<'a>, _node: Handle, e: &'a Enum) -> CatResult<()> {
|
||||
let Enum { name: _, gens: _, variants: _ } = e;
|
||||
|
||||
// table.set_ty(node, kind);
|
||||
Ok(())
|
||||
}
|
||||
@ -107,17 +77,10 @@ fn cat_enum<'a>(_table: &mut Table<'a>, _node: Handle, e: &'a Enum) -> CatResult
|
||||
fn cat_variant<'a>(table: &mut Table<'a>, node: Handle, v: &'a Variant) -> CatResult<()> {
|
||||
let Variant { name, kind, body } = v;
|
||||
let parent = table.parent(node).copied().unwrap_or(table.root());
|
||||
match (kind, body) {
|
||||
(StructKind::Empty, None) => {
|
||||
table.set_ty(node, TypeKind::Adt(Adt::UnitStruct));
|
||||
Ok(())
|
||||
}
|
||||
(StructKind::Empty, Some(c)) => {
|
||||
table.set_body(node, c);
|
||||
table.set_ty(node, TypeKind::Adt(Adt::UnitStruct));
|
||||
Ok(())
|
||||
}
|
||||
(StructKind::Tuple(ty), None) => {
|
||||
match (kind) {
|
||||
(StructKind::Empty) => Ok(()),
|
||||
(StructKind::Empty) => Ok(()),
|
||||
(StructKind::Tuple(ty)) => {
|
||||
let ty = TypeKind::Adt(Adt::TupleStruct(
|
||||
ty.iter()
|
||||
.map(|ty| ty.evaluate(table, node).map(|ty| (Visibility::Public, ty)))
|
||||
@ -126,7 +89,7 @@ fn cat_variant<'a>(table: &mut Table<'a>, node: Handle, v: &'a Variant) -> CatRe
|
||||
table.set_ty(node, ty);
|
||||
Ok(())
|
||||
}
|
||||
(StructKind::Struct(members), None) => {
|
||||
(StructKind::Struct(members)) => {
|
||||
let mut out = vec![];
|
||||
for StructMember { vis, name, ty } in members {
|
||||
let ty = ty.evaluate(table, node)?;
|
||||
@ -144,9 +107,6 @@ fn cat_variant<'a>(table: &mut Table<'a>, node: Handle, v: &'a Variant) -> CatRe
|
||||
table.set_ty(node, TypeKind::Adt(Adt::Struct(out)));
|
||||
Ok(())
|
||||
}
|
||||
(_, Some(body)) => {
|
||||
panic!("Unexpected body `{body}` in enum variant `{v}`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
||||
Source::Module(v) => v.infer(&mut eng),
|
||||
Source::Alias(v) => v.infer(&mut eng),
|
||||
Source::Enum(v) => v.infer(&mut eng),
|
||||
Source::Variant(v) => v.infer(&mut eng),
|
||||
// Source::Variant(v) => v.infer(&mut eng),
|
||||
Source::Struct(v) => v.infer(&mut eng),
|
||||
Source::Const(v) => v.infer(&mut eng),
|
||||
Source::Static(v) => v.infer(&mut eng),
|
||||
@ -221,42 +221,37 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
||||
}
|
||||
|
||||
/// All primitives must be predefined in the standard library.
|
||||
pub fn primitive(&self, name: Sym) -> Option<Handle> {
|
||||
pub fn primitive(&self, name: &'static str) -> Handle {
|
||||
// TODO: keep a map of primitives in the table root
|
||||
self.table.get_by_sym(self.table.root(), &name)
|
||||
self.table.get_lang_item(name)
|
||||
}
|
||||
|
||||
pub fn never(&mut self) -> Handle {
|
||||
self.table.anon_type(TypeKind::Never)
|
||||
self.table.get_lang_item("never")
|
||||
}
|
||||
|
||||
pub fn empty(&mut self) -> Handle {
|
||||
self.table.anon_type(TypeKind::Empty)
|
||||
self.table.anon_type(TypeKind::Tuple(vec![]))
|
||||
}
|
||||
|
||||
pub fn bool(&self) -> Handle {
|
||||
self.primitive("bool".into())
|
||||
.expect("There should be a type named bool.")
|
||||
self.primitive("bool")
|
||||
}
|
||||
|
||||
pub fn char(&self) -> Handle {
|
||||
self.primitive("char".into())
|
||||
.expect("There should be a type named char.")
|
||||
self.primitive("char")
|
||||
}
|
||||
|
||||
pub fn str(&self) -> Handle {
|
||||
self.primitive("str".into())
|
||||
.expect("There should be a type named str.")
|
||||
self.primitive("str")
|
||||
}
|
||||
|
||||
pub fn u32(&self) -> Handle {
|
||||
self.primitive("u32".into())
|
||||
.expect("There should be a type named u32.")
|
||||
self.primitive("u32")
|
||||
}
|
||||
|
||||
pub fn usize(&self) -> Handle {
|
||||
self.primitive("usize".into())
|
||||
.expect("There should be a type named usize.")
|
||||
self.primitive("usize")
|
||||
}
|
||||
|
||||
/// Creates a new inferred-integer literal
|
||||
@ -344,7 +339,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
||||
&TypeKind::FnSig { args, rety } => {
|
||||
is_generic_rec(this, args, seen) || is_generic_rec(this, rety, seen)
|
||||
}
|
||||
TypeKind::Empty | TypeKind::Never | TypeKind::Module => false,
|
||||
TypeKind::Module => false,
|
||||
}
|
||||
}
|
||||
is_generic_rec(self, ty, &mut HashSet::new())
|
||||
@ -358,12 +353,12 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
||||
return ty;
|
||||
};
|
||||
let entry = self.table.entry(ty);
|
||||
let Some(ty) = entry.ty().cloned() else {
|
||||
let Some(tykind) = entry.ty().cloned() else {
|
||||
return ty;
|
||||
};
|
||||
|
||||
// TODO: Parent the deep clone into a new "monomorphs" branch of tree
|
||||
match ty {
|
||||
match tykind {
|
||||
TypeKind::Variable => self.new_inferred(),
|
||||
TypeKind::Array(h, s) => {
|
||||
let ty = self.deep_clone(h);
|
||||
@ -405,6 +400,10 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
||||
let ty = self.deep_clone(h);
|
||||
self.table.anon_type(TypeKind::Ref(ty))
|
||||
}
|
||||
TypeKind::Ptr(handle) => {
|
||||
let ty = self.deep_clone(handle);
|
||||
self.table.anon_type(TypeKind::Ptr(ty))
|
||||
}
|
||||
TypeKind::Slice(h) => {
|
||||
let ty = self.deep_clone(h);
|
||||
self.table.anon_type(TypeKind::Slice(ty))
|
||||
@ -418,7 +417,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
||||
let rety = self.deep_clone(rety);
|
||||
self.table.anon_type(TypeKind::FnSig { args, rety })
|
||||
}
|
||||
_ => self.table.anon_type(ty),
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,8 +471,6 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
||||
| TypeKind::Variable
|
||||
| TypeKind::Adt(Adt::UnitStruct)
|
||||
| TypeKind::Primitive(_)
|
||||
| TypeKind::Empty
|
||||
| TypeKind::Never
|
||||
| TypeKind::Module => false,
|
||||
}
|
||||
}
|
||||
@ -490,6 +487,10 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
||||
};
|
||||
|
||||
match (a, b) {
|
||||
(TypeKind::Variable, TypeKind::Variable) => {
|
||||
self.set_instance(ah, bh);
|
||||
Ok(())
|
||||
}
|
||||
(TypeKind::Inferred, _) => {
|
||||
self.set_instance(ah, bh);
|
||||
Ok(())
|
||||
@ -602,12 +603,8 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
||||
self.unify(a1, a2)?;
|
||||
self.unify(r1, r2)
|
||||
}
|
||||
(TypeKind::Empty, TypeKind::Tuple(t)) | (TypeKind::Tuple(t), TypeKind::Empty)
|
||||
if t.is_empty() =>
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
(TypeKind::Never, _) | (_, TypeKind::Never) => Ok(()),
|
||||
(TypeKind::Primitive(Primitive::Never), _)
|
||||
| (_, TypeKind::Primitive(Primitive::Never)) => Ok(()),
|
||||
(a, b) if a == b => Ok(()),
|
||||
_ => Err(InferenceError::Mismatch(ah, bh)),
|
||||
}
|
||||
|
@ -78,16 +78,31 @@ impl<'a> Inference<'a> for Module {
|
||||
|
||||
impl<'a> Inference<'a> for Alias {
|
||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||
Ok(e.empty())
|
||||
let Self { name: _, from } = self;
|
||||
// let this = e.by_name(name)?;
|
||||
let alias = if let Some(from) = from {
|
||||
TypeKind::Instance(e.infer(from)?)
|
||||
} else {
|
||||
TypeKind::Tuple(vec![])
|
||||
};
|
||||
|
||||
// This node may be a lang item referring to a primitive.
|
||||
let mut entry = e.at.to_entry_mut(e.table);
|
||||
if entry.ty().is_some() {
|
||||
return Ok(e.empty());
|
||||
}
|
||||
entry.set_ty(alias);
|
||||
|
||||
Ok(entry.id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Inference<'a> for Const {
|
||||
#[allow(unused)]
|
||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||
let Self { name, ty, init } = self;
|
||||
let Self { name: _, ty, init } = self;
|
||||
// Same as static
|
||||
let node = e.by_name(name)?;
|
||||
let node = e.at; //.by_name(name)?;
|
||||
let ty = e.infer(ty)?;
|
||||
let mut scope = e.at(node);
|
||||
// infer body
|
||||
@ -103,7 +118,7 @@ impl<'a> Inference<'a> for Static {
|
||||
#[allow(unused)]
|
||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||
let Static { mutable, name, ty, init } = self;
|
||||
let node = e.by_name(name)?;
|
||||
let node = e.at; //e.by_name(name)?;
|
||||
let ty = e.infer(ty)?;
|
||||
let mut scope = e.at(node);
|
||||
// infer body
|
||||
@ -120,7 +135,7 @@ impl<'a> Inference<'a> for Function {
|
||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||
let Self { name, gens, sign, bind, body } = self;
|
||||
// bind name to signature
|
||||
let node = e.by_name(name)?;
|
||||
let node = e.at; // e.by_name(name)?;
|
||||
let node = e.deep_clone(node);
|
||||
let fnty = e.by_name(sign)?;
|
||||
e.unify(node, fnty)?;
|
||||
@ -154,14 +169,15 @@ impl<'a> Inference<'a> for Function {
|
||||
|
||||
impl<'a> Inference<'a> for Enum {
|
||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||
let Self { name, gens, variants } = self;
|
||||
let node = e.by_name(name)?;
|
||||
let Self { name: _, gens, variants } = self;
|
||||
let node = e.at; //e.by_name(name)?;
|
||||
let mut scope = e.at(node);
|
||||
|
||||
scope.infer(gens)?;
|
||||
for variant in variants {
|
||||
println!("Inferring {variant}");
|
||||
let var_ty = scope.infer(variant)?;
|
||||
scope.unify(var_ty, node)?;
|
||||
scope.unify(node, var_ty)?;
|
||||
}
|
||||
Ok(node)
|
||||
}
|
||||
@ -169,31 +185,46 @@ impl<'a> Inference<'a> for Enum {
|
||||
|
||||
impl<'a> Inference<'a> for Variant {
|
||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||
let Self { name: _, kind: _, body } = self;
|
||||
let ty = e.new_inferred();
|
||||
let Self { name, kind: _, body } = self;
|
||||
let node = e.by_name(name)?;
|
||||
|
||||
// TODO: evaluate kind
|
||||
|
||||
if let Some(body) = body {
|
||||
let value = body.infer(e)?;
|
||||
e.unify(ty, value)?;
|
||||
// TODO: this doesn't work when some variants have bodies and some don't
|
||||
if e.table.ty(node).is_some() {
|
||||
println!("{node} has ty!");
|
||||
return Ok(node);
|
||||
}
|
||||
|
||||
Ok(ty)
|
||||
match body {
|
||||
Some(body) => {
|
||||
let mut e = e.at(node);
|
||||
let value = e.infer(body)?;
|
||||
e.unify(node, value)?;
|
||||
}
|
||||
_ => {
|
||||
e.table.entry_mut(node).set_ty(TypeKind::Inferred);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Inference<'a> for Struct {
|
||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||
Ok(e.new_inferred())
|
||||
let Self { name, gens, kind: _ } = self;
|
||||
let node = e.by_name(name)?;
|
||||
let mut e = e.at(node);
|
||||
e.infer(gens)?;
|
||||
|
||||
Ok(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Inference<'a> for Impl {
|
||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||
let Self { gens: _, target, body } = self;
|
||||
let Self { gens, target, body } = self;
|
||||
// TODO: match gens to target gens
|
||||
// gens.infer(e)?;
|
||||
gens.infer(e)?;
|
||||
let instance = target.infer(e)?;
|
||||
let instance = e.def_usage(instance);
|
||||
let mut scope = e.at(instance);
|
||||
@ -527,8 +558,9 @@ impl<'a> Inference<'a> for Binary {
|
||||
e.unify(tail, bool)?;
|
||||
Ok(bool)
|
||||
}
|
||||
Bk::RangeExc => todo!("Ranges in the type checker"),
|
||||
Bk::RangeInc => todo!("Ranges in the type checker"),
|
||||
// TODO: Don't return the generic form wholesale.
|
||||
Bk::RangeExc => Ok(e.table.get_lang_item("range_exc")),
|
||||
Bk::RangeInc => Ok(e.table.get_lang_item("range_exc")),
|
||||
Bk::Shl | Bk::Shr => {
|
||||
let shift_amount = e.u32();
|
||||
e.unify(tail, shift_amount)?;
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
type_kind::TypeKind,
|
||||
};
|
||||
use cl_ast::{
|
||||
ItemKind, Sym,
|
||||
ItemKind, Literal, Meta, MetaKind, Sym,
|
||||
ast_visitor::{Visit, Walk},
|
||||
};
|
||||
|
||||
@ -57,6 +57,15 @@ impl<'a> Visit<'a> for Populator<'_, 'a> {
|
||||
entry.inner.set_span(*span);
|
||||
entry.inner.set_meta(&attrs.meta);
|
||||
|
||||
for Meta { name, kind } in &attrs.meta {
|
||||
if let ("lang", MetaKind::Equals(Literal::String(s))) = (name.to_ref(), kind) {
|
||||
if let Ok(prim) = s.parse() {
|
||||
entry.inner.set_ty(TypeKind::Primitive(prim));
|
||||
}
|
||||
entry.inner.mark_lang_item(Sym::from(s).to_ref());
|
||||
}
|
||||
}
|
||||
|
||||
entry.visit_children(i);
|
||||
|
||||
if let (Some(name), child) = (entry.name, entry.inner.id()) {
|
||||
@ -158,8 +167,16 @@ impl<'a> Visit<'a> for Populator<'_, 'a> {
|
||||
self.inner.set_source(Source::Variant(value));
|
||||
self.set_name(*name);
|
||||
self.visit(kind);
|
||||
if let Some(body) = body {
|
||||
self.inner.set_body(body);
|
||||
match (kind, body) {
|
||||
(cl_ast::StructKind::Empty, None) => {
|
||||
self.inner.set_ty(TypeKind::Inferred);
|
||||
}
|
||||
(cl_ast::StructKind::Empty, Some(body)) => {
|
||||
self.inner.set_body(body);
|
||||
}
|
||||
(cl_ast::StructKind::Tuple(_items), None) => {}
|
||||
(cl_ast::StructKind::Struct(_struct_members), None) => {}
|
||||
(_, Some(body)) => panic!("Unexpected body {body} in enum variant `{value}`"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ pub struct Table<'a> {
|
||||
sources: HashMap<Handle, Source<'a>>,
|
||||
impl_targets: HashMap<Handle, Handle>,
|
||||
anon_types: HashMap<TypeKind, Handle>,
|
||||
lang_items: HashMap<Sym, Handle>,
|
||||
lang_items: HashMap<&'static str, Handle>,
|
||||
|
||||
// --- Queues for algorithms ---
|
||||
pub(crate) unchecked: Vec<Handle>,
|
||||
@ -129,10 +129,17 @@ impl<'a> Table<'a> {
|
||||
self.impls.push(item);
|
||||
}
|
||||
|
||||
pub fn mark_lang_item(&mut self, name: Sym, item: Handle) {
|
||||
pub fn mark_lang_item(&mut self, name: &'static str, item: Handle) {
|
||||
self.lang_items.insert(name, item);
|
||||
}
|
||||
|
||||
pub fn get_lang_item(&self, name: &str) -> Handle {
|
||||
match self.lang_items.get(name).copied() {
|
||||
Some(handle) => handle,
|
||||
None => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_iter(&self) -> impl Iterator<Item = Handle> + use<> {
|
||||
self.kinds.keys()
|
||||
}
|
||||
|
@ -40,8 +40,7 @@ impl TypeExpression for Ty {
|
||||
impl TypeExpression for TyKind {
|
||||
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
|
||||
match self {
|
||||
TyKind::Never => Ok(table.anon_type(TypeKind::Never)),
|
||||
TyKind::Empty => Ok(table.anon_type(TypeKind::Empty)),
|
||||
TyKind::Never => Ok(table.get_lang_item("never")),
|
||||
TyKind::Infer => Ok(table.inferred_type()),
|
||||
TyKind::Path(p) => p.evaluate(table, node),
|
||||
TyKind::Array(a) => a.evaluate(table, node),
|
||||
@ -97,10 +96,7 @@ impl TypeExpression for TySlice {
|
||||
impl TypeExpression for TyTuple {
|
||||
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
|
||||
let Self { types } = self;
|
||||
let kind = match types.len() {
|
||||
0 => TypeKind::Empty,
|
||||
_ => TypeKind::Tuple(types.evaluate(table, node)?),
|
||||
};
|
||||
let kind = TypeKind::Tuple(types.evaluate(table, node)?);
|
||||
Ok(table.anon_type(kind))
|
||||
}
|
||||
}
|
||||
|
@ -32,10 +32,6 @@ pub enum TypeKind {
|
||||
Tuple(Vec<Handle>),
|
||||
/// A function which accepts multiple inputs and produces an output
|
||||
FnSig { args: Handle, rety: Handle },
|
||||
/// The unit type
|
||||
Empty,
|
||||
/// The never type
|
||||
Never,
|
||||
/// An untyped module
|
||||
Module,
|
||||
}
|
||||
@ -70,6 +66,7 @@ pub enum Primitive {
|
||||
Bool, // boolean value
|
||||
Char, // Unicode codepoint
|
||||
Str, // UTF-8 string
|
||||
Never, // The never type
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
@ -121,6 +118,7 @@ impl FromStr for Primitive {
|
||||
"bool" => Primitive::Bool,
|
||||
"char" => Primitive::Char,
|
||||
"str" => Primitive::Str,
|
||||
"never" => Primitive::Never,
|
||||
_ => Err(())?,
|
||||
})
|
||||
}
|
||||
|
@ -25,8 +25,6 @@ impl Display for TypeKind {
|
||||
})(f.delimit_with("tuple (", ")"))
|
||||
}
|
||||
TypeKind::FnSig { args, rety } => write!(f, "fn (#{args}) -> #{rety}"),
|
||||
TypeKind::Empty => f.write_str("()"),
|
||||
TypeKind::Never => f.write_str("!"),
|
||||
TypeKind::Module => f.write_str("mod"),
|
||||
}
|
||||
}
|
||||
@ -94,6 +92,7 @@ impl Display for Primitive {
|
||||
Primitive::Bool => f.write_str("bool"),
|
||||
Primitive::Char => f.write_str("char"),
|
||||
Primitive::Str => f.write_str("str"),
|
||||
Primitive::Never => f.write_str("!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
//! Implements format string evaluation in weak Conlang
|
||||
|
||||
fn f(__fmt: str) -> str {
|
||||
|
||||
/// Formats a string
|
||||
fn f(__fmt: &str) -> &str {
|
||||
let __out = "";
|
||||
let __expr = "";
|
||||
let __label = "";
|
||||
|
@ -4,13 +4,11 @@
|
||||
// These two functions shouldn't actually be polymorphic, but
|
||||
// the AST interpreter doesn't know about type annotations
|
||||
// or operator overloading.
|
||||
#[generic("T")]
|
||||
pub fn max(a: T, b: T) -> T {
|
||||
pub fn max<T>(a: T, b: T) -> T {
|
||||
(if a < b { b } else { a })
|
||||
}
|
||||
|
||||
#[generic("T")]
|
||||
pub fn min(a: T, b: T) -> T {
|
||||
pub fn min<T>(a: T, b: T) -> T {
|
||||
(if a > b { b } else { a })
|
||||
}
|
||||
|
||||
|
@ -13,11 +13,11 @@ pub fn lfsr_next() {
|
||||
}
|
||||
|
||||
/// Returns a pseudorandom byte
|
||||
pub fn rand() -> u8 {
|
||||
pub fn rand() -> u64 {
|
||||
for _ in 0..8 {
|
||||
lfsr_next()
|
||||
}
|
||||
state & 0xff
|
||||
};
|
||||
(state & 0xff) as u64
|
||||
}
|
||||
|
||||
// Prints a maze out of diagonal box drawing characters, ['╲', '╱']
|
||||
|
@ -25,5 +25,7 @@ pub mod result;
|
||||
|
||||
pub mod range;
|
||||
|
||||
pub mod never;
|
||||
|
||||
// #[cfg("test")]
|
||||
// mod test;
|
||||
|
4
stdlib/std/never.cl
Normal file
4
stdlib/std/never.cl
Normal file
@ -0,0 +1,4 @@
|
||||
//! Never: the return type of an infinite loop
|
||||
|
||||
#[lang = "never"]
|
||||
type Never = !;
|
@ -1,6 +1,7 @@
|
||||
//! The optional type, representing the presence or absence of a thing.
|
||||
use super::preamble::*;
|
||||
|
||||
#[lang = "option"]
|
||||
pub enum Option<T> {
|
||||
Some(T),
|
||||
None,
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! The Result type, indicating a fallible operation.
|
||||
use super::preamble::*;
|
||||
|
||||
#[lang = "result"]
|
||||
pub enum Result<T, E> {
|
||||
Ok(T),
|
||||
Err(E),
|
||||
|
Loading…
x
Reference in New Issue
Block a user