Skip to content

Commit c4dc638

Browse files
committed
Finished basic support for generic type aliases
1 parent 5a902fe commit c4dc638

File tree

7 files changed

+95
-32
lines changed

7 files changed

+95
-32
lines changed

Diff for: src/asg/mod.rs

+39-8
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ mod variable_storage;
2020

2121
pub use self::variable_storage::VariableStorageKey;
2222
pub use crate::ast::{IntegerBits, IntegerSign};
23-
use crate::{ast::AstWorkspace, source_files::SourceFiles};
23+
use crate::{
24+
ast::AstWorkspace,
25+
resolve::{PolyRecipe, PolyValue, PolymorphErrorKind},
26+
source_files::SourceFiles,
27+
};
2428
pub use block::*;
2529
pub use datatype::*;
2630
pub use destination::*;
@@ -33,9 +37,13 @@ pub use helper_expr::*;
3337
pub use human_name::*;
3438
pub use impl_params::*;
3539
pub use implementation::*;
40+
use indexmap::IndexMap;
3641
pub use overload::*;
3742
use slotmap::{new_key_type, SlotMap};
38-
use std::collections::{HashMap, HashSet};
43+
use std::{
44+
borrow::Cow,
45+
collections::{HashMap, HashSet},
46+
};
3947
pub use stmt::*;
4048
pub use structure::*;
4149
pub use trait_constraint::*;
@@ -85,21 +93,42 @@ impl<'a> Asg<'a> {
8593
}
8694
}
8795

88-
pub fn unalias(&'a self, whole_type: &'a Type) -> Result<&'a Type, UnaliasError> {
89-
let mut running = whole_type;
96+
pub fn unalias(&'a self, whole_type: &'a Type) -> Result<Cow<'a, Type>, UnaliasError> {
97+
let mut running = Cow::Borrowed(whole_type);
9098
let mut depth = 0;
9199

