Skip to content

Commit 8b20cb2

Browse files
committed
Fixed bug with type arguments for named types not being properly resolved in some circumstances
1 parent bf2be1f commit 8b20cb2

File tree

5 files changed

+254
-99
lines changed

5 files changed

+254
-99
lines changed

Diff for: src/asg/datatype/kind/mod.rs

+120-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub use fixed_array::FixedArray;
1717
pub use func_ptr::FuncPtr;
1818
use num::{BigInt, Zero};
1919
use ordered_float::NotNan;
20-
use std::fmt::Display;
20+
use std::{borrow::Cow, fmt::Display};
2121

2222
#[derive(Clone, Debug, Hash, PartialEq, IsVariant, Unwrap)]
2323
pub enum TypeKind {
@@ -115,6 +115,125 @@ impl TypeKind {
115115
_ => 0,
116116
}
117117
}
118+
119+
pub fn map_type_params<E>(
120+
&self,
121+
mut mapper: impl FnMut(TypeParam) -> Result<TypeParam, E>,
122+
) -> Result<Cow<Self>, TypeParamError<E>> {
123+
match self {
124+
TypeKind::Unresolved
125+
| TypeKind::Boolean
126+
| TypeKind::Integer(_, _)
127+
| TypeKind::CInteger(_, _)
128+
| TypeKind::IntegerLiteral(_)
129+
| TypeKind::FloatLiteral(_)
130+
| TypeKind::Floating(_) => Ok(Cow::Borrowed(self)),
131+
TypeKind::Ptr(inner) => {
132+
let TypeParam::Type(inner) = mapper(TypeParam::Type(Cow::Borrowed(inner)))
133+
.map_err(TypeParamError::MappingError)?
134+
else {
135+
return Err(TypeParamError::ExpectedType { index: 0 });
136+
};
137+
138+
Ok(Cow::Owned(Self::Ptr(Box::new(inner.into_owned()))))
139+
}
140+
TypeKind::Void
141+
| TypeKind::Never
142+
| TypeKind::AnonymousStruct()
143+
| TypeKind::AnonymousUnion()
144+
| TypeKind::AnonymousEnum() => Ok(Cow::Borrowed(self)),
145+
TypeKind::FixedArray(fixed_array) => {
146+
let TypeParam::Size(size) = mapper(TypeParam::Size(fixed_array.size))
147+
.map_err(TypeParamError::MappingError)?
148+
else {
149+
return Err(TypeParamError::ExpectedSize { index: 0 });
150+
};
151+
152+
if size != fixed_array.size {
153+
return Err(TypeParamError::ExpectedSizeValue {
154+
index: 0,
155+
value: fixed_array.size,
156+
});
157+
}
158+
159+
let TypeParam::Type(inner) =
160+
mapper(TypeParam::Type(Cow::Borrowed(&fixed_array.inner)))
161+
.map_err(TypeParamError::MappingError)?
162+
else {
163+
return Err(TypeParamError::ExpectedType { index: 1 });
164+
};
165+
166+
Ok(Cow::Owned(Self::FixedArray(Box::new(FixedArray {
167+
size,
168+
inner: inner.into_owned(),
169+
}))))
170+
}
171+
TypeKind::FuncPtr(_) => todo!(),
172+
TypeKind::Enum(_, _) => Ok(Cow::Borrowed(self)),
173+
TypeKind::Structure(human_name, struct_ref, type_args) => {
174+
if type_args.is_empty() {
175+
return Ok(Cow::Borrowed(self));
176+
}
177+
178+
let mut mapped = vec![];
179+
180+
for (i, type_arg) in type_args.iter().enumerate() {
181+
let TypeParam::Type(inner) = mapper(TypeParam::Type(Cow::Borrowed(type_arg)))
182+
.map_err(TypeParamError::MappingError)?
183+
else {
184+
return Err(TypeParamError::ExpectedType { index: i });
185+
};
186+
187+
mapped.push(inner.into_owned());
188+
}
189+
190+
Ok(Cow::Owned(Self::Structure(
191+
human_name.clone(),
192+
*struct_ref,
193+
mapped,
194+
)))
195+
}
196+
TypeKind::TypeAlias(_, _) => Ok(Cow::Borrowed(self)),
197+
TypeKind::Polymorph(_, _) => Ok(Cow::Borrowed(self)),
198+
TypeKind::Trait(human_name, trait_ref, type_args) => {
199+
if type_args.is_empty() {
200+
return Ok(Cow::Borrowed(self));
201+
}
202+
203+
let mut mapped = vec![];
204+
205+
for (i, type_arg) in type_args.iter().enumerate() {
206+
let TypeParam::Type(inner) = mapper(TypeParam::Type(Cow::Borrowed(type_arg)))
207+
.map_err(TypeParamError::MappingError)?
208+
else {
209+
return Err(TypeParamError::ExpectedType { index: i });
210+
};
211+
212+
mapped.push(inner.into_owned());
213+
}
214+
215+
Ok(Cow::Owned(Self::Trait(
216+
human_name.clone(),
217+
*trait_ref,
218+
mapped,
219+
)))
220+
}
221+
}
222+
}
223+
}
224+
225+
#[derive(Clone, Debug)]
226+
pub enum TypeParam<'a> {
227+
Size(u64),
228+
Type(Cow<'a, Type>),
229+
}
230+
231+
#[derive(Clone, Debug)]
232+
pub enum TypeParamError<E> {
233+
MappingError(E),
234+
ExpectedType { index: usize },
235+
ExpectedSize { index: usize },
236+
ExpectedSizeValue { index: usize, value: u64 },
118237
}
119238

