Skip to content

Commit 4a3b25c

Browse files
committed
Started improving type alias support and error messages
1 parent 5eb2bcb commit 4a3b25c

File tree

18 files changed

+218
-114
lines changed

18 files changed

+218
-114
lines changed

Diff for: src/asg/expr/enum_member.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,38 @@
11
use crate::{
2-
asg::{EnumRef, HumanName},
2+
asg::{EnumRef, HumanName, Type},
33
source_files::Source,
44
};
55
use core::hash::Hash;
6+
use num::BigInt;
67

78
#[derive(Clone, Debug)]
89
pub struct EnumMemberLiteral {
910
pub human_name: HumanName,
10-
pub enum_ref: EnumRef,
11+
pub enum_target: EnumTarget,
1112
pub variant_name: String,
1213
pub source: Source,
1314
}
1415

1516
impl Hash for EnumMemberLiteral {
1617
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1718
self.human_name.hash(state);
18-
self.enum_ref.hash(state);
19+
self.enum_target.hash(state);
1920
self.variant_name.hash(state);
2021
}
2122
}
2223

2324
impl PartialEq for EnumMemberLiteral {
2425
fn eq(&self, other: &Self) -> bool {
2526
self.human_name.eq(&other.human_name)
26-
&& self.enum_ref.eq(&other.enum_ref)
27+
&& self.enum_target.eq(&other.enum_target)
2728
&& self.variant_name.eq(&other.variant_name)
2829
}
2930
}
3031

3132
impl Eq for EnumMemberLiteral {}
33+
34+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
35+
pub enum EnumTarget {
36+
Named(EnumRef),
37+
Anonymous(BigInt, Type),
38+
}

Diff for: src/asg/mod.rs

+33-6
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub use impl_params::*;
3434
pub use implementation::*;
3535
pub use overload::*;
3636
use slotmap::{new_key_type, SlotMap};
37-
use std::collections::HashMap;
37+
use std::collections::{HashMap, HashSet};
3838
pub use stmt::*;
3939
pub use structure::*;
4040
pub use trait_constraint::*;
@@ -83,27 +83,54 @@ impl<'a> Asg<'a> {
8383
}
8484
}
8585

86-
pub fn unalias(&'a self, mut ty: &'a Type) -> Result<&'a Type, UnaliasError> {
86+
pub fn unalias(&'a self, whole_type: &'a Type) -> Result<&'a Type, UnaliasError> {
87+
let mut running = whole_type;
8788
let mut depth = 0;
8889

89-
while let TypeKind::TypeAlias(_, type_alias_ref) = ty.kind {
90-
ty = self
90+
while let TypeKind::TypeAlias(_, type_alias_ref) = running.kind {
91+
running = self
9192
.type_aliases
9293
.get(type_alias_ref)
9394
.expect("valid type alias ref");
9495

9596
depth += 1;
9697

9798
if depth > Self::MAX_UNALIAS_DEPTH {
98-
return Err(UnaliasError::MaxDepthExceeded);
99+
return Err(self.find_type_alias_self_reference(whole_type));
99100
}
100101
}
101102

102-
Ok(ty)
103+
Ok(running)
104+
}
105+
106+
fn find_type_alias_self_reference(&self, whole_type: &Type) -> UnaliasError {
107+
let mut seen = HashSet::new();
108+
let mut running = whole_type;
109+
let mut depth = 0;
110+
111+
while let TypeKind::TypeAlias(human_name, type_alias_ref) = &running.kind {
112+
running = self
113+
.type_aliases
114+
.get(*type_alias_ref)
115+
.expect("valid type alias ref");
116+
117+
if !seen.insert(type_alias_ref) {
118+
return UnaliasError::SelfReferentialTypeAlias(human_name.0.clone());
119+
}
120+
121+
depth += 1;
122+
123+
if depth > Self::MAX_UNALIAS_DEPTH {
124+
break;
125+
}
126+
}
127+
128+
return UnaliasError::MaxDepthExceeded;
103129
}
104130
}
105131

106132
#[derive(Clone, Debug)]
107133
pub enum UnaliasError {
108134
MaxDepthExceeded,
135+
SelfReferentialTypeAlias(String),
109136
}

