Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG]: Parser crash when invoking member method on generic type #910

Closed
meer-suri opened this issue Sep 24, 2023 · 3 comments
Closed

[BUG]: Parser crash when invoking member method on generic type #910

meer-suri opened this issue Sep 24, 2023 · 3 comments
Assignees
Labels
bug Something isn't working mojo Issues that are related to mojo mojo-lang Tag for all issues related to language.

Comments

@meer-suri
Copy link

meer-suri commented Sep 24, 2023

Bug description

Wrote very basic String (Str) and List (List[T]) types to experiment with mojo. Initially tried to create items as List[Str] and append Strs to it but got the error candidate not viable: result cannot bind generic !mlirtype to memory-only type 'Str' so experimented with a different signature for append that replaced T with Pointer[T] to see what would happen. The append worked, but this change seemed to cause the parser to crash when calling a method of Str on an item of the list - items[0].to_str(). Accessing an attribute of Str on an item of the list like items[0].size works fine

mojo: /__w/modular/modular/KGEN/lib/MojoParser/ExprEmitter.cpp:691: M::KGEN::LIT::MBValue M::KGEN::LIT::ExprEmitter::emitMBValue(ASTExprAnd<M::KGEN::LIT::AnyValue>, M::KGEN::LIT::ExprContext): Assertion `value.ir.getIfPValue() && "expected a PValue if not an MRValue"' failed.
Please submit a bug report to https://github.com/modularml/mojo/issues and include the crash backtrace along with all the relevant source codes.
Stack dump:
0.	Program arguments: mojo mylist.mojo
1.	Crash resolving decl body at loc("/home/memryxsw/mojo/mojo-experiments/crash_reports/mylist.mojo":45:1)
    >> fn main() raises:
       ^................
    >>     var items = List[Str]()
    >>     print(items.size)
    >>     var a = Str("abc")
    >>     print(a.to_str())
2.	Crash parsing statement at loc("/home/memryxsw/mojo/mojo-experiments/crash_reports/mylist.mojo":52:5)
    >>     print(items[0].to_str())
           ^.......................<
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  mojo      0x0000560de31f0797
1  mojo      0x0000560de31ee36e
2  mojo      0x0000560de31f0e6f
3  libc.so.6 0x00007fe4e7a42520
4  libc.so.6 0x00007fe4e7a96a7c pthread_kill + 300
5  libc.so.6 0x00007fe4e7a42476 raise + 22
6  libc.so.6 0x00007fe4e7a287f3 abort + 211
7  libc.so.6 0x00007fe4e7a2871b
8  libc.so.6 0x00007fe4e7a39e96
9  mojo      0x0000560de360d564
10 mojo      0x0000560de365ce56
11 mojo      0x0000560de365fb9c
12 mojo      0x0000560de3652e89
13 mojo      0x0000560de361cd79
14 mojo      0x0000560de361c689
15 mojo      0x0000560de360f8b9
16 mojo      0x0000560de363d70b
17 mojo      0x0000560de3638a94
18 mojo      0x0000560de3638946
19 mojo      0x0000560de35f2952
20 mojo      0x0000560de35ea96e
21 mojo      0x0000560de35e8ea9
22 mojo      0x0000560de35b4d3a
23 mojo      0x0000560de35b56ab
24 mojo      0x0000560de31bad3f
25 mojo      0x0000560de31a5f60
26 mojo      0x0000560de31b9c4d
27 mojo      0x0000560de319fb6d
28 libc.so.6 0x00007fe4e7a29d90
29 libc.so.6 0x00007fe4e7a29e40 __libc_start_main + 128
30 mojo      0x0000560de319f0fe
Aborted

Steps to reproduce

mylist.mojo

from memory.unsafe import Pointer

from mystr import Str

struct List[T: AnyType]:
    var data: Pointer[T]
    var size: Int
    var capacity: Int

    fn __init__(inout self):
        self.data = Pointer[T].alloc(1)
        self.capacity = 1
        self.size = 0

    fn __init__(inout self, size: Int, value: T):
        self.data = Pointer[T].alloc(size)
        self.capacity = size
        self.size = size
        for i in range(size):
            let value_copy = value
            self.data.store(i, value_copy)

    fn append(inout self, obj: Pointer[T]): # won't accept T so maybe Pointer[T] could work?
        if self.size == self.capacity:
            let new_capacity = 2*self.capacity
            let new_data = Pointer[T].alloc(new_capacity)
            for i in range(self.size):
                new_data.store(i, self.data.load(i))
            self.data.free()
            self.capacity = new_capacity
            self.data = new_data
        self.data.store(self.size, obj.load())
        self.size += 1

    fn __getitem__(inout self, idx: Int) raises -> T:
        if idx >= 0 and idx > self.size:
            raise Error("Index out of bounds")
        return self.data.load(idx)
    
    fn __del__(owned self):
        self.data.free()
        self.size = 0
        self.capacity = 0

fn main() raises:
    var items = List[Str]()
    print(items.size)
    var a = Str("abc")
    print(a.to_str())
    items.append(Pointer[Str].address_of(a))
    print(items.size)
    print(items[0].to_str())

mystr.mojo

from memory.unsafe import Pointer

struct Str:
    var data: Pointer[UInt8]
    var size: Int

    fn __init__(inout self):
        self.data = Pointer[UInt8].get_null()
        self.size = 0

    fn __init__(inout self, size: Int):
        self.data = Pointer[UInt8].alloc(size)
        self.size = size

    fn __init__(inout self, s: String):
        self.size = len(s)
        self.data = Pointer[UInt8].alloc(self.size)
        for i in range(self.size):
            self.data.store(i, UInt8(ord(s[i])))

    fn __copyinit__(inout self, other: Str):
        self.data = Pointer[UInt8].alloc(other.size)
        self.size = other.size
        for i in range(self.size):
            self.data.store(i, other.data.load(i))

    fn __add__(borrowed self, other: Str) -> Str:
        let out_str = Str(self.size + other.size)
        for i in range(self.size):
            out_str.data.store(i, self.data.load(i))
        for i in range(other.size):
            out_str.data.store(i + self.size, other.data.load(i))
        return out_str

    fn make_empty(inout self, size: Int):
        self.data = Pointer[UInt8].alloc(size)
        self.size = size
        for i in range(size):
            self.data.store(i, 0)

    fn to_str(borrowed self) -> String:
        var s = String()
        for i in range(self.size):
            let c = chr(self.data.load(i).to_int())
            s += c[0]
        return s

    fn startswith(borrowed self, prefix: String) -> Bool:
        let pref_len = len(prefix)
        if pref_len > self.size:
            return False
        for i in range(pref_len):
            if self.data.load(i) != ord(prefix[i]):
                return False
        return True

System information

- What OS did you do install Mojo on ? Ubuntu 22.04
- Provide version information for Mojo by pasting the output of `mojo -v` mojo 0.3.0 (f64f9601)
- Provide Modular CLI version by pasting the output of `modular -v` modular 0.1.4 (6b54d308)
@meer-suri meer-suri added bug Something isn't working mojo Issues that are related to mojo labels Sep 24, 2023
@ematejska ematejska added the mojo-lang Tag for all issues related to language. label Sep 25, 2023
@Mogball Mogball changed the title [BUG]: Parser: Crash resolving decl body [BUG]: Parser crash when invoking member method on generic type Sep 26, 2023
@Mogball
Copy link
Collaborator

Mogball commented Oct 19, 2023

Thanks for the bug report! I've reduced the problem to the following test case

struct Thing:
    fn init(self):
        pass

@value
struct List[T: AnyType]:
    fn __getitem__(inout self, idx: Int) raises -> T:
        pass

fn main() raises:
    var items = List[Thing]()
    print(items[0].init())

@Mogball
Copy link
Collaborator

Mogball commented Oct 19, 2023

@willghatch Do you mind taking a look when you have a chance?

@willghatch willghatch self-assigned this Oct 19, 2023
@willghatch
Copy link
Contributor

This has been fixed and will be included in the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working mojo Issues that are related to mojo mojo-lang Tag for all issues related to language.
Projects
None yet
Development

No branches or pull requests

4 participants