120239
impl Display for TypeKind {

Diff for: src/resolve/impl_head.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,6 @@ fn ensure_satisfies_trait_func(
206206
Ok(())
207207
}
208208

209-
fn mismatch(source: Source) -> ResolveError {
210-
ResolveError::other("Type violates expected type required by trait", source)
211-
}
212-
213209
fn matches(
214210
ctx: &ResolveCtx,
215211
asg: &Asg,
@@ -218,6 +214,17 @@ fn matches(
218214
ty_in_trait: &Type,
219215
ty_in_impl: &Type,
220216
) -> Result<(), ResolveError> {
217+
let mismatch = |source| {
218+
ResolveError::other(
219+
format!(
220+
"Type '{}' violates expected type required by trait '{}'",
221+
ty_in_impl.to_string(),
222+
ty_in_trait.to_string(),
223+
),
224+
source,
225+
)
226+
};
227+
221228
match &ty_in_trait.kind {
222229
asg::TypeKind::Unresolved => panic!("unresolved"),
223230
asg::TypeKind::Void

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

+93-73
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
use super::{find_error::FindTypeError, ResolveTypeCtx};
22
use crate::{
3-
asg::{self},
4-
ast::TypeArg,
3+
asg::{self, TypeParam, TypeParamError},
4+
ast::{self, TypeArg},
55
name::Name,
6-
resolve::error::ResolveErrorKind,
6+
resolve::error::ResolveError,
7+
source_files::Source,
78
};
8-
use itertools::Itertools;
99
use std::borrow::Cow;
1010

1111
impl<'a> ResolveTypeCtx<'a> {
1212
pub fn find(
1313
&self,
1414
name: &Name,
15-
arguments: &[TypeArg],
15+
type_args: &[TypeArg],
16+
source: Source,
1617
) -> Result<Cow<'a, asg::TypeKind>, FindTypeError> {
1718
let settings = &self.asg.workspace.settings[self
1819
.asg
@@ -24,88 +25,107 @@ impl<'a> ResolveTypeCtx<'a> {
2425
.expect("valid settings id")
2526
.0];
2627

27-
if let Some(decl) = name
28+
let decl = name
2829
.as_plain_str()
2930
.and_then(|name| {
3031
self.types_in_modules
3132
.get(&self.module_fs_node_id)
3233
.and_then(|types_in_module| types_in_module.get(name))
3334
})
34-
// NOTE: This will need to be map instead at some point
35-
.filter(|decl| decl.num_parameters(self.asg) == arguments.len())
36-
{
37-
if let asg::TypeKind::Structure(human_name, struct_ref, _) = &decl.kind {
38-
let arguments = arguments
39-
.iter()
40-
.flat_map(|arg| match arg {
41-
TypeArg::Type(ty) => self.resolve(ty),
42-
TypeArg::Expr(expr) => Err(ResolveErrorKind::Other {
43-
message:
44-
"Expressions cannot be used as type parameters to structures yet"
45-
.into(),
46-
}
47-
.at(expr.source)),
48-
})
49-
.collect_vec();
35+
.filter(|local| local.num_parameters(self.asg) == type_args.len())
36+
.map(Ok)
37+
.unwrap_or_else(|| {
38+
if name.namespace.is_empty() {
39+
return Err(FindTypeError::NotDefined);
40+
}
5041

51-
return Ok(Cow::Owned(asg::TypeKind::Structure(
52-
human_name.clone(),
53-
*struct_ref,
54-
arguments,
55-
)));
56-
}
42+
let Name {
43+
namespace,
44+
basename,
45+
..
46+
} = name;
5747

58-
if let asg::TypeKind::Trait(human_name, trait_ref, _) = &decl.kind {
59-
let arguments = arguments
60-
.iter()
61-
.flat_map(|arg| match arg {
62-
TypeArg::Type(ty) => self.resolve(ty),
63-
TypeArg::Expr(expr) => Err(ResolveErrorKind::Other {
64-
message: "Expressions cannot be used as type parameters to traits yet"
65-
.into(),
66-
}
67-
.at(expr.source)),
68-
})
69-
.collect_vec();
48+
let mut matches = settings
49+
.namespace_to_dependency
50+
.get(namespace.as_ref())
51+
.into_iter()
52+
.flatten()
53+
.flat_map(|dep| settings.dependency_to_module.get(dep))
54+
.flat_map(|fs_node_id| self.types_in_modules.get(fs_node_id))
55+
.flat_map(|decls| decls.get(basename.as_ref()))
56+
.filter(|decl| decl.privacy.is_public())
57+
.filter(|decl| decl.num_parameters(self.asg) == type_args.len());
7058

71-
return Ok(Cow::Owned(asg::TypeKind::Trait(
72-
human_name.clone(),
73-
*trait_ref,
74-
arguments,
75-
)));
76-
}
59+
if let Some(found) = matches.next() {
60+
if matches.next().is_some() {
61+
Err(FindTypeError::Ambiguous)
62+
} else {
63+
Ok(found)
64+
}
65+
} else {
66+
Err(FindTypeError::NotDefined)
67+
}
68+
})?;
7769

78-
return Ok(Cow::Borrowed(&decl.kind));
79-
}
70+
let mut type_args = type_args.into_iter().enumerate();
8071

81-
if !name.namespace.is_empty() {
82-
let Name {
83-
namespace,
84-
basename,
85-
..
86-
} = name;
72+
let filled = decl
73+
.kind
74+
.map_type_params(|_hint| {
75+
let Some((_i, value)) = type_args.next() else {
76+
return Err(FindTypeError::TypeArgsLengthMismatch);
77+
};
8778

88-
let mut matches = settings
89-
.namespace_to_dependency
90-
.get(namespace.as_ref())
91-
.into_iter()
92-
.flatten()
93-
.flat_map(|dep| settings.dependency_to_module.get(dep))
94-
.flat_map(|fs_node_id| self.types_in_modules.get(fs_node_id))
95-
.flat_map(|decls| decls.get(basename.as_ref()))
96-
.filter(|decl| decl.privacy.is_public())
97-
// NOTE: This will need to be flat_map instead at some point
98-
.filter(|decl| decl.num_parameters(self.asg) == arguments.len());
79+
match value {
80+
TypeArg::Type(ty) => self
81+
.resolve(ty)
82+
.map(Cow::Owned)
83+
.map(TypeParam::Type)
84+
.map_err(FindTypeError::ResolveError),
85+
TypeArg::Expr(expr) => {
86+
let ast::ExprKind::Integer(ast::Integer::Generic(value)) = &expr.kind
87+
else {
88+
return Err(FindTypeError::ResolveError(ResolveError::other(
89+
"Expressions are not supported as type arguments yet",
90+
source,
91+
)));
92+
};
9993

100-
if let Some(found) = matches.next() {
101-
if matches.next().is_some() {
102-
return Err(FindTypeError::Ambiguous);
103-
} else {
104-
return Ok(Cow::Borrowed(&found.kind));
94+
u64::try_from(value).map(TypeParam::Size).map_err(|_| {
95+
FindTypeError::ResolveError(ResolveError::other(
96+
"Size is too large",
97+
source,
98+
))
99+
})
100+
}
105101
}
106-
}
107-
}
102+
})
103+
.map_err(|err| match err {
104+
TypeParamError::MappingError(e) => e,
105+
TypeParamError::ExpectedType { index } => {
106+
FindTypeError::ResolveError(ResolveError::other(
107+
format!("Expected type for type argument {}", index + 1),
108+
source,
109+
))
110+
}
111+
TypeParamError::ExpectedSize { index } => {
112+
FindTypeError::ResolveError(ResolveError::other(
113+
format!("Expected size for type argument {}", index + 1),
114+
source,
115+
))
116+
}
117+
TypeParamError::ExpectedSizeValue { index, value } => {
118+
FindTypeError::ResolveError(ResolveError::other(
119+
format!("Expected size of {} of type argument {}", value, index + 1),
120+
source,
121+
))
122+
}
123+
});
124+
125+
if type_args.next().is_some() {
126+
return Err(FindTypeError::TypeArgsLengthMismatch);
127+
};
108128

109-
Err(FindTypeError::NotDefined)
129+
filled
110130
}
111131
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub enum FindTypeError {
1111
RecursiveAlias(ResolvedName),
1212
ResolveError(ResolveError),
1313
ConstraintsNotSatisfied,
14+
TypeArgsLengthMismatch,
1415
}
1516

1617
impl FindTypeError {
@@ -36,6 +37,10 @@ impl FindTypeError {
3637
}
3738
.at(source)
3839
}
40+
FindTypeError::TypeArgsLengthMismatch => ResolveErrorKind::Other {
41+
message: "Incorrect number of type arguments for type".into(),
42+
}
43+
.at(source),
3944
FindTypeError::ResolveError(err) => err,
4045
}
4146
}

0 commit comments

Comments
 (0)