Skip to content

Commit 8bd10ae

Browse files
committed
Add construction and deconstruction
1 parent 7313c52 commit 8bd10ae

File tree

4 files changed

+219
-38
lines changed

4 files changed

+219
-38
lines changed

crates/rue-compiler/src/compiler/item/type_alias_item.rs

+7-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rue_parser::TypeAliasItem;
2+
use rue_typing::{Alias, Type, TypeId};
23

3-
use crate::{compiler::Compiler, value::Type, ErrorKind, TypeId};
4+
use crate::compiler::Compiler;
45

56
impl Compiler<'_> {
67
/// Define a type for an alias in the current scope, but leave it as unknown for now.
@@ -22,22 +23,11 @@ impl Compiler<'_> {
2223
.map_or(self.ty.std().unknown, |ty| self.compile_type(ty));
2324

2425
// Set the alias type to the resolved type.
25-
*self.db.ty_mut(alias_type_id) = Type::Alias(type_id);
26-
27-
// A cycle between type aliases has been detected.
28-
// We set it to unknown to prevent stack overflow issues later.
29-
if self.db.is_cyclic(alias_type_id) {
30-
let name = type_alias
31-
.name()
32-
.expect("the name should exist if it's in a cyclic reference");
33-
34-
self.db.error(
35-
ErrorKind::RecursiveTypeAlias(name.to_string()),
36-
name.text_range(),
37-
);
38-
39-
*self.db.ty_mut(alias_type_id) = Type::Unknown;
40-
}
26+
*self.ty.get_mut(alias_type_id) = Type::Alias(Alias {
27+
original_type_id: None,
28+
type_id,
29+
generic_types: Vec::new(),
30+
});
4131

4232
self.type_definition_stack.pop().unwrap();
4333
}

crates/rue-typing/src/difference.rs

+15-14
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@ use std::collections::HashSet;
33
use num_bigint::BigInt;
44
use num_traits::One;
55

6-
use crate::{bigint_to_bytes, Enum, StandardTypes, Struct, Type, TypeId, TypeSystem, Variant};
6+
use crate::{bigint_to_bytes, Enum, Struct, Type, TypeId, TypeSystem, Variant};
77

