Skip to main content

Nightly: v0.26.2

This version is still a work in progress.

✨ Highlights

Language enhancements

  • Mojo now supports specifying default value for inferred parameter, it make it easier to create a partially bound type like

    struct Pointer[mut = False, // o: Origin[mut]] : pass
    
    # Default to immutable pointer
    comptime ImmPointer = Pointer[_]
    # Explicitly set to mutable pointer
    comptime mutPointer = Pointer[mut = True, _]
    # Inferred mutability from `SomeOrigin()`
    comptime InferredPointer = Pointer[SomeOrigin()]
    # Parametric mutability pointer.
    comptime ParametricPointer = Pointer[...]
  • Mojo now supports a standalone assert statement, similar to Python's assert. It checks a condition at runtime and aborts the program if the condition is false:

    assert x > 0, "x must be positive"
    assert len(items) != 0

    The condition must be a Bool expression and the optional message can be any Writable expression (StringLiteral, String, Int, etc.). Under the hood, assert desugars to a call to debug_assert, so it respects the existing -D ASSERT flag: assertions are active when compiled with -D ASSERT=all and are no-ops otherwise.

  • Mojo now enforces a more explicit parameter bindings rules:

    • [] is mandatory to make type more concrete:

      struct SomeStruct[a : Int = 1]:
        pass
      
      # SS1 is a parametric type
      comptime SS1 = SomeStruct
      
      # SS2 a concrete type alias of `SomeStruct[1]
      comptime SS2 = SomeStruct[]
      
    • When [] is used, it must produce a concrete type unless _/... is used to unbind a specific/multiple missing parameters.

      struct SomeStruct[a : Int, b: Int, c: Int = 2]:
        pass
      
      # Error: can not infer `b`, since `[]` must produce a concrete type, without `_`/`...``
      comptime SS1 = SomeStruct[1]
      
      # This is a concrete type alias of `SomeStruct[1, 1, 2]`
      comptime SS2 = SomeStruct[1, 1]
      
      # Using `...` defers binding of b and c, and produces `SomeStruct[1, ?, ?]` (preserving possible defaults)
      comptime SS3 = SomeStruct[1, ...]
      
      # Even SS3 unbinds `c`, Mojo keeps track of the fact that there is a default value for c:
      # This install b (using 1) and c (using default value), and produce `SomeStruct[1, 1, 2]`
      comptime SS4 = SS3[1]
      
      # This installs the default and is identical to `SomeStruct[1, ?, 2]`
      comptime SS5 = SomeStruct[1, _]
      
      # This unbind the default explicitly and is identical to `SomeStruct[1, ?, ?]`
      comptime SS6 = SomeStruct[1, _, _]
      
      
      # The following two are equivalent:
      comptime SS7 = SomeStruct
      comptime SS8 = SomeStruct[...]
      
  • Mojo now supports t-strings (template strings) for building structured string templates with interpolated expressions. T-strings use the t"..." prefix and produce a TString value that captures both the static format string and any runtime arguments, rather than immediately producing a String:

    fn main():
        var x = 10
        var y = 20
        print(t"{x} + {y} = {x + y}")  # prints: 10 + 20 = 30

    Use {{ and }} to include literal braces in the output:

    print(t"Use {{braces}} like this")  # prints: Use {braces} like this
  • Mojo now supports comptime if and comptime for as the preferred syntax for compile-time conditional and loop constructs, replacing the legacy @parameter if and @parameter for decorator forms:

    # Old syntax (still accepted, deprecated in a future release)
    @parameter
    if some_condition:
        ...
    
    @parameter
    for i in range(10):
        ...
    
    # New syntax
    comptime if some_condition:
        ...
    
    comptime for i in range(10):
        ...

    Both syntaxes are accepted in this release. The @parameter forms will be deprecated soon, and the parser will generate a warning and a fixit suggestion to migrate to the new syntax.

  • @register_passable("trivial") is now deprecated, conform to TrivialRegisterPassable trait instead. The decorator will be removed after next release.

  • @register_passable is now deprecated, conform to RegisterPassable trait instead. The decorator will be removed after next release.

  • Mojo now supports more flexible default arguments and parameters, which can mismatch on declared type when their types are parametric. This allows inferring parameters from these when they are used as a default value, for example:

      fn take_string_slice[o: ImmOrigin](str: StringSlice[o] = ""): ...
      fn use_it():
        take_string_slice() # Ok, defaults to empty string, inferring "o".
        # Explicit calls also work of course.
        take_string_slice(StaticString("hello"))
    
      # Default value is checked for validity at the call site.
      fn defaultArgumentBadType2[T: AnyType](a: T = 1.0): pass
      fn callDefaultArgumentBadType2():
          # Ok!
          defaultArgumentBadType2[Float64]()
          # error: value passed to 'a' cannot be converted from 'FloatLiteral[1]' to 'Int'
          defaultArgumentBadType2[Int]()
  • Mojo now supports the @align(N) decorator to specify minimum alignment for structs, similar to C++'s alignas and Rust's #[repr(align(N))]. The value N must be a positive power of 2 and specifies the minimum alignment in bytes. The actual alignment will be max(N, natural_alignment) - you cannot use @align to reduce alignment below the struct's natural alignment. For example, @align(1) on a struct containing an Int (8-byte aligned) will emit a warning and the struct will remain 8-byte aligned.

    from sys import align_of
    
    @align(64)
    struct CacheAligned:
        var data: Int
    
    fn main():
        print(align_of[CacheAligned]())  # Prints 64

    Both stack and heap allocations respect @align.

    The alignment value can also be a struct parameter, enabling generic aligned types:

    @align(Self.alignment)
    struct AlignedBuffer[alignment: Int]:
        var data: Int
    
    fn main():
        print(align_of[AlignedBuffer[64]]())   # Prints 64
        print(align_of[AlignedBuffer[128]]())  # Prints 128
  • Mojo now allows move constructors to take their "take" argument as either deinit or var. deinit should be generally preferred, but var can be useful in unusual cases where you want C++-like behavior where the destructor still runs on the value after the move constructor is done with it.

    fn __init__(out self, *, var take: Self):
      self.data = munge(take.data)
      # take.__del__() runs here.
  • def functions now allows a raises specifier, and support typed errors. def will soon require an exception specifier to throw, so we strongly recommend changing def functions to have an explicit raises keyword. To help with migration, the Mojo compiler now produces a warning for def functions that lack a raises specifier.

    # Older behavior
    def foo():        # implicitly raises Error.
    def bar() raises: # was invalid
    # Current behavior
    def bar():        # Still implicitly raises Error (not recommended; warns)
    def bar() raises: # Explicit raises Error (recommended)
    # Near future behavior
    def bar():        # Does not raise.
    def bar() raises: # Explicit raises Error (required)

Language changes

  • **_ and *_ are no longer supported in parameter binding lists. Use a more concise ... to unbind any unspecified parameter explicitly.

  • As part of "init unification", the __moveinit__ and __copyinit__ methods are now renamed to fn __init__(out self, *, take: Self) and fn __init__(out self, *, copy: Self) respectively. Mojo now accepts these names for initializers, but also supports the legacy __moveinit__ and __copyinit__ names as well (for now). However, the argument name for these legacy methods must now be named take and copy respectively. Please move to the more modern __init__ names when possible.

  • As part of init unification, the __moveinit__is_trivial and __copyinit__is_trivial members of Movable and Copyable have been renamed to __move_ctor_is_trivial and __copy_ctor_is_trivial respectively.

  • Homogenous variadic parameters are now passed with the VariadicParamList type (formerly known as VariadicList) and arguments are now passed consistently passed with VariadicList (formerly VariadicListMem) instead of trivial types being passed directly.

  • Slice literals in subscripts has changed to be more similar to collection literals. They now pass an empty tuple as a required __slice_literal__ keyword argument to disambiguate slices. If you have defined your own range types, please add a __slice_literal__: () = () argument to their constructors.

  • trait declarations no longer automatically inherit from ImplicitlyDestructible. struct declarations are not changed, and continue to inherit from ImplicitlyDestructible.

    Previously, the @explicit_destroy annotation was required to opt-out of ImplicitlyDestructible conformance. Now, if a trait's usage depends on implicit destructibility, it must opt-in explicitly:

    # Before
    trait Foo:
        ...
    
    # After:
    trait Foo(ImplicitlyDestructible):
        ...

    Conversely, if a trait wanted to support non-implicitly-destructible types, it no longer needs to be annotated with @explicit_destroy:

    # Before
    @explicit_destroy
    trait Foo:
        ...
    
    # After
    trait Foo:
        ...

    Making struct continue to inherit from ImplicitlyDestructible and not trait is intended to balance usability and familiarity in the common case, with the need to foster broad Mojo ecosystem support for explicitly destroyed types.

    It's not a problem if the majority of struct types are ImplicitlyDestructible in practice. However, if many ecosystem libraries are written with unnecessary ImplicitlyDestructible bounds, that would hamper the usability of any individual struct type that opts-in to being explicitly destroyed.

    Libraries with generic algorithms and types should be written to accommodate linear types. Making ImplicitlyDestructible opt-in for traits encourages a default stance of support, with specific types and functions only opting-in to the narrower ImplicitlyDestructible requirement if they truly need it.

    The majority of generic algorithms that take their inputs by reference should not be affected.

  • Unstable __comptime_assert syntax is now finalized as comptime assert. A deprecation warning is emitted with a fixit for the old syntax.

  • comptime assert no longer errors on always false conditions. The assertion will only trigger if its parent scope is concretized.

  • A statically False comptime assert now ends a scope. Any code following it in the same scope is now a warning, and can be removed.

  • Re-exported symbols from a package's __init__.mojo are no longer shadowed by a submodule of the same name. For example, if pkg/foo.mojo defines fn foo and pkg/__init__.mojo does from .foo import foo, then from pkg import foo and from pkg import * now correctly resolve to the function rather than the module.

  • is_compile_time() has been renamed to is_run_in_comptime_interpreter() to provide a mechanism for supporting different code execution path in comptime interpreter from runtime generated code. The check should be used as condition for runtime if. Compiler now warns if it is used as condition for comptime if.

Library changes

  • StaticTuple now supports comparison operators. __eq__/__ne__ are available when element_type: Equatable, and __lt__/__le__/__gt__/ __ge__ are available when element_type: Comparable. All use lexicographic ordering with compile-time unrolled loops.

  • Dict now uses real conditional conformances for Writable. The Dict type only conforms to Writable when both its key and value types do, enforced at compile time via where clauses.

  • Standard library types now use conditional conformances, replacing previous _constrained_conforms_to checks:

    • Dict: Writable
    • InlineArray: Writable
    • List: Equatable, Writable
    • Optional: Writable
    • Set: Writable
    • Tuple: Writable
    • Variant: Writable
  • lane_group_sum(), lane_group_max(), and lane_group_min() in std.gpu.primitives.warp now always broadcast the reduction result to all participating lanes, using optimized hardware-specific paths (AMD DPP, Blackwell redux, or butterfly shuffle pattern). The previous lane_group_sum_and_broadcast(), lane_group_max_and_broadcast() functions are deprecated — use the short names instead.

  • Bool no longer conforms to the Indexer trait. Previously, Bool could be used to index into collections (e.g., nums[True]), which is not desirable behavior for a strongly-typed language. Use Int(my_bool) to explicitly convert a Bool to an index.

  • The Stringable and Representable traits are now deprecated. Use Writable instead to make your types formattable as strings. Writable provides a default implementation, so in many cases simply adding Writable conformance is enough without manually implementing write_to() or write_repr_to(), however, you can manually implement these to get custom output.

  • The env_get_bool(), env_get_int(), env_get_string(), and env_get_dtype() functions in the sys.param_env module have been renamed to get_defined_bool(), get_defined_int(), get_defined_string(), and get_defined_dtype() in the new sys.defines module. The new names better reflect that these functions read compile-time defines (set via -D), not runtime environment variables. The is_defined() function has also moved to sys.defines without renaming. The old names in sys.param_env are deprecated but still available.

  • TString.write_to() now uses a compact encoding for format strings. The format string is flattened at compile time into NUL-terminated literal segments, producing considerably smaller static data and faster runtime than the previous struct-based precompiled entries.

  • Set.pop() now uses Dict.popitem() directly, avoiding a redundant rehash. Order changes from FIFO to LIFO, matching Python's unordered set.pop().

  • Set.__gt__() and Set.__lt__() now use an O(1) len() check plus a single issubset() traversal instead of two full traversals.

  • Added uninit_move_n(), uninit_copy_n(), and destroy_n() functions to the memory module for efficient bulk memory operations. These functions handle moving, copying, and destroying multiple values in contiguous memory, with automatic optimization for trivial types using memcpy. They encapsulate the common pattern of checking __move_ctor_is_trivial, __copy_ctor_is_trivial, or __del__is_trivial and selecting the appropriate implementation. The List collection now uses these functions internally for improved code clarity and maintainability.

  • Dict internals have been replaced with a Swiss Table implementation using SIMD group probing for lookups. This improves lookup, insertion, and deletion performance — especially when looking up keys not in the dict — while increasing the load factor from 2/3 to 7/8 for better memory efficiency. The power_of_two_initial_capacity keyword argument has been renamed to capacity and now accepts any positive integer (it is rounded up to the next power of two internally, minimum 16).

  • Dict now performs in-place tombstone rehashing when the table is full of tombstones but the live element count is low. This prevents unnecessary capacity doubling after repeated insert/delete cycles.

  • Implicit conversions from Int to SIMD are now deprecated, and will be removed in a future version of Mojo. This includes deprecating converions from Int to specific SIMD scalar types like Int8 or Float32.

    Note: The experimental mojo build --experimental-fixit command may be useful in assiting with migrating your code to reflect this change.

    Code currently relying on implicit conversions, e.g.:

    fn foo(arg: Int) -> Float32:
        return arg

    should be changed to use an explicit conversion:

    fn foo(arg: Int) -> Float32:
        return Float32(arg)

    Occasionally, when an implicit conversion was happening from a scalar Int to a wider SIMD value, the compiler will suggest a change to make the conversion explicit that is somewhat verbose, performing both the type conversion and the "splat" in a single step:

    var bits: SIMD[DType.uint8, 16] = ...
    - var y = bits >> (j * 4)
    + var y = bits >> SIMD[DType.uint8, 16](j * 4)

    a simpler change is to make the type conversion explicit, and let the "splat" continue to happen implicitly (which will remain supported):

    var bits: SIMD[DType.uint8, 16] = ...
    - var y = bits >> (j * 4)
    + var y = bits >> UInt8(j * 4)

    A similar overly verbose suggestion can be emitted relating to LayoutTensor.element_type, where the compiler may suggest a change of the form:

    - tensor[i] = i * l
    + tensor[i] = LayoutTensor[DType.uint32, Layout(IntTuple(-1)), stack].element_type(i * l)

    where a simpler change is sufficient:

    - tensor[i] = i * l
    + tensor[i] = UInt32(i * l)
    
    # Note: If the tensors `dtype` is not statically known, this works as well:
    + tensor[i] = Scalar[tensor.dtype](i * l)
  • The builtin.math module has been merged into math. The traits Absable, DivModable, Powable, Roundable and functions abs(), divmod(), max(), min(), pow(), round() are now part of the math module and continue to be available in the prelude. Code that explicitly imported from builtin.math should update to import from math instead.

  • The ffi module is now a top-level module in the standard library, rather than being nested under sys. This improves discoverability of FFI functionality. Update your imports from from sys.ffi import ... to from ffi import ....

  • Added UnsafeUnion[*Ts], a C-style untagged union type for FFI interoperability. Unlike Variant, UnsafeUnion does not track which type is stored (no discriminant), making it suitable for interfacing with C unions and low-level type punning. The memory layout exactly matches C unions (size is max of elements, alignment is max of elements).

    All element types must have trivial copy, move, and destroy operations, matching C union semantics where types don't have constructors or destructors.

    Construction is explicit (no implicit conversion) to emphasize the unsafe nature of this type. All accessor methods are prefixed with unsafe_ to make it clear that these operations are unsafe.

    from ffi import UnsafeUnion
    
    # Define a union that can hold Int32 or Float32
    comptime IntOrFloat = UnsafeUnion[Int32, Float32]
    
    var u = IntOrFloat(Int32(42))
    print(u.unsafe_get[Int32]())  # => 42
    print(u)  # => UnsafeUnion[Int32, Float32](size=4, align=4)
    
    # Type punning (reinterpreting bits)
    var u2 = IntOrFloat(Float32(1.0))
    print(u2.unsafe_get[Int32]())  # => 1065353216 (IEEE 754 bits)
  • The itertools module now includes three new iterator combinators:

    • cycle(iterable): Creates an iterator that cycles through elements indefinitely
    • take_while[predicate](iterable): Yields elements while the predicate returns True
    • drop_while[predicate](iterable): Drops elements while the predicate returns True, then yields the rest
  • Math functions in std.math (exp, exp2, log2, erf, tanh, sin, cos, tan, acos, asin, atan, atan2, acosh, asinh, atanh, cosh, sinh, expm1, log10, log1p, logb, cbrt, erfc, j0, j1, y0, y1) now use where dtype.is_floating_point() clauses on their signatures instead of __comptime_assert checks in their bodies. This provides better compile-time error messages at the call site. Callers using these functions with generic dtype parameters may need to add evidence proving (either a where clause or __comptime_assert) that their type is floating point.

  • Many kernels in nn have been migrated to use TileTensor. We will have more documentation on TileTensor and its uses over the coming weeks.

  • InlineArray now requires explicitly using literals for construction. E.g.

    var a: InlineArray[UInt8, 4] = [1, 2, 3, 4]
    # instead of InlineArray[UInt8, 4](1, 2, 3, 4)
  • The following types now conform to Writable and have custom implementations of write_to and write_repr_to.

    • Tuple
    • Variant
    • Optional
  • The stdlib is beginning to remove support for the Stringable and Representable traits in favor of the unified Writable trait. Most stdlib types have had their conformance to Stringable and Representable removed and the associated __str__() and __repr__() methods have been deprecated.

  • The testing module now provides assert_equal and assert_not_equal overloads for Tuple, enabling direct tuple-to-tuple comparisons in tests instead of element-by-element assertions. Element types must conform to Equatable & Writable.

  • The __reversed__() method on String, StringSlice, and StringLiteral has been deprecated in favor of the new codepoints_reversed() method. The new method name makes it explicit that iteration is over Unicode codepoints in reverse order, maintaining consistency with the existing codepoints() and codepoint_slices() methods. The deprecated __reversed__() methods will continue to work but will emit deprecation warnings.

  • The Origin struct now takes the underlying MLIR origin as a parameter instead of storing it. This follows the design of IntLiteral and related types, and fixes some memory safety problems.

  • The StringSlice constructor from String now propagates mutability. If you have a mutable reference to a String, StringSlice(str) returns a mutable StringSlice. The String.as_string_slice() method is now deprecated in favor of the StringSlice(str) constructor, and String.as_string_slice_mut() has been removed.

  • String.ljust, String.rjust, and String.center have been renamed to String.ascii_ljust, String.ascii_rjust, and String.ascii_center. Likewise for their mequivalents on StringSlice and StaticString

  • String.resize will now panic if the new length would truncate a codepoint. Previously it would result in a string with invalid UTF-8.

  • String.resize will now panic if fill_byte is >=128. Previously it would create invalid UTF-8.

  • Subscripting into String and StringSlice will now panic if the index falls in the middle of a UTF-8 encoded code-point. Previously they would return invalid UTF-8. This panic is unconditional. Use .as_bytes()[...] if you really want the previous behavior.

  • StringSlice[byte=] subscripting now returns a StringSlice instead of a String, This is consistent with range-based subscripting.

  • Subscripting String and StringSlice by byte position will now return an entire Unicode codepoint. Previously it would return a single byte, and produce invalid UTF-8 if the index fell on the starting byte of a multi-byte codepoint.

  • The following types now correctly implement write_repr_to

    • List, Set
  • assert_equal and assert_not_equal now work with types implementing Writable.

  • All traits and structs with @register_passable("trivial") decorator are now extending TrivialRegisterPassable trait. The decorator is removed from them.

  • String, StringSlice, and StringLiteral's .format() method now require their arguments to be Writable.

  • Formatting compile-time format strings (StringLiterals) no longer allocates memory! It uses global_constant to store what would be heap allocated parsed formatting data.

  • Int.__truediv__ now performs truncating integer division, returning Int instead of the previously deprecated Float64. Use explicit Float64 casts for floating-point division.

  • Documentation for SIMD.__round__ now clarifies the pre-existing behavior that ties are rounded to the nearest even, not away from zero.

  • A new utils/type_functions module was added for holding type functions. Type functions are comptime declarations that produce a type from compile-time parameter inputs. Unlike regular fn functions which accept and return runtime values, type functions operate entirely at compile time -- they take comptime parameters and evaluate to a type, with no runtime component.

    • ConditionalType - A type function that conditionally selects between two types based on a compile-time boolean condition. It is the type-level equivalent of the ternary conditional expression Then if If else Else.
  • reflection/traits has been added, providing compile-time meta functions (AllWritable, AllMovable, AllCopyable, AllImplicitlyCopyable, AllDefaultable, AllEquatable) that evaluate to True if all types in a variadic type list conform to the corresponding trait.

  • UnsafeMaybeUninit has been renamed as such, and it's methods have had their names updated to reflect the init name. It also now exposes a zeroed() method to get zeroed out uninitialized memory. It also no longer calls abort() when being copied or moved, allowing for more practical uses.

  • Added the UnsafeNicheable and UnsafeSingleNicheable traits to std.utils. These traits allow types to expose known-invalid bit patterns ("niches") that can be used by containers like Optional and Variant to avoid storing a separate tag, so that size_of[Optional[T]]() == size_of[T](). UnsafeSingleNicheable is a simplified subtrait for the common case where a type has exactly one niche value.

    • Variant and Optional now automatically take advantage of this: when the variant types qualify, the discriminant tag is elided entirely, reducing the size of the variant. For example, size_of[Optional[T]]() == size_of[T]() for any T that implements UnsafeNicheable.
    • Variant also only works with Movable types in the interim instead of AnyType due to some compiler limitations.
  • Span[T] is no longer restricted to Copyable types. It now works with T: AnyType. There are a few restrictions including iteration requiring T: Copyable.

  • Int.write_padded now accounts for a negative sign when calculating the width, resulting in a consistent width regardless of sign:

    Int(1).write_padded(s, 4)  # writes "   1"
    Int(-1).write_padded(s, 4) # writes "  -1"
  • SIMD now has a write_padded method for integral DTypes, matching the behaviour of Int.write_padded. The padding is added elementwise. Unlike SIMD regular printing, there are no spaces added between elements by default:

    Int32(1).write_padded(s, 4)  # writes "   1"
    Int32(-1).write_padded(s, 4) # writes "  -1"
    
    # "[   1,  -1,   0,1234]"
    SIMD[DType.int32, 4](1,-1,0,1234).write_padded(s, 4)
    # "[255,255]"
    SIMD[DType.uint8, 2](255).write_padded(s, 1)
  • SIMD's safe division operators (__floordiv__, __mod__, __divmod__) now return safe results in an elementwise fashion. They previously returned a zero result if any element of the divisor was zero:

    comptime Int32x2 = SIMD[DType.int32, 2]
    
    var a = Int32x2(99, 99)
    var b = Int32x2(4, 0)
    # Now returns [24, 0]
    # Previously returned [0, 0]
    print(a.__floordiv__(b))
  • Changed CompilationTarget.unsupported_target_error() to return Never, and removed it's result type parameter.

  • Remove DType.get_dtype[T]() and DType.is_scalar[T](). These were low-level operations for extracting the DType of a SIMD in generic code. There are better alternatives available in Mojo today using reflection capabilities.

Tooling changes

  • The Mojo compiler now accepts conjoined -D options in addition to the non-conjoined form as before. Now, both -Dfoo and -D foo are accepted.

  • mojo build now supports several --print-* options for discovering target configuration and supported architectures:

    • --print-effective-target: Shows the resolved target configuration after processing all command-line flags.
    • --print-supported-targets: Lists all available LLVM target architectures.
    • --print-supported-cpus: Lists valid CPU names for a given target triple (requires --target-triple).
    • --print-supported-accelerators: Lists all supported GPU and accelerator architectures (NVIDIA, AMD, Apple Metal).
  • mojo format now only formats Mojo files (.mojo, .🔥) by default when run on a directory. Previously it would also format Python files, which conflicted with Python-specific formatters in pre-commit hooks. Users who want to format Python files can use mblack directly.

  • mojo format now supports --print-cache-dir (hidden, use --help-hidden to see it) to display the path to the formatter cache directory.

  • mojo build --emit=asm now also emits GPU kernel assembly files alongside the host .s output. For NVIDIA targets, PTX is written as <out>_<kernelfn>.ptx; for Apple Metal targets, LLVM IR is written as <out>_<kernelfn>.ll; for AMD targets, .amdgcn files are written. Multiple kernels generated from the same function are disambiguated with a numeric suffix (e.g. <out>_<kernelfn>_1.ptx).

❌ Removed

  • The owned keyword has been removed. Use var for parameters or deinit for __moveinit__/__del__ arguments as appropriate.

  • Dict.EMPTY and Dict.REMOVED comptime aliases have been removed. These were internal implementation details of the old hash table design.

  • The @nonmaterializable decorator has been renamed to @__nonmaterializable. This decorator should not be used outside the standard library, and might be removed in a future release.

🛠️ Fixed

  • Fixed a bug where Mojo incorrectly passed or returned structs in extern C function calls. The compiler now applies platform ABI coercion (System V AMD64 on x86-64, AAPCS on ARM64) when lowering external calls, decomposing structs into the register types the C ABI requires — matching the behavior of Clang and Rust. This resolves silent wrong-answer bugs when calling C functions that take or return struct types.

  • Issue #5845: Functions raising custom type with conversion fails when returning StringSlice

  • Issue #5722: __del__ incorrectly runs when __init__ raises before all fields are initialized.

  • Issue #5875: Storing SIMD[DType.bool, N] with width > 1 to a pointer and reading back element-wise now returns correct values.

  • StringSlice.find: Fixed integer overflow bug in SIMD string search that caused searches to fail when searching for strings longer than simd_width_of[DType.bool]() and haystacks larger than UInt16.MAX.

  • LinkedList.reverse(): Fixed missing prev pointer updates, which caused __reversed__() to produce wrong results after reversing.

  • Mojo would previously consider types Movable if they had a __moveinit__ method, even if they didn't conform to Movable. Movability is now tied to the conformance which implies the method.

Was this page helpful?