Skip to content

Commit

Permalink
Started working on support for user-defined traits
Browse files Browse the repository at this point in the history
  • Loading branch information
IsaacShelton committed Dec 15, 2024
1 parent 581f371 commit 943ec77
Show file tree
Hide file tree
Showing 16 changed files with 177 additions and 22 deletions.
4 changes: 4 additions & 0 deletions src/lower/datatype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ pub fn lower_type(
match &resolved_type.kind {
resolved::TypeKind::Unresolved => panic!("got unresolved type during lower_type!"),
resolved::TypeKind::Polymorph(_, _) => todo!("cannot directly lower polymorph"),
resolved::TypeKind::Trait(name, _) => Err(LowerErrorKind::CannotUseTraitDirectly {
name: name.to_string(),
}
.at(resolved_type.source)),
resolved::TypeKind::Boolean => Ok(ir::Type::Boolean),
resolved::TypeKind::Integer(bits, sign) => Ok(match (bits, sign) {
(Bits::Bits8, Sign::Signed) => ir::Type::S8,
Expand Down
6 changes: 6 additions & 0 deletions src/lower/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ pub enum LowerErrorKind {
},
PolymorphError(PolymorphErrorKind),
IncorrectNumberOfTypeArguments,
CannotUseTraitDirectly {
name: String,
},
}

impl From<PolymorphError> for LowerError {
Expand Down Expand Up @@ -106,6 +109,9 @@ impl Display for LowerErrorKind {
write!(f, "Incorrect number of type arguments")
}
LowerErrorKind::PolymorphError(e) => e.fmt(f),
LowerErrorKind::CannotUseTraitDirectly { name } => {
write!(f, "Cannot use trait '{}' directly", name)
}
}
}
}
8 changes: 8 additions & 0 deletions src/resolve/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ pub enum ResolveErrorKind {
ConstraintsNotSatisfiedForType {
name: String,
},
TypeIsNotATrait {
name: String,
},
Other {
message: String,
},
Expand Down Expand Up @@ -537,6 +540,11 @@ impl Display for ResolveErrorKind {
ResolveErrorKind::ConstraintsNotSatisfiedForType { name } => {
write!(f, "Constraints not satisfied for type '{}'", name)?;
}
ResolveErrorKind::TypeIsNotATrait {
name
} => {
write!(f, "Type '{}' is not a trait", name)?;
}
ResolveErrorKind::Other { message } => {
write!(f, "{}", message)?;
}
Expand Down
1 change: 1 addition & 0 deletions src/resolve/function_head.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ pub fn collect_constraints(map: &mut HashMap<String, HashSet<Constraint>>, ty: &
set.insert(constraint.clone());
}
}
resolved::TypeKind::Trait(_, _) => (),
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/resolve/job.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
resolved::{self, EnumRef, StructureRef, TypeAliasRef},
resolved::{self, EnumRef, StructureRef, TraitRef, TypeAliasRef},
workspace::fs::FsNodeId,
};

Expand All @@ -12,6 +12,7 @@ pub enum FuncJob {
pub struct TypeJob {
pub physical_file_id: FsNodeId,
pub type_aliases: Vec<TypeAliasRef>,
pub traits: Vec<TraitRef>,
pub structures: Vec<StructureRef>,
pub enums: Vec<EnumRef>,
}
4 changes: 3 additions & 1 deletion src/resolve/polymorph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ impl PolyRecipe {

poly_type.resolved_type.clone()
}
resolved::TypeKind::Trait(_, _) => ty.clone(),
})
}
}
Expand Down Expand Up @@ -189,7 +190,8 @@ impl PolyCatalog {
| resolved::TypeKind::Floating(_)
| resolved::TypeKind::Void
| resolved::TypeKind::Enum(_, _)
| resolved::TypeKind::TypeAlias(_, _) => {
| resolved::TypeKind::TypeAlias(_, _)
| resolved::TypeKind::Trait(_, _) => {
if *pattern_type == *concrete_type {
Ok(())
} else {
Expand Down
50 changes: 39 additions & 11 deletions src/resolve/type_ctx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,49 @@ impl<'a, 'b, 'c> From<&'c ResolveExprCtx<'a, 'b>> for ResolveTypeCtx<'c> {
}
}

pub fn resolve_constraints(constraints: &[ast::Type]) -> Result<Vec<Constraint>, ResolveError> {
pub fn resolve_constraints(
type_ctx: &ResolveTypeCtx,
constraints: &[ast::Type],
) -> Result<Vec<Constraint>, ResolveError> {
let mut resolved_constraints = vec![];

for constraint in constraints {
if let ast::TypeKind::Named(name, arguments) = &constraint.kind {
resolved_constraints.push(match name.as_plain_str() {
Some("PrimitiveAdd") if arguments.is_empty() => Constraint::PrimitiveAdd,
_ => {
return Err(
ResolveErrorKind::UndeclaredTrait(name.to_string()).at(constraint.source)
)
}
});
}
resolved_constraints.push(resolve_constraint(type_ctx, constraint)?);
}

Ok(resolved_constraints)
}

pub fn resolve_constraint(
type_ctx: &ResolveTypeCtx,
constraint: &ast::Type,
) -> Result<Constraint, ResolveError> {
if let ast::TypeKind::Named(name, arguments) = &constraint.kind {
match name.as_plain_str() {
Some("PrimitiveAdd") if arguments.is_empty() => return Ok(Constraint::PrimitiveAdd),
_ => {
let resolved_type = type_ctx.resolve(constraint).map_err(|err| {
if let ResolveErrorKind::UndeclaredType { name } = err.kind {
ResolveErrorKind::UndeclaredTrait(name).at(err.source)
} else {
err
}
})?;

let resolved::TypeKind::Trait(_, trait_ref) = &resolved_type.kind else {
return Err(ResolveErrorKind::TypeIsNotATrait {
name: resolved_type.to_string(),
}
.at(resolved_type.source));
};

return Ok(Constraint::Trait(*trait_ref));
}
}
}

return Err(ResolveErrorKind::TypeIsNotATrait {
name: constraint.to_string(),
}
.at(constraint.source));
}
2 changes: 1 addition & 1 deletion src/resolve/type_ctx/resolve_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl<'a> ResolveTypeCtx<'a> {
}
ast::TypeKind::Polymorph(polymorph, constraints) => Ok(resolved::TypeKind::Polymorph(
polymorph.clone(),
resolve_constraints(constraints)?,
resolve_constraints(self, constraints)?,
)),
}
.map(|kind| kind.at(ast_type.source))
Expand Down
61 changes: 58 additions & 3 deletions src/resolve/type_definition/prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ use crate::{
ctx::ResolveCtx,
error::{ResolveError, ResolveErrorKind},
job::TypeJob,
type_ctx::resolve_constraints,
type_ctx::{resolve_constraints, ResolveTypeCtx},
},
resolved::{
self, CurrentConstraints, EnumRef, HumanName, StructureRef, TraitRef, TypeAliasRef,
TypeDecl, TypeParameters,
},
resolved::{self, EnumRef, HumanName, StructureRef, TypeAliasRef, TypeDecl, TypeParameters},
workspace::fs::FsNodeId,
};
use indexmap::IndexMap;
Expand All @@ -28,15 +31,26 @@ pub fn prepare_type_jobs(
let mut job = TypeJob {
physical_file_id: *physical_file_id,
type_aliases: Vec::with_capacity(file.type_aliases.len()),
traits: Vec::with_capacity(file.traits.len()),
structures: Vec::with_capacity(file.structures.len()),
enums: Vec::with_capacity(file.enums.len()),
};

for user_trait in file.traits.iter() {
job.traits.push(prepare_trait(
ctx,
resolved_ast,
module_fs_node_id,
user_trait,
));
}

for structure in file.structures.iter() {
job.structures.push(prepare_structure(
ctx,
resolved_ast,
module_fs_node_id,
*physical_file_id,
structure,
)?);
}
Expand Down Expand Up @@ -69,14 +83,25 @@ fn prepare_structure(
ctx: &mut ResolveCtx,
resolved_ast: &mut resolved::Ast,
module_fs_node_id: FsNodeId,
physical_fs_node_id: FsNodeId,
structure: &ast::Structure,
) -> Result<StructureRef, ResolveError> {
let source = structure.source;

let mut parameters = TypeParameters::default();

for (name, parameter) in structure.parameters.iter() {
let constraints = resolve_constraints(&parameter.constraints)?;
let zero_current_constraints = CurrentConstraints::default();
let constraints = resolve_constraints(
&ResolveTypeCtx::new(
resolved_ast,
module_fs_node_id,
physical_fs_node_id,
&ctx.types_in_modules,
&zero_current_constraints,
),
&parameter.constraints,
)?;

if parameters
.parameters
Expand Down Expand Up @@ -155,6 +180,36 @@ fn prepare_enum(
enum_ref
}

fn prepare_trait(
ctx: &mut ResolveCtx,
resolved_ast: &mut resolved::Ast,
module_fs_node_id: FsNodeId,
definition: &ast::Trait,
) -> TraitRef {
let trait_ref = resolved_ast.traits.insert(resolved::Trait {
methods: vec![],
source: definition.source,
});

let kind = resolved::TypeKind::Trait(HumanName(definition.name.to_string()), trait_ref);
let source = definition.source;
let privacy = definition.privacy;

ctx.types_in_modules
.entry(module_fs_node_id)
.or_default()
.insert(
definition.name.to_string(),
TypeDecl {
kind,
source,
privacy,
},
);

trait_ref
}

fn prepare_type_alias(
ctx: &mut ResolveCtx,
resolved_ast: &mut resolved::Ast,
Expand Down
23 changes: 21 additions & 2 deletions src/resolve/type_definition/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ pub fn resolve_type_jobs(
.get_owning_module(job.physical_file_id)
.unwrap_or(job.physical_file_id);

for (_trait_ref, _user_trait) in job.traits.iter().zip(file.traits.iter()) {
resolve_trait()?;
}

for (structure_ref, structure) in job.structures.iter().zip(file.structures.iter()) {
resolve_structure(
ctx,
Expand Down Expand Up @@ -76,12 +80,22 @@ fn resolve_structure(
structure_ref: StructureRef,
) -> Result<(), ResolveError> {
for (field_name, field) in structure.fields.iter() {
let mut constraints = HashMap::new();
let pre_constraints = CurrentConstraints::default();
let pre_type_ctx = ResolveTypeCtx::new(
&resolved_ast,
module_file_id,
physical_file_id,
&ctx.types_in_modules,
&pre_constraints,
);

let mut constraints = HashMap::new();
for (name, parameter) in structure.parameters.iter() {
constraints.insert(
name.into(),
HashSet::from_iter(resolve_constraints(&parameter.constraints)?.drain(..)),
HashSet::from_iter(
resolve_constraints(&pre_type_ctx, &parameter.constraints)?.drain(..),
),
);
}

Expand Down Expand Up @@ -165,3 +179,8 @@ fn resolve_type_alias(
*resolved_ast.type_aliases.get_mut(type_alias_ref).unwrap() = resolved_type;
Ok(())
}

fn resolve_trait() -> Result<(), ResolveError> {
eprintln!("warning: trait methods are not resolved yet");
Ok(())
}
3 changes: 3 additions & 0 deletions src/resolved/datatype/kind/constraint.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use crate::resolved::TraitRef;
use std::fmt::Display;

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Constraint {
PrimitiveAdd,
Trait(TraitRef),
}

impl Display for Constraint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Constraint::PrimitiveAdd => write!(f, "PrimitiveAdd"),
Constraint::Trait(_) => write!(f, "<user-defined trait>"),
}
}
}
10 changes: 8 additions & 2 deletions src/resolved/datatype/kind/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod function_pointer;
use super::Type;
use crate::{
ast::{fmt_c_integer, CInteger, FloatSize, IntegerBits, IntegerSign},
resolved::{human_name::HumanName, Ast, EnumRef, StructureRef, TypeAliasRef},
resolved::{human_name::HumanName, Ast, EnumRef, StructureRef, TraitRef, TypeAliasRef},
source_files::Source,
target::Target,
};
Expand Down Expand Up @@ -39,6 +39,7 @@ pub enum TypeKind {
Structure(HumanName, StructureRef, Vec<Type>),
TypeAlias(HumanName, TypeAliasRef),
Polymorph(String, Vec<Constraint>),
Trait(HumanName, TraitRef),
}

impl TypeKind {
Expand Down Expand Up @@ -70,6 +71,7 @@ impl TypeKind {
.any(|parameter| parameter.kind.contains_polymorph()),
TypeKind::TypeAlias(_, _) => false,
TypeKind::Polymorph(_, _) => true,
TypeKind::Trait(_, _) => false,
}
}

Expand Down Expand Up @@ -98,7 +100,8 @@ impl TypeKind {
| TypeKind::FunctionPointer(..)
| TypeKind::Enum(_, _)
| TypeKind::AnonymousEnum()
| TypeKind::Polymorph(_, _) => None,
| TypeKind::Polymorph(_, _)
| TypeKind::Trait(_, _) => None,
}
}

Expand Down Expand Up @@ -190,6 +193,9 @@ impl Display for TypeKind {
write!(f, "{:?}", constaint)?;
}
}
TypeKind::Trait(name, _) => {
write!(f, "{}", name)?;
}
}

Ok(())
Expand Down
1 change: 1 addition & 0 deletions src/resolved/datatype/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ impl Type {
TypeKind::Polymorph(_, constraints) => {
constraints.drain(..);
}
TypeKind::Trait(_, _) => (),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/resolved/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub struct CurrentConstraints {
impl CurrentConstraints {
pub fn satisfies(&self, ty: &Type, constraint: &Constraint) -> bool {
match constraint {
Constraint::PrimitiveAdd => match &ty.kind {
Constraint::PrimitiveAdd | Constraint::Trait(..) => match &ty.kind {
TypeKind::Integer(..) | TypeKind::CInteger(..) | TypeKind::Floating(..) => true,
TypeKind::Polymorph(name, constraints) => {
constraints.contains(constraint)
Expand Down
Loading

0 comments on commit 943ec77

Please sign in to comment.