Skip to content

Commit

Permalink
Prelude implementation for Array methods
Browse files Browse the repository at this point in the history
Typechecker2: Fix bug where generics could receive a value of `Any` if
the hint is `Any`. This isn't _necessarily_ a bug per se, but it doesn't
always result in the expected value so I think it makes sense to make
this change.
  • Loading branch information
kengorab committed Nov 22, 2023
1 parent f8d224f commit f60027d
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 20 deletions.
8 changes: 3 additions & 5 deletions abra_cli/abra-files/example.abra
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// TODO: This shouldn't stackoverflow
//println([])

func callFn(fn: (Int, Int, Int, Int) => Int) = println(fn(1, 16, 1, 2))

func foo(*x: Int[]): Int = 12
/// Expect: 22
callFn(foo)
val arr = [1, 2, 3, 4]
func sum(acc: Int, i: Int): Int = acc + i
println(arr.reduce(0, sum))
52 changes: 48 additions & 4 deletions abra_core/src/typechecker/prelude.stub.abra
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,54 @@ type Array<T> {
@Stub func popFront(self): T?
@Stub func splitAt(self, index: Int): (T[], T[])
@Stub func concat(self, other: T[]): T[]
@Stub func map<U>(self, fn: (T) => U): U[]
@Stub func filter(self, fn: (T) => Bool): T[]
@Stub func reduce<U>(self, initialValue: U, fn: (U, T) => U): U
@Stub func forEach(self, fn: (T) => Unit)

func map<U>(self, fn: (T, Int) => U): U[] {
val newArray: U[] = Array.withCapacity(self.length)
var i = 0
while i < self.length {
val item = self._buffer.offset(i).load()
val result = fn(item, i)
newArray.push(result)
i += 1
}

newArray
}

func filter(self, fn: (T, Int) => Bool): T[] {
val newArray: T[] = Array.withCapacity(self.length)
var i = 0
while i < self.length {
val item = self._buffer.offset(i).load()
if fn(item, i) {
newArray.push(item)
}
i += 1
}

newArray
}

func reduce<U>(self, initialValue: U, fn: (U, T, Int) => U): U {
var acc = initialValue
var i = 0
while i < self.length {
val item = self._buffer.offset(i).load()
acc = fn(acc, item, i)
i += 1
}

acc
}

func forEach(self, fn: (T, Int) => Unit) {
var i = 0
while i < self.length {
val item = self._buffer.offset(i).load()
fn(item, i)
i += 1
}
}

func join(self, joiner = ""): String {
val reprs: String[] = Array.withCapacity(self.length)
Expand Down
6 changes: 4 additions & 2 deletions abra_core/src/typechecker/typechecker2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5181,8 +5181,10 @@ impl<'a, L: LoadModule> Typechecker2<'a, L> {
return_type_id = self.substitute_generics_with_known(&return_type_id, &filled_in_generic_types);
}
if let Some(type_hint) = type_hint {
if self.type_contains_generics(&return_type_id) {
self.extract_values_for_generics(&type_hint, &return_type_id, &mut filled_in_generic_types);
if type_hint != PRELUDE_ANY_TYPE_ID {
if self.type_contains_generics(&return_type_id) {
self.extract_values_for_generics(&type_hint, &return_type_id, &mut filled_in_generic_types);
}
}
}

Expand Down
10 changes: 4 additions & 6 deletions abra_core/src/typechecker/typechecker2_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4345,13 +4345,11 @@ fn typecheck_failure_lambda() {
received: PRELUDE_STRING_TYPE_ID,
};
assert_eq!(expected, err);
let (project, Either::Right(err)) = test_typecheck("[1, 2, 3].map((x: Int, y: Int) => x)").unwrap_err() else { unreachable!() };
let expected_type_id = project.find_type_id(&ScopeId(ModuleId(1), 0), &project.function_type(vec![PRELUDE_INT_TYPE_ID], 1, false, PRELUDE_INT_TYPE_ID)).unwrap();
let received_type_id = project.find_type_id(&ScopeId(ModuleId(1), 1), &project.function_type(vec![PRELUDE_INT_TYPE_ID, PRELUDE_INT_TYPE_ID], 2, false, PRELUDE_INT_TYPE_ID)).unwrap();
let (_, Either::Right(err)) = test_typecheck("[1, 2, 3].map((x: Int, y: String) => x)").unwrap_err() else { unreachable!() };
let expected = TypeError::TypeMismatch {
span: Span::new(ModuleId(1), (1, 16), (1, 35)),
expected: vec![expected_type_id],
received: received_type_id,
span: Span::new(ModuleId(1), (1, 24), (1, 24)),
expected: vec![PRELUDE_INT_TYPE_ID],
received: PRELUDE_STRING_TYPE_ID,
};
assert_eq!(expected, err);
}
Expand Down
3 changes: 1 addition & 2 deletions abra_llvm/src/compiler2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@ impl ResolvedGenerics {

pub fn new_via_method_call(&self, target_ty: &Type, method: &Function, realized_generics: &Vec<TypeId>, project: &Project) -> ResolvedGenerics {
// TODO: Rework this? It's a little inefficient because it collects twice (and clones the underlying map).
ResolvedGenerics::default()
.new_via_instance(target_ty, project)
self.new_via_instance(target_ty, project)
.extend_via_func_call(method, realized_generics, project)
}

Expand Down
49 changes: 48 additions & 1 deletion abra_llvm/tests/arrays.abra
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func testRangeIndexing() {
}
testRangeIndexing()

// Array#pop()
// Array#pop
func testArrayPop() {
val arr = [1, 2, 3]
/// Expect: 3
Expand All @@ -88,6 +88,53 @@ func testArrayPop() {
}
testArrayPop()

// Array#map
func addOne(i: Int): Int = i + 1
func exclaim(i: Int, _: Int, x = "!"): String = "$i$x"
func testArrayMap() {
val arr = [1, 2, 3, 4]

/// Expect: [2, 3, 4, 5]
println(arr.map(addOne))

/// Expect: [1!, 2!, 3!, 4!]
println(arr.map(exclaim))
}
testArrayMap()

// Array#filter
func isEven(i: Int): Bool = i % 2 == 0
func testArrayFilter() {
val arr = [1, 2, 3, 4]

/// Expect: [2, 4]
println(arr.filter(isEven))
}
testArrayFilter()

// Array#reduce
func doSum(acc: Int, i: Int): Int = acc + i
func testArrayReduce() {
val arr = [1, 2, 3, 4]

/// Expect: 10
println(arr.reduce(0, doSum))
}
testArrayReduce()

// Array#forEach
func printItem(item: Int) = println(item)
func testArrayForEach() {
val arr = [1, 2, 3, 4]

/// Expect: 1
/// Expect: 2
/// Expect: 3
/// Expect: 4
arr.forEach(printItem)
}
testArrayForEach()

// Array#join
func testArrayJoin() {
val arr = [123, 456, 789]
Expand Down

0 comments on commit f60027d

Please sign in to comment.