Diff for: src/lower/expr/mod.rs

+30-21
Original file line numberDiff line numberDiff line change
@@ -419,32 +419,41 @@ pub fn lower_expr(
419419
Ok(Value::Literal(Literal::Void))
420420
}
421421
ExprKind::EnumMemberLiteral(enum_member_literal) => {
422-
let enum_definition = asg
423-
.enums
424-
.get(enum_member_literal.enum_ref)
425-
.expect("referenced enum to exist for enum member literal");
426-
427-
let member = enum_definition
428-
.members
429-
.get(&enum_member_literal.variant_name)
430-
.ok_or_else(|| {
431-
LowerErrorKind::NoSuchEnumMember {
432-
enum_name: enum_member_literal.human_name.to_string(),
433-
variant_name: enum_member_literal.variant_name.clone(),
434-
}
435-
.at(enum_member_literal.source)
436-
})?;
437-
438-
let ir_type = lower_type(ir_module, &builder.unpoly(&enum_definition.ty)?, asg)?;
439-
440-
let value = &member.value;
422+
let (value, ir_type, source) = match &enum_member_literal.enum_target {
423+
asg::EnumTarget::Named(enum_ref) => {
424+
let enum_definition = asg
425+
.enums
426+
.get(*enum_ref)
427+
.expect("referenced enum to exist for enum member literal");
428+
429+
let member = enum_definition
430+
.members
431+
.get(&enum_member_literal.variant_name)
432+
.ok_or_else(|| {
433+
LowerErrorKind::NoSuchEnumMember {
434+
enum_name: enum_member_literal.human_name.to_string(),
435+
variant_name: enum_member_literal.variant_name.clone(),
436+
}
437+
.at(enum_member_literal.source)
438+
})?;
439+
440+
let ir_type =
441+
lower_type(ir_module, &builder.unpoly(&enum_definition.ty)?, asg)?;
442+
443+
(&member.value, ir_type, enum_definition.source)
444+
}
445+
asg::EnumTarget::Anonymous(value, ty) => {
446+
let ir_type = lower_type(ir_module, &builder.unpoly(&ty)?, asg)?;
447+
(value, ir_type, enum_member_literal.source)
448+
}
449+
};
441450

442451
let make_error = |_| {
443452
LowerErrorKind::CannotFit {
444453
value: value.to_string(),
445454
expected_type: enum_member_literal.human_name.to_string(),
446455
}
447-
.at(enum_definition.source)
456+
.at(source)
448457
};
449458

450459
Ok(match ir_type {
@@ -476,7 +485,7 @@ pub fn lower_expr(
476485
return Err(LowerErrorKind::EnumBackingTypeMustBeInteger {
477486
enum_name: enum_member_literal.human_name.to_string(),
478487
}
479-
.at(enum_definition.source))
488+
.at(source))
480489
}
481490
})
482491
}

Diff for: src/resolve/error.rs

