diff --git a/compiler/cl-ast/src/ast.rs b/compiler/cl-ast/src/ast.rs index 99af47d..c79d408 100644 --- a/compiler/cl-ast/src/ast.rs +++ b/compiler/cl-ast/src/ast.rs @@ -224,7 +224,6 @@ pub struct Ty { #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum TyKind { Never, - Empty, Infer, Path(Path), Array(TyArray), diff --git a/compiler/cl-ast/src/ast_impl/display.rs b/compiler/cl-ast/src/ast_impl/display.rs index 32987cc..53c84f9 100644 --- a/compiler/cl-ast/src/ast_impl/display.rs +++ b/compiler/cl-ast/src/ast_impl/display.rs @@ -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(()) } diff --git a/compiler/cl-ast/src/ast_impl/weight_of.rs b/compiler/cl-ast/src/ast_impl/weight_of.rs index acd2ada..ee43654 100644 --- a/compiler/cl-ast/src/ast_impl/weight_of.rs +++ b/compiler/cl-ast/src/ast_impl/weight_of.rs @@ -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(), diff --git a/compiler/cl-ast/src/ast_visitor/fold.rs b/compiler/cl-ast/src/ast_visitor/fold.rs index 09b03f5..5540066 100644 --- a/compiler/cl-ast/src/ast_visitor/fold.rs +++ b/compiler/cl-ast/src/ast_visitor/fold.rs @@ -531,7 +531,6 @@ pub fn or_fold_use_tree(folder: &mut F, tree: UseTree) -> UseT pub fn or_fold_ty_kind(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)), diff --git a/compiler/cl-ast/src/ast_visitor/walk.rs b/compiler/cl-ast/src/ast_visitor/walk.rs index 25b6c1c..03175d0 100644 --- a/compiler/cl-ast/src/ast_visitor/walk.rs +++ b/compiler/cl-ast/src/ast_visitor/walk.rs @@ -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), diff --git a/compiler/cl-interpret/src/interpret.rs b/compiler/cl-interpret/src/interpret.rs index 9003dc7..c296a91 100644 --- a/compiler/cl-interpret/src/interpret.rs +++ b/compiler/cl-interpret/src/interpret.rs @@ -723,9 +723,12 @@ impl Interpret for Cast { fn interpret(&self, env: &mut Environment) -> IResult { 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())? }; diff --git a/compiler/cl-parser/src/parser.rs b/compiler/cl-parser/src/parser.rs index fd7fa63..1495d88 100644 --- a/compiler/cl-parser/src/parser.rs +++ b/compiler/cl-parser/src/parser.rs @@ -464,13 +464,18 @@ impl Parse<'_> for Function { let gens = Generics::parse(p)?; let ((bind, types), span) = delim(Spanned::::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![] }, + }, }), }) } diff --git a/compiler/cl-repl/examples/to_c.rs b/compiler/cl-repl/examples/to_c.rs index 736383c..5f9bb48 100644 --- a/compiler/cl-repl/examples/to_c.rs +++ b/compiler/cl-repl/examples/to_c.rs @@ -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 { diff --git a/compiler/cl-repl/examples/yaml.rs b/compiler/cl-repl/examples/yaml.rs index a80fa65..83caef0 100644 --- a/compiler/cl-repl/examples/yaml.rs +++ b/compiler/cl-repl/examples/yaml.rs @@ -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 { diff --git a/compiler/cl-typeck/src/entry.rs b/compiler/cl-typeck/src/entry.rs index 658188a..1158dc5 100644 --- a/compiler/cl-typeck/src/entry.rs +++ b/compiler/cl-typeck/src/entry.rs @@ -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) + } } diff --git a/compiler/cl-typeck/src/entry/display.rs b/compiler/cl-typeck/src/entry/display.rs index 7915f0e..c85fec5 100644 --- a/compiler/cl-typeck/src/entry/display.rs +++ b/compiler/cl-typeck/src/entry/display.rs @@ -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 { diff --git a/compiler/cl-typeck/src/stage/categorize.rs b/compiler/cl-typeck/src/stage/categorize.rs index 866a906..8e13994 100644 --- a/compiler/cl-typeck/src/stage/categorize.rs +++ b/compiler/cl-typeck/src/stage/categorize.rs @@ -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}`") - } } } diff --git a/compiler/cl-typeck/src/stage/infer/engine.rs b/compiler/cl-typeck/src/stage/infer/engine.rs index cdf7257..e0a15bc 100644 --- a/compiler/cl-typeck/src/stage/infer/engine.rs +++ b/compiler/cl-typeck/src/stage/infer/engine.rs @@ -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 { + 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)), } diff --git a/compiler/cl-typeck/src/stage/infer/inference.rs b/compiler/cl-typeck/src/stage/infer/inference.rs index 10be487..fa59420 100644 --- a/compiler/cl-typeck/src/stage/infer/inference.rs +++ b/compiler/cl-typeck/src/stage/infer/inference.rs @@ -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)?; diff --git a/compiler/cl-typeck/src/stage/populate.rs b/compiler/cl-typeck/src/stage/populate.rs index ed06674..a7068e1 100644 --- a/compiler/cl-typeck/src/stage/populate.rs +++ b/compiler/cl-typeck/src/stage/populate.rs @@ -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}`"), } } diff --git a/compiler/cl-typeck/src/table.rs b/compiler/cl-typeck/src/table.rs index 707d676..366ce66 100644 --- a/compiler/cl-typeck/src/table.rs +++ b/compiler/cl-typeck/src/table.rs @@ -57,7 +57,7 @@ pub struct Table<'a> { sources: HashMap>, impl_targets: HashMap, anon_types: HashMap, - lang_items: HashMap, + lang_items: HashMap<&'static str, Handle>, // --- Queues for algorithms --- pub(crate) unchecked: Vec, @@ -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 + use<> { self.kinds.keys() } diff --git a/compiler/cl-typeck/src/type_expression.rs b/compiler/cl-typeck/src/type_expression.rs index fefb533..e4b8d1c 100644 --- a/compiler/cl-typeck/src/type_expression.rs +++ b/compiler/cl-typeck/src/type_expression.rs @@ -40,8 +40,7 @@ impl TypeExpression for Ty { impl TypeExpression for TyKind { fn evaluate(&self, table: &mut Table, node: Handle) -> Result { 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 { 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)) } } diff --git a/compiler/cl-typeck/src/type_kind.rs b/compiler/cl-typeck/src/type_kind.rs index 3d59dd2..658891f 100644 --- a/compiler/cl-typeck/src/type_kind.rs +++ b/compiler/cl-typeck/src/type_kind.rs @@ -32,10 +32,6 @@ pub enum TypeKind { Tuple(Vec), /// 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(())?, }) } diff --git a/compiler/cl-typeck/src/type_kind/display.rs b/compiler/cl-typeck/src/type_kind/display.rs index dc1a6d0..884fa45 100644 --- a/compiler/cl-typeck/src/type_kind/display.rs +++ b/compiler/cl-typeck/src/type_kind/display.rs @@ -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("!"), } } } diff --git a/sample-code/fstring.cl b/sample-code/fstring.cl index f820b8b..a2dc5b5 100644 --- a/sample-code/fstring.cl +++ b/sample-code/fstring.cl @@ -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 = ""; diff --git a/sample-code/math.cl b/sample-code/math.cl index 0a750a9..c0e71fa 100644 --- a/sample-code/math.cl +++ b/sample-code/math.cl @@ -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(a: T, b: T) -> T { (if a < b { b } else { a }) } -#[generic("T")] -pub fn min(a: T, b: T) -> T { +pub fn min(a: T, b: T) -> T { (if a > b { b } else { a }) } diff --git a/sample-code/rand.cl b/sample-code/rand.cl index 4915e5b..a55ecb0 100644 --- a/sample-code/rand.cl +++ b/sample-code/rand.cl @@ -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, ['╲', '╱'] diff --git a/stdlib/std.cl b/stdlib/std.cl index 111c2e0..b214037 100644 --- a/stdlib/std.cl +++ b/stdlib/std.cl @@ -25,5 +25,7 @@ pub mod result; pub mod range; +pub mod never; + // #[cfg("test")] // mod test; diff --git a/stdlib/std/never.cl b/stdlib/std/never.cl new file mode 100644 index 0000000..9f02bc3 --- /dev/null +++ b/stdlib/std/never.cl @@ -0,0 +1,4 @@ +//! Never: the return type of an infinite loop + +#[lang = "never"] +type Never = !; diff --git a/stdlib/std/option.cl b/stdlib/std/option.cl index bb976c2..e5258fc 100644 --- a/stdlib/std/option.cl +++ b/stdlib/std/option.cl @@ -1,6 +1,7 @@ //! The optional type, representing the presence or absence of a thing. use super::preamble::*; +#[lang = "option"] pub enum Option { Some(T), None, diff --git a/stdlib/std/result.cl b/stdlib/std/result.cl index f5862ae..2345eae 100644 --- a/stdlib/std/result.cl +++ b/stdlib/std/result.cl @@ -1,6 +1,7 @@ //! The Result type, indicating a fallible operation. use super::preamble::*; +#[lang = "result"] pub enum Result { Ok(T), Err(E),