88
pub(crate) fn difference_type(
99
types: &mut TypeSystem,
10-
std: &StandardTypes,
1110
lhs: TypeId,
1211
rhs: TypeId,
1312
visited: &mut HashSet<(TypeId, TypeId)>,
1413
) -> TypeId {
14+
let std = types.std();
15+
1516
if !visited.insert((lhs, rhs)) {
1617
return lhs;
1718
}
@@ -198,8 +199,8 @@ pub(crate) fn difference_type(
198199
let (lhs_first, lhs_rest) = (*lhs_first, *lhs_rest);
199200
let (rhs_first, rhs_rest) = (*rhs_first, *rhs_rest);
200201

201-
let first = difference_type(types, std, lhs_first, rhs_first, visited);
202-
let rest = difference_type(types, std, lhs_rest, rhs_rest, visited);
202+
let first = difference_type(types, lhs_first, rhs_first, visited);
203+
let rest = difference_type(types, lhs_rest, rhs_rest, visited);
203204

204205
if matches!(types.get(first), Type::Never) || matches!(types.get(first), Type::Never) {
205206
std.never
@@ -216,7 +217,7 @@ pub(crate) fn difference_type(
216217
let mut result = Vec::new();
217218

218219
for item in &items {
219-
let item = difference_type(types, std, *item, rhs, visited);
220+
let item = difference_type(types, *item, rhs, visited);
220221
if matches!(types.get(item), Type::Never) {
221222
continue;
222223
}
@@ -238,17 +239,17 @@ pub(crate) fn difference_type(
238239
let items = items.clone();
239240
let mut lhs = lhs;
240241
for item in items {
241-
lhs = difference_type(types, std, lhs, item, visited);
242+
lhs = difference_type(types, lhs, item, visited);
242243
}
243244
lhs
244245
}
245246

246-
(Type::Alias(alias), _) => difference_type(types, std, alias.type_id, rhs, visited),
247-
(_, Type::Alias(alias)) => difference_type(types, std, lhs, alias.type_id, visited),
247+
(Type::Alias(alias), _) => difference_type(types, alias.type_id, rhs, visited),
248+
(_, Type::Alias(alias)) => difference_type(types, lhs, alias.type_id, visited),
248249

249250
(Type::Struct(ty), _) => {
250251
let ty = ty.clone();
251-
let type_id = difference_type(types, std, ty.type_id, rhs, visited);
252+
let type_id = difference_type(types, ty.type_id, rhs, visited);
252253

253254
types.alloc(Type::Struct(Struct {
254255
original_type_id: Some(ty.original_type_id.unwrap_or(lhs)),
@@ -260,7 +261,7 @@ pub(crate) fn difference_type(
260261
}
261262
(_, Type::Struct(ty)) => {
262263
let ty = ty.clone();
263-
let type_id = difference_type(types, std, lhs, ty.type_id, visited);
264+
let type_id = difference_type(types, lhs, ty.type_id, visited);
264265

265266
types.alloc(Type::Struct(Struct {
266267
original_type_id: Some(ty.original_type_id.unwrap_or(rhs)),
@@ -273,7 +274,7 @@ pub(crate) fn difference_type(
273274

274275
(Type::Enum(ty), _) => {
275276
let ty = ty.clone();
276-
let type_id = difference_type(types, std, ty.type_id, rhs, visited);
277+
let type_id = difference_type(types, ty.type_id, rhs, visited);
277278

278279
types.alloc(Type::Enum(Enum {
279280
original_type_id: Some(ty.original_type_id.unwrap_or(lhs)),
@@ -284,7 +285,7 @@ pub(crate) fn difference_type(
284285
}
285286
(_, Type::Enum(ty)) => {
286287
let ty = ty.clone();
287-
let type_id = difference_type(types, std, lhs, ty.type_id, visited);
288+
let type_id = difference_type(types, lhs, ty.type_id, visited);
288289

289290
types.alloc(Type::Enum(Enum {
290291
original_type_id: Some(ty.original_type_id.unwrap_or(rhs)),
@@ -296,7 +297,7 @@ pub(crate) fn difference_type(
296297

297298
(Type::Variant(variant), _) => {
298299
let variant = variant.clone();
299-
let type_id = difference_type(types, std, variant.type_id, rhs, visited);
300+
let type_id = difference_type(types, variant.type_id, rhs, visited);
300301

301302
types.alloc(Type::Variant(Variant {
302303
original_type_id: Some(variant.original_type_id.unwrap_or(lhs)),
@@ -310,7 +311,7 @@ pub(crate) fn difference_type(
310311
}
311312
(_, Type::Variant(variant)) => {
312313
let variant = variant.clone();
313-
let type_id = difference_type(types, std, lhs, variant.type_id, visited);
314+
let type_id = difference_type(types, lhs, variant.type_id, visited);
314315

315316
types.alloc(Type::Variant(Variant {
316317
original_type_id: Some(variant.original_type_id.unwrap_or(rhs)),

crates/rue-typing/src/semantic_types.rs

+191-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::collections::HashMap;
33
use indexmap::IndexSet;
44
use num_bigint::BigInt;
55

6-
use crate::TypeId;
6+
use crate::{Comparison, Type, TypeId, TypeSystem};
77

88
/// The kind of ending that a list has.
99
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -86,3 +86,193 @@ pub struct Variant {
8686
/// The discriminant value.
8787
pub discriminant: BigInt,
8888
}
89+
90+
/// Constructs a structural type consisting of the items in a list.
91+
pub fn construct_items(
92+
db: &mut TypeSystem,
93+
items: impl DoubleEndedIterator<Item = TypeId>,
94+
rest: Rest,
95+
) -> TypeId {
96+
let mut result = db.std().nil;
97+
for (i, item) in items.rev().enumerate() {
98+
if i == 0 {
99+
match rest {
100+
Rest::Spread => {
101+
result = item;
102+
continue;
103+
}
104+
Rest::Optional => {
105+
result = db.alloc(Type::Pair(item, result));
106+
result = db.alloc(Type::Union(vec![result, db.std().nil]));
107+
continue;
108+
}
109+
Rest::Nil => {}
110+
}
111+
}
112+
result = db.alloc(Type::Pair(item, result));
113+
}
114+
result
115+
}
116+
117+
/// Deconstructs a structural type into a list of items and a rest value.
118+
pub fn deconstruct_items(
119+
db: &mut TypeSystem,
120+
type_id: TypeId,
121+
length: usize,
122+
rest: Rest,
123+
) -> Option<Vec<TypeId>> {
124+
let mut items = Vec::with_capacity(length);
125+
let mut current = type_id;
126+
127+
for i in (0..length).rev() {
128+
if i == 0 {
129+
match rest {
130+
Rest::Spread => {
131+
items.push(current);
132+
break;
133+
}
134+
Rest::Optional => {
135+
if db.compare(db.std().nil, current) > Comparison::Assignable {
136+
return None;
137+
}
138+
139+
let non_nil = db.difference(current, db.std().nil);
140+
let (first, rest) = db.get_pair(non_nil)?;
141+
142+
if db.compare(rest, db.std().nil) > Comparison::Equal {
143+
return None;
144+
}
145+
146+
items.push(first);
147+
break;
148+
}
149+
Rest::Nil => {
150+
let (first, rest) = db.get_pair(current)?;
151+
items.push(first);
152+
if db.compare(rest, db.std().nil) > Comparison::Equal {
153+
return None;
154+
}
155+
break;
156+
}
157+
}
158+
}
159+
let (first, rest) = db.get_pair(current)?;
160+
items.push(first);
161+
current = rest;
162+
}
163+
164+
Some(items)
165+
}
166+
167+
#[cfg(test)]
168+
mod tests {
169+
use super::*;
170+
171+
#[test]
172+
fn test_construct_int_nil() {
173+
let mut db = TypeSystem::new();
174+
let std = db.std();
175+
let type_id = construct_items(&mut db, [std.int].into_iter(), Rest::Nil);
176+
let items = deconstruct_items(&mut db, type_id, 1, Rest::Nil);
177+
assert_eq!(items, Some(vec![std.int]));
178+
}
179+
180+
#[test]
181+
fn test_construct_int() {
182+
let mut db = TypeSystem::new();
183+
let std = db.std();
184+
let type_id = construct_items(&mut db, [std.int].into_iter(), Rest::Spread);
185+
let items = deconstruct_items(&mut db, type_id, 1, Rest::Spread);
186+
assert_eq!(items, Some(vec![std.int]));
187+
}
188+
189+
#[test]
190+
fn test_construct_int_optional() {
191+
let mut db = TypeSystem::new();
192+
let std = db.std();
193+
let type_id = construct_items(&mut db, [std.int].into_iter(), Rest::Optional);
194+
let items = deconstruct_items(&mut db, type_id, 1, Rest::Optional);
195+
assert_eq!(items, Some(vec![std.int]));
196+
}
197+
198+
#[test]
199+
fn test_construct_empty_nil() {
200+
let mut db = TypeSystem::new();
201+
let type_id = construct_items(&mut db, [].into_iter(), Rest::Nil);
202+
let items = deconstruct_items(&mut db, type_id, 0, Rest::Nil);
203+
assert_eq!(items, Some(vec![]));
204+
}
205+
206+
#[test]
207+
fn test_construct_empty() {
208+
let mut db = TypeSystem::new();
209+
let type_id = construct_items(&mut db, [].into_iter(), Rest::Spread);
210+
let items = deconstruct_items(&mut db, type_id, 0, Rest::Spread);
211+
assert_eq!(items, Some(vec![]));
212+
}
213+
214+
#[test]
215+
fn test_construct_empty_optional() {
216+
let mut db = TypeSystem::new();
217+
let type_id = construct_items(&mut db, [].into_iter(), Rest::Optional);
218+
let items = deconstruct_items(&mut db, type_id, 0, Rest::Optional);
219+
assert_eq!(items, Some(vec![]));
220+
}
221+
222+
#[test]
223+
fn test_construct_int_int_nil() {
224+
let mut db = TypeSystem::new();
225+
let std = db.std();
226+
let type_id = construct_items(&mut db, [std.int, std.int].into_iter(), Rest::Nil);
227+
let items = deconstruct_items(&mut db, type_id, 2, Rest::Nil);
228+
assert_eq!(items, Some(vec![std.int, std.int]));
229+
}
230+
231+
#[test]
232+
fn test_construct_int_int() {
233+
let mut db = TypeSystem::new();
234+
let std = db.std();
235+
let type_id = construct_items(&mut db, [std.int, std.int].into_iter(), Rest::Spread);
236+
let items = deconstruct_items(&mut db, type_id, 2, Rest::Spread);
237+
assert_eq!(items, Some(vec![std.int, std.int]));
238+
}
239+
240+
#[test]
241+
fn test_construct_int_int_optional() {
242+
let mut db = TypeSystem::new();
243+
let std = db.std();
244+
let type_id = construct_items(&mut db, [std.int, std.int].into_iter(), Rest::Optional);
245+
let items = deconstruct_items(&mut db, type_id, 2, Rest::Optional);
246+
assert_eq!(items, Some(vec![std.int, std.int]));
247+
}
248+
249+
#[test]
250+
fn test_construct_bytes32_pair_nil() {
251+
let mut db = TypeSystem::new();
252+
let std = db.std();
253+
let pair = db.alloc(Type::Pair(std.bytes32, std.nil));
254+
let type_id = construct_items(&mut db, [std.bytes32, pair].into_iter(), Rest::Nil);
255+
let items = deconstruct_items(&mut db, type_id, 2, Rest::Nil);
256+
assert_eq!(items, Some(vec![std.bytes32, pair]));
257+
}
258+
259+
#[test]
260+
fn test_construct_bytes32_pair() {
261+
let mut db = TypeSystem::new();
262+
let std = db.std();
263+
let pair = db.alloc(Type::Pair(std.bytes32, std.nil));
264+
let type_id = construct_items(&mut db, [std.bytes32, pair].into_iter(), Rest::Spread);
265+
let items = deconstruct_items(&mut db, type_id, 2, Rest::Spread);
266+
assert_eq!(items, Some(vec![std.bytes32, pair]));
267+
}
268+
269+
#[test]
270+
fn test_construct_bytes32_pair_optional() {
271+
let mut db = TypeSystem::new();
272+
let std = db.std();
273+
let pair = db.alloc(Type::Pair(std.bytes32, std.nil));
274+
let type_id = construct_items(&mut db, [std.bytes32, pair].into_iter(), Rest::Optional);
275+
let items = deconstruct_items(&mut db, type_id, 2, Rest::Optional);
276+
assert_eq!(items, Some(vec![std.bytes32, pair]));
277+
}
278+
}

crates/rue-typing/src/type_system.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -103,16 +103,16 @@ impl TypeSystem {
103103
}
104104
}
105105

106-
pub fn pair_first(&self, type_id: TypeId) -> Option<TypeId> {
106+
pub fn get_pair(&self, type_id: TypeId) -> Option<(TypeId, TypeId)> {
107107
match self.get(type_id) {
108-
Type::Pair(first, _) => Some(*first),
108+
Type::Pair(first, rest) => Some((*first, *rest)),
109109
_ => None,
110110
}
111111
}
112112

113-
pub fn pair_rest(&self, type_id: TypeId) -> Option<TypeId> {
113+
pub fn get_union(&self, type_id: TypeId) -> Option<&[TypeId]> {
114114
match self.get(type_id) {
115-
Type::Pair(_, rest) => Some(*rest),
115+
Type::Union(types) => Some(types),
116116
_ => None,
117117
}
118118
}
@@ -178,8 +178,8 @@ impl TypeSystem {
178178
check_type(self, lhs, rhs, &mut HashSet::new()).map(simplify_check)
179179
}
180180

181-
pub fn difference(&mut self, std: &StandardTypes, lhs: TypeId, rhs: TypeId) -> TypeId {
182-
difference_type(self, std, lhs, rhs, &mut HashSet::new())
181+
pub fn difference(&mut self, lhs: TypeId, rhs: TypeId) -> TypeId {
182+
difference_type(self, lhs, rhs, &mut HashSet::new())
183183
}
184184

185185
pub fn replace(

0 commit comments

Comments
 (0)