92-
while let TypeKind::TypeAlias(_, type_alias_ref, type_args) = &running.kind {
100+
while let TypeKind::TypeAlias(human_name, type_alias_ref, type_args) = &running.kind {
93101
let alias = self
94102
.type_aliases
95103
.get(*type_alias_ref)
96104
.expect("valid type alias ref");
97105

98-
if !type_args.is_empty() || !alias.params.is_empty() {
99-
todo!("unalias type alias with type args");
106+
if type_args.len() != alias.params.len() {
107+
return Err(UnaliasError::IncorrectNumberOfTypeArgsForAlias(
108+
human_name.0.clone(),
109+
));
110+
}
111+
112+
if alias.params.is_empty() {
113+
running = Cow::Borrowed(&alias.becomes);
114+
} else {
115+
let polymorphs = IndexMap::<String, PolyValue>::from_iter(
116+
alias
117+
.params
118+
.iter()
119+
.cloned()
120+
.zip(type_args.iter().cloned().map(PolyValue::Type)),
121+
);
122+
123+
let recipe = PolyRecipe { polymorphs };
124+
125+
running = Cow::Owned(
126+
recipe
127+
.resolve_type(&alias.becomes)
128+
.map_err(|e| UnaliasError::PolymorphError(e.kind))?,
129+
)
100130
}
101131

102-
running = &alias.becomes;
103132
depth += 1;
104133

105134
if depth > Self::MAX_UNALIAS_DEPTH {
@@ -146,4 +175,6 @@ impl<'a> Asg<'a> {
146175
pub enum UnaliasError {
147176
MaxDepthExceeded,
148177
SelfReferentialTypeAlias(String),
178+
IncorrectNumberOfTypeArgsForAlias(String),
179+
PolymorphError(PolymorphErrorKind),
149180
}

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

+10-10
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub fn conform_expr<O: Objective>(
8888

8989
if *from_type == *to_type {
9090
return O::success(|| TypedExpr {
91-
ty: to_type.clone(),
91+
ty: to_type.into_owned(),
9292
expr: expr.expr.clone(),
9393
is_initialized: expr.is_initialized,
9494
});
@@ -99,29 +99,29 @@ pub fn conform_expr<O: Objective>(
9999
from,
100100
behavior.c_integer_assumptions(),
101101
expr.expr.source,
102-
to_type,
102+
&to_type,
103103
),
104104
TypeKind::Integer(from_bits, from_sign) => from_integer::<O>(
105-
&expr.expr, from_type, mode, behavior, *from_bits, *from_sign, to_type,
105+
&expr.expr, &from_type, mode, behavior, *from_bits, *from_sign, &to_type,
106106
),
107-
TypeKind::FloatLiteral(from) => from_float_literal::<O>(*from, to_type, conform_source),
108-
TypeKind::Floating(from_size) => from_float::<O>(&expr.expr, mode, *from_size, to_type),
109-
TypeKind::Ptr(from_inner) => from_pointer::<O>(ctx, &expr.expr, mode, from_inner, to_type),
107+
TypeKind::FloatLiteral(from) => from_float_literal::<O>(*from, &to_type, conform_source),
108+
TypeKind::Floating(from_size) => from_float::<O>(&expr.expr, mode, *from_size, &to_type),
109+
TypeKind::Ptr(from_inner) => from_pointer::<O>(ctx, &expr.expr, mode, from_inner, &to_type),
110110
TypeKind::CInteger(from_size, from_sign) => from_c_integer::<O>(
111111
&expr.expr,
112-
from_type,
112+
&from_type,
113113
mode,
114114
behavior,
115115
*from_size,
116116
*from_sign,
117-
to_type,
117+
&to_type,
118118
conform_source,
119119
),
120120
TypeKind::AnonymousEnum(enumeration) => from_anonymous_enum::<O>(
121121
&expr.expr,
122-
from_type,
122+
&from_type,
123123
mode,
124-
to_type,
124+
&to_type,
125125
enumeration.as_ref(),
126126
conform_source,
127127
),

Diff for: src/resolve/core_struct_info.rs

+23-12
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,41 @@ use crate::{
33
asg::{self, Asg, HumanName, StructRef},
44
source_files::Source,
55
};
6+
use std::borrow::Cow;
67

78
#[derive(Clone, Debug)]
89
pub struct CoreStructInfo<'a> {
9-
pub name: &'a HumanName,
10+
pub name: Cow<'a, HumanName>,
1011
pub struct_ref: StructRef,
11-
pub arguments: &'a [asg::Type],
12+
pub arguments: Cow<'a, [asg::Type]>,
1213
}
1314

1415
pub fn get_core_struct_info<'a, 'b>(
1516
asg: &'b Asg<'a>,
1617
ty: &'a asg::Type,
1718
source: Source,
1819
) -> Result<CoreStructInfo<'b>, Option<ResolveError>> {
19-
match &asg
20+
let t = asg
2021
.unalias(ty)
2122
.map_err(|e| ResolveErrorKind::from(e).at(source))
22-
.map_err(Some)?
23-
.kind
24-
{
25-
asg::TypeKind::Structure(name, struct_ref, arguments) => Ok(CoreStructInfo {
26-
name,
27-
struct_ref: *struct_ref,
28-
arguments: arguments.as_slice(),
29-
}),
30-
_ => Err(None),
23+
.map_err(Some)?;
24+
25+
match t {
26+
Cow::Borrowed(t) => match &t.kind {
27+
asg::TypeKind::Structure(name, struct_ref, arguments) => Ok(CoreStructInfo {
28+
name: Cow::Borrowed(&name),
29+
struct_ref: *struct_ref,
30+
arguments: Cow::Borrowed(arguments.as_slice()),
31+
}),
32+
_ => Err(None),
33+
},
34+
Cow::Owned(t) => match &t.kind {
35+
asg::TypeKind::Structure(name, struct_ref, arguments) => Ok(CoreStructInfo {
36+
name: Cow::Owned(name.clone()),
37+
struct_ref: *struct_ref,
38+
arguments: Cow::Owned(arguments.as_slice().to_owned()),
39+
}),
40+
_ => Err(None),
41+
},
3142
}
3243
}

Diff for: src/resolve/error.rs

+8
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,14 @@ impl Display for ResolveErrorKind {
526526
UnaliasError::SelfReferentialTypeAlias(type_alias_name) => {
527527
write!(f, "Type alias '{}' is self-referential", type_alias_name)?
528528
}
529+
UnaliasError::IncorrectNumberOfTypeArgsForAlias(type_alias_name) => write!(
530+
f,
531+
"Incorrect number of type arguments for type alias '{}'",
532+
type_alias_name
533+
)?,
534+
UnaliasError::PolymorphError(e) => {
535+
e.fmt(f)?;
536+
}
529537
},
530538
ResolveErrorKind::CannotDeclareVariableOutsideFunction => {
531539
write!(f, "Cannot declare variable outside of function")?;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ pub fn resolve_struct_literal_expr(
7676
})
7777
})?;
7878

79-
let struct_name = struct_name.clone();
79+
let struct_name = struct_name.into_owned();
8080
let arguments = arguments.to_vec();
8181

8282
let mut next_index = 0;

Diff for: src/resolve/type_ctx/resolve_type.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl<'a> ResolveTypeCtx<'a> {
4141
.unalias(&ty)
4242
.map_err(ResolveErrorKind::from)
4343
.map_err(|e| e.at(ast_type.source))?
44-
.clone()),
44+
.into_owned()),
4545
ResolveTypeOptions::KeepAliases => Ok(ty),
4646
}
4747
}

Diff for: tests/success/generics_type_alias/main.adept

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
pragma => adept("3.0")
3+
4+
#[foreign]
5+
func printf(format ptr#char, ...) int
6+
7+
typealias t<$T> = $T
8+
9+
func main {
10+
x t<int> = 13
11+
12+
printf(c"x = %d\n", x)
13+
}

0 commit comments

Comments
 (0)