+14-21
Original file line numberDiff line numberDiff line change
@@ -523,28 +523,19 @@ impl Display for ResolveErrorKind {
523523
)?;
524524
}
525525
ResolveErrorKind::UnaliasError(details) => match details {
526-
UnaliasError::MaxDepthExceeded => write!(
527-
f,
528-
"Maximum type alias depth exceeded, please ensure your type alias is not recursive"
529-
)?,
526+
UnaliasError::MaxDepthExceeded => write!(f, "Maximum type alias depth exceeded")?,
527+
UnaliasError::SelfReferentialTypeAlias(type_alias_name) => {
528+
write!(f, "Type alias '{}' is self-referential", type_alias_name)?
529+
}
530530
},
531531
ResolveErrorKind::CannotDeclareVariableOutsideFunction => {
532-
write!(
533-
f,
534-
"Cannot declare variable outside of function"
535-
)?;
536-
},
532+
write!(f, "Cannot declare variable outside of function")?;
533+
}
537534
ResolveErrorKind::CannotReturnOutsideFunction => {
538-
write!(
539-
f,
540-
"Cannot return outside of function"
541-
)?;
535+
write!(f, "Cannot return outside of function")?;
542536
}
543537
ResolveErrorKind::CannotAssignVariableOutsideFunction => {
544-
write!(
545-
f,
546-
"Cannot assign variable outside of function"
547-
)?;
538+
write!(f, "Cannot assign variable outside of function")?;
548539
}
549540
ResolveErrorKind::PolymorphError(e) => {
550541
e.fmt(f)?;
@@ -553,14 +544,16 @@ impl Display for ResolveErrorKind {
553544
write!(f, "Undeclared trait '{}'", trait_name)?;
554545
}
555546
ResolveErrorKind::CannotUseOperator { operator, on_type } => {
556-
write!(f, "Cannot use operator '{}' on type '{}'", operator, on_type)?;
547+
write!(
548+
f,
549+
"Cannot use operator '{}' on type '{}'",
550+
operator, on_type
551+
)?;
557552
}
558553
ResolveErrorKind::ConstraintsNotSatisfiedForType { name } => {
559554
write!(f, "Constraints not satisfied for type '{}'", name)?;
560555
}
561-
ResolveErrorKind::TypeIsNotATrait {
562-
name
563-
} => {
556+
ResolveErrorKind::TypeIsNotATrait { name } => {
564557
write!(f, "Type '{}' is not a trait", name)?;
565558
}
566559
ResolveErrorKind::DuplicateTypeName { name } => {

Diff for: src/resolve/expr/call/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use crate::{
99
resolve::{
1010
conform::{conform_expr, to_default::conform_expr_to_default, ConformMode, Perform},
1111
error::{ResolveError, ResolveErrorKind},
12-
resolve_type_args_to_poly_args, Initialized, PolyCatalog,
12+
resolve_type_args_to_poly_args,
13+
type_ctx::ResolveTypeOptions,
14+
Initialized, PolyCatalog,
1315
},
1416
source_files::Source,
1517
};
@@ -132,7 +134,9 @@ pub fn call_callee(
132134
.map_err(ResolveError::from)?;
133135

134136
if let Some(required_ty) = &call.expected_to_return {
135-
let resolved_required_ty = ctx.type_ctx().resolve(required_ty)?;
137+
let resolved_required_ty = ctx
138+
.type_ctx()
139+
.resolve(required_ty, ResolveTypeOptions::Unalias)?;
136140

137141
if resolved_required_ty != return_type {
138142
return Err(ResolveErrorKind::FunctionMustReturnType {

Diff for: src/resolve/expr/mod.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use super::{
2020
destination::resolve_expr_to_destination,
2121
error::ResolveError,
2222
func_haystack::FuncHaystack,
23+
type_ctx::ResolveTypeOptions,
2324
variable_haystack::VariableHaystack,
2425
Initialized, ResolveTypeCtx,
2526
};
@@ -376,7 +377,9 @@ pub fn resolve_expr(
376377
resolve_static_member_call(ctx, static_access_call)
377378
}
378379
ast::ExprKind::SizeOf(ast_type) => {
379-
let ty = ctx.type_ctx().resolve(ast_type)?;
380+
let ty = ctx
381+
.type_ctx()
382+
.resolve(ast_type, ResolveTypeOptions::Unalias)?;
380383

381384
Ok(TypedExpr::new(
382385
asg::TypeKind::Integer(IntegerBits::Bits64, IntegerSign::Unsigned).at(source),
@@ -405,11 +408,15 @@ pub fn resolve_expr(
405408
result_type,
406409
} = &**info;
407410

408-
let ty = ctx.type_ctx().resolve(result_type)?;
411+
let ty = ctx
412+
.type_ctx()
413+
.resolve(result_type, ResolveTypeOptions::Unalias)?;
409414
let mut resolved_args = Vec::with_capacity(args.len());
410415

411416
for (expected_arg_type, arg) in args {
412-
let preferred_type = ctx.type_ctx().resolve(expected_arg_type)?;
417+
let preferred_type = ctx
418+
.type_ctx()
419+
.resolve(expected_arg_type, ResolveTypeOptions::Unalias)?;
413420

414421
resolved_args.push(
415422
resolve_expr(

Diff for: src/resolve/expr/static_member.rs

+28-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{call::call_callee, resolve_expr, ResolveExprCtx, ResolveExprMode};
22
use crate::{
3-
asg::{self, ImplRef, PolyCall, PolyCallee, TypeKind, TypedExpr},
3+
asg::{self, HumanName, ImplRef, PolyCall, PolyCallee, TypeKind, TypedExpr},
44
ast::{self, StaticMemberCall, StaticMemberValue, TypeArg},
55
name::Name,
66
resolve::{
@@ -11,7 +11,9 @@ use crate::{
1111
expr::PreferredType,
1212
func_haystack::{FindFunctionError, FuncHaystack},
1313
initialized::Initialized,
14-
resolve_type_args_to_poly_args, PolyCatalog, PolyRecipe,
14+
resolve_type_args_to_poly_args,
15+
type_ctx::ResolveTypeOptions,
16+
PolyCatalog, PolyRecipe,
1517
},
1618
source_files::Source,
1719
};
@@ -29,9 +31,24 @@ pub fn resolve_static_member_value(
2931
source,
3032
} = static_member_value;
3133

32-
let ty = ctx.type_ctx().resolve(&subject)?;
34+
let ty = ctx
35+
.type_ctx()
36+
.resolve(&subject, ResolveTypeOptions::Unalias)?;
3337

34-
let TypeKind::Enum(human_name, enum_ref) = &ty.kind else {
38+
let extracted = match &ty.kind {
39+
TypeKind::AnonymousEnum(enumeration) => enumeration.members.get(value).map(|member| {
40+
(
41+
HumanName("(anonymous enum)".into()),
42+
asg::EnumTarget::Anonymous(member.value.clone(), ty.clone()),
43+
)
44+
}),
45+
TypeKind::Enum(human_name, enum_ref) => {
46+
Some((human_name.clone(), asg::EnumTarget::Named(*enum_ref)))
47+
}
48+
_ => None,
49+
};
50+
51+
let Some((human_name, enum_target)) = extracted else {
3552
return Err(ResolveErrorKind::StaticMemberOfTypeDoesNotExist {
3653
ty: subject.to_string(),
3754
member: value.to_string(),
@@ -40,11 +57,11 @@ pub fn resolve_static_member_value(
4057
};
4158

4259
Ok(TypedExpr::new(
43-
ty.clone(),
60+
ty,
4461
asg::Expr::new(
4562
asg::ExprKind::EnumMemberLiteral(Box::new(asg::EnumMemberLiteral {
46-
human_name: human_name.clone(),
47-
enum_ref: *enum_ref,
63+
human_name,
64+
enum_target,
4865
variant_name: value.to_string(),
4966
source: *value_source,
5067
})),
@@ -153,7 +170,10 @@ pub fn resolve_impl_mention(
153170
match arg {
154171
ast::TypeArg::Type(ty) => {
155172
catalog
156-
.put_type(name, &ctx.type_ctx().resolve(ty)?)
173+
.put_type(
174+
name,
175+
&ctx.type_ctx().resolve(ty, ResolveTypeOptions::Unalias)?,
176+
)
157177
.expect("unique impl parameter names");
158178
}
159179
ast::TypeArg::Expr(expr) => {

Diff for: src/resolve/expr/struct_literal.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
conform::{conform_expr, ConformMode, Perform},
77
core_struct_info::{get_core_struct_info, CoreStructInfo},
88
error::{ResolveError, ResolveErrorKind},
9+
type_ctx::ResolveTypeOptions,
910
Initialized, PolyCatalog, PolymorphError,
1011
},
1112
source_files::Source,
@@ -58,7 +59,9 @@ pub fn resolve_struct_literal_expr(
5859
conform_behavior: ConformBehavior,
5960
source: Source,
6061
) -> Result<TypedExpr, ResolveError> {
61-
let struct_type = ctx.type_ctx().resolve(ast_type)?;
62+
let struct_type = ctx
63+
.type_ctx()
64+
.resolve(ast_type, ResolveTypeOptions::Unalias)?;
6265

6366
let CoreStructInfo {
6467
name: struct_name,

0 commit comments

Comments
 (0)