Highlights
Here's a brief summary of some of the major changes in this release, with more detailed information in the following sections:
The
inout
andborrowed
argument conventions have been renamed tomut
andread
, respectively. A newout
convention has been added for theself
argument in constructors and for named results. See Language changes for details.Lifetime
and related types in the standard library have been renamed toOrigin
to better clarify that parameters of this type indicate where a reference is derived from, not the more complicated notion of where a variable is initialized and destroyed. As a consequence the__lifetime_of()
operator is now named__origin_of()
.
There are also a number of other origin-related improvements in this release, including being able to specify a union of origins by listing multiple values in the
__origin_of()
operator or inside theref
origin specifier (ref [a, b]
). For details, see Language changes.
For background information and rationale on the name change see the proposal. For more information on origins, see Lifetimes, origins and references in the Mojo Manual.
Implicit conversions are now opt-in using the
@implicit
decorator. See Language changes for details.The standard library has added several new types, including
Deque
(a double-ended queue) andOwnedPointer
(safe, single-owner, non-nullable smart pointer). See Standard library changes for details.The VS Code extension now supports setting data breakpoints and function breakpoints, and the Mojo LLDB debugger supports symbol breakpoints, such as
b main
orb my_module::main
.We've made a number of improvement to how information is displayed in error messages, LSP, and generated API documentation. For details, see Tooling changes.
And we've added a number of new docs, including a brand new Mojo tutorial, new pages on operators and expressions, error handling, and pointers, and many smaller additions and improvements.
Language changes
Argument convention changes:
The
inout
andborrowed
argument conventions have been renamed tomut
(for "mutate") andread
, respectively. These verbs reflect what the callee can do to the argument value passed in by the caller, without requiring the programmer to know about advanced features like references.
For information on Mojo's argument conventions, see Argument conventions in the Mojo Manual.
The argument convention for the
self
argument in the__init__()
,__copyinit__()
, and__moveinit__()
methods has been changed frominout
toout
, reflecting that a constructor method initializes itsself
value without reading from it. This also enables spelling the type of an initializer correctly, which was not supported before:
struct Foo: fn __init__(out self): passfn test(): # This works now var fnPtr : fn(out x: Foo)->None = Foo.__init__ var someFoo : Foo fnPtr(someFoo) # initializes someFoo.
struct Foo: fn __init__(out self): passfn test(): # This works now var fnPtr : fn(out x: Foo)->None = Foo.__init__ var someFoo : Foo fnPtr(someFoo) # initializes someFoo.
The previous
fn __init__(inout self)
syntax is still supported in this release of Mojo, but will be removed in the future. Please migrate to the new syntax.Similarly, the spelling of named results has switched to use
out
syntax instead of-> T as name
. Functions may have at most one named result or return type specified with the usual->
syntax.out
arguments may occur anywhere in the argument list, but are typically last (except for__init__
methods, where they are typically first).
# This function has type "fn() -> String"fn example(out result: String): result = "foo"
# This function has type "fn() -> String"fn example(out result: String): result = "foo"
The parser still accepts the old syntax as a synonym for this, but that will eventually be deprecated and removed.
This was discussed extensively in a public proposal. For more information, see Named results in the Mojo Manual.
Single argument constructors now require the
@implicit
decorator to allow for implicit conversions. Previously you could define an__init__
that takes a single argument:
struct Foo: var value: Int fn __init__(out self, value: Int): self.value = value
struct Foo: var value: Int fn __init__(out self, value: Int): self.value = value
And this would allow you to pass an
Int
in the position of aFoo
:
fn func(foo: Foo): print("implicitly converted Int to Foo:", foo.value)fn main(): func(Int(42))
fn func(foo: Foo): print("implicitly converted Int to Foo:", foo.value)fn main(): func(Int(42))
This can result in complicated errors that are difficult to debug. By default this implicit behavior is now turned off, so you have to explicitly construct
Foo
:
fn main(): func(Foo(42))
fn main(): func(Foo(42))
You can still opt into implicit conversions by adding the
@implicit
decorator. For example, to enable implicit conversions fromInt
toFoo
:
struct Foo: var value: Int @implicit fn __init__(out self, value: Int): self.value = value
struct Foo: var value: Int @implicit fn __init__(out self, value: Int): self.value = value
For more information see Constructors and implicit conversion in the Mojo Manual.
Origin-related changes:
The
AnyLifetime
type (useful for declaring origin types as parameters) has has been renamed toOrigin
and the__lifetime_of()
operator renamed to__origin_of()
.Origin
is now a complete wrapper around the MLIR origin type.
The
Origin.type
alias has been renamed to_mlir_origin
. In parameter lists, you can now write justOrigin[..]
, instead ofOrigin[..].type
.ImmutableOrigin
andMutableOrigin
are now, respectively, just aliases forOrigin[False]
andOrigin[True]
.Origin
struct values are now supported in the origin specifier of aref [..]
argument.Added
Origin.cast_from
for casting the mutability of an origin value.
ref
arguments and results now allow for providing a memory value directly in the origin specifier, rather than requiring the use of__origin_of()
. It is still fine to use__origin_of()
explicitly though, and this is required when specifying origins for parameters (e.g. to thePointer
type). For example, this is now valid without__origin_of()
:
fn return_ref(a: String) -> ref [a] String: return a
fn return_ref(a: String) -> ref [a] String: return a
Various improvements to origin handling and syntax have landed, including support for the ternary operator and allowing multiple arguments in a
ref
specifier (which are implicitly unions). This enables expression of simple algorithms cleanly:
fn my_min[T: Comparable](ref a: T, ref b: T) -> ref [a, b] T: return a if a < b else b
fn my_min[T: Comparable](ref a: T, ref b: T) -> ref [a, b] T: return a if a < b else b
It is also nice that
my_min
automatically and implicitly propagates the mutability of its arguments, so things likemy_min(str1, str2) += "foo"
is valid.ref
function arguments without an origin clause are now treated asref [_]
, which is more syntactically convenient and consistent:
fn takes_and_return_ref(ref a: String) -> ref [a] String: return a
fn takes_and_return_ref(ref a: String) -> ref [a] String: return a
The
__type_of(x)
and__origin_of(x)
operators are much more general now: they allow arbitrary expressions inside of them, allow referring to dynamic values in parameter contexts, and even allow referring to raising functions in non-raising contexts. These operations never evaluate their expression, so any side effects that occur in the expression are never evaluated at runtime, eliminating concerns about__type_of(expensive())
being a problem.The destructor insertion logic in Mojo is now aware that types that take an
MutableAnyOrigin
orImmutableAnyOrigin
as part of their signature could potentially access any live value that destructor insertion is tracking, eliminating a significant usability issue with unsafe APIs likeUnsafePointer
. Consider a typical example working with strings before this change:
var str = String(...)var ptr = str.unsafe_ptr()some_low_level_api(ptr)_ = str^ # OLD HACK: Explicitly keep string alive until here!
var str = String(...)var ptr = str.unsafe_ptr()some_low_level_api(ptr)_ = str^ # OLD HACK: Explicitly keep string alive until here!
The
_ = str^
pattern was formerly required because the Mojo compiler has no idea what "ptr" might reference. As a consequence, it had no idea thatsome_low_level_api()
might accessstr
and therefore thought it was ok to destroy theString
before the call - this is why the explicit lifetime extension was required.
Mojo now knows that
UnsafePointer
may access theMutableAnyOrigin
origin, and now assumes that any API that uses that origin could use live values. In this case, it assumes thatsome_low_level_api()
might accessstr
and because it might be using it, it cannot destroystr
until after the call. The consequence of this is that the old hack is no longer needed for these cases!Function types now accept an origin set parameter. This parameter represents the origins of values captured by a parameter closure. The compiler automatically tags parameter closures with the right set of origins. This enables lifetimes and parameter closures to correctly compose.
fn call_it[f: fn() capturing [_] -> None](): f()fn test(): var msg = String("hello world") @parameter fn say_hi(): print(msg) call_it[say_hi]() # no longer need to write `_ = msg^`!!
fn call_it[f: fn() capturing [_] -> None](): f()fn test(): var msg = String("hello world") @parameter fn say_hi(): print(msg) call_it[say_hi]() # no longer need to write `_ = msg^`!!
Note that this only works for higher-order functions which have explicitly added
[_]
as the capture origins. By default, the compiler still assumes acapturing
closure does not reference any origins. This will soon change.
Infer-only parameters may now be explicitly bound with keywords, enabling some important patterns in the standard library:
struct StringSlice[is_mutable: Bool, //, origin: Origin[is_mutable]]: ...alias ImmStringSlice = StringSlice[is_mutable=False]# This auto-parameterizes on the origin, but constrains it to being an# immutable slice instead of a potentially mutable one.fn take_imm_slice(a: ImmStringSlice): ...
struct StringSlice[is_mutable: Bool, //, origin: Origin[is_mutable]]: ...alias ImmStringSlice = StringSlice[is_mutable=False]# This auto-parameterizes on the origin, but constrains it to being an# immutable slice instead of a potentially mutable one.fn take_imm_slice(a: ImmStringSlice): ...
The flag for turning on asserts has changed, e.g. to enable all checks:
mojo -D ASSERT=all main.mojo
mojo -D ASSERT=all main.mojo
The levels are:
none
: all assertions offwarn
: print assertion errors e.g. for multithreaded tests (previously-D ASSERT_WARNING
)safe
: the default mode for standard CPU safety assertionsall
: turn on all assertions (previously-D MOJO_ENABLE_ASSERTIONS
)
You can now also pass
Stringable
args to format a message, which will have no runtime penalty or IR bloat cost when assertions are off. Previously you had to:
x = -1debug_assert( x > 0, String.format_sequence(“expected x to be more than 0 but got: ”, x))
x = -1debug_assert( x > 0, String.format_sequence(“expected x to be more than 0 but got: ”, x))
Which can't be optimized away by the compiler in release builds, you can now pass multiple args for a formatted message at no runtime cost:
debug_assert(x > 0, “expected x to be more than 0 but got: ”, x)
debug_assert(x > 0, “expected x to be more than 0 but got: ”, x)
Automatic parameterization of parameters is now supported. Specifying a parameterized type with unbound parameters causes them to be implicitly added to the function signature as infer-only parameters.
fn foo[value: SIMD[DType.int32, _]](): pass# Equivalent tofn foo[size: Int, //, value: SIMD[DType.int32, size]](): pass
fn foo[value: SIMD[DType.int32, _]](): pass# Equivalent tofn foo[size: Int, //, value: SIMD[DType.int32, size]](): pass
Mojo can now interpret simple LLVM intrinsics in parameter expressions, enabling things like
count_leading_zeros
to work at compile time: Issue #933.Introduced the
@explicit_destroy
annotation, the__disable_del
keyword, theUnknownDestructibility
trait, and theImplicitlyDestructible
keyword, for the experimental explicitly destroyed types feature.Added associated types; we can now have aliases like
alias T: AnyType
,alias N: Int
, etc. in a trait, and then specify them in structs that conform to that trait. For more information, see Associated aliases for generics.
Standard library changes
Introduced a new
Deque
(double-ended queue) collection type, based on a dynamically resizing circular buffer for efficient O(1) additions and removals at both ends as well as O(1) direct access to all elements.
The
Deque
supports the full Pythoncollections.deque
API, ensuring that all expected deque operations perform as in Python.
Enhancements to the standard Python API include
peek()
andpeekleft()
methods for non-destructive access to the last and first elements, and advanced constructor options (capacity
,min_capacity
, andshrink
) for customizing memory allocation and performance. These options allow for optimized memory usage and reduced buffer reallocations, providing flexibility based on application requirements.The
Formatter
struct has been replaced with aWriter
trait to enable buffered IO, increasing print and file writing perf to the same speed as C. It's now more general purpose and can write anySpan[Byte]
. To align with this theFormattable
trait is now namedWritable
, and theString.format_sequence()
static method to initialize a newString
has been renamed toString.write()
. Here's an example of using all of the changes:
from memory import Span@valuestruct NewString(Writer, Writable): var s: String # Writer requirement to write a Span of Bytes fn write_bytes(inout self, bytes: Span[Byte, _]): self.s._iadd[False](bytes) # Writer requirement to take multiple args fn write[*Ts: Writable](inout self, *args: *Ts): @parameter fn write_arg[T: Writable](arg: T): arg.write_to(self) args.each[write_arg]() # Also make it Writable to allow `print` to write the inner String fn write_to[W: Writer](self, inout writer: W): writer.write(self.s)@valuestruct Point(Writable): var x: Int var y: Int # Pass multiple args to the Writer. The Int and StringLiteral types call # `writer.write_bytes` in their own `write_to` implementations. fn write_to[W: Writer](self, inout writer: W): writer.write("Point(", self.x, ", ", self.y, ")") # Enable conversion to a String using `str(point)` fn __str__(self) -> String: return String.write(self)fn main(): var point = Point(1, 2) var new_string = NewString(str(point)) new_string.write("\n", Point(3, 4)) print(new_string)
from memory import Span@valuestruct NewString(Writer, Writable): var s: String # Writer requirement to write a Span of Bytes fn write_bytes(inout self, bytes: Span[Byte, _]): self.s._iadd[False](bytes) # Writer requirement to take multiple args fn write[*Ts: Writable](inout self, *args: *Ts): @parameter fn write_arg[T: Writable](arg: T): arg.write_to(self) args.each[write_arg]() # Also make it Writable to allow `print` to write the inner String fn write_to[W: Writer](self, inout writer: W): writer.write(self.s)@valuestruct Point(Writable): var x: Int var y: Int # Pass multiple args to the Writer. The Int and StringLiteral types call # `writer.write_bytes` in their own `write_to` implementations. fn write_to[W: Writer](self, inout writer: W): writer.write("Point(", self.x, ", ", self.y, ")") # Enable conversion to a String using `str(point)` fn __str__(self) -> String: return String.write(self)fn main(): var point = Point(1, 2) var new_string = NewString(str(point)) new_string.write("\n", Point(3, 4)) print(new_string)
Point(1, 2)Point(3, 4)
Point(1, 2)Point(3, 4)
Python interop changes:
Introduced
TypedPythonObject
as a light-weight way to annotatePythonObject
values with static type information. This design will likely evolve and change significantly.
Added
TypedPythonObject["Tuple].__getitem__()
for accessing the elements of a Python tuple.
Added
Python.add_object()
, to add a namedPythonObject
value to a Python 'module' object instance.Added
Python.unsafe_get_python_exception()
, as an efficient low-level utility to get the MojoError
equivalent of the current CPython error state.Add
PythonObject.from_borrowed_ptr()
, to simplify the construction ofPythonObject
values from CPython 'borrowed reference' pointers.
The existing
PythonObject.__init__(PyObjectPtr)
should continue to be used for the more common case of constructing aPythonObject
from a 'strong reference' pointer.Support for multi-dimensional indexing and slicing for
PythonObject
(PR #3549, PR #3583).
var np = Python.import_module("numpy")var a = np.array(PythonObject([1,2,3,4,5,6])).reshape(2,3)print((a[0, 1])) # 2print((a[1][::-1])) # [6 5 4]
var np = Python.import_module("numpy")var a = np.array(PythonObject([1,2,3,4,5,6])).reshape(2,3)print((a[0, 1])) # 2print((a[1][::-1])) # [6 5 4]
Note that the syntax,
a[1, ::-1]
, is currently not supported.Added
PythonObject.__contains__()
. (PR #3101)
Example usage:
x = PythonObject([1,2,3])if 1 in x: print("1 in x")
x = PythonObject([1,2,3])if 1 in x: print("1 in x")
Pointer related changes:
The
UnsafePointer
type now has anorigin
parameter that can be used when theUnsafePointer
points to a value with a known origin. This origin is propagated through theptr[]
indirection operation. This parameter and otherUnsafePointer
parameters (other than the type) are now keyword-only.You can now index into
UnsafePointer
usingSIMD
scalar integral types:
p = UnsafePointer[Int].alloc(1)i = UInt8(1)p[i] = 42print(p[i])
p = UnsafePointer[Int].alloc(1)i = UInt8(1)p[i] = 42print(p[i])
Added a new
OwnedPointer
type as a safe, single-owner, non-nullable smart pointer with similar semantics to Rust'sBox<>
and C++'sstd::unique_ptr
. (PR #3524)Arc
has been renamed toArcPointer
, for consistency withOwnedPointer
.ArcPointer
now implementsIdentifiable
, and can be compared for pointer equivalence usinga is b
.The
Reference
type has been renamed toPointer
: a memory safe complement toUnsafePointer
. This change is motivated by the fact thatPointer
is assignable and requires an explicit dereference withptr[]
. Renaming toPointer
clarifies that "references" meansref
arguments and results, and gives us a model that is more similar to what the C++ community would expect.
For an overview of Mojo's pointer types, see the new Intro to pointers page in the Mojo Manual.
A new
as_noalias_ptr()
method as been added toUnsafePointer
. This method specifies to the compiler that the resultant pointer is a distinct identifiable object that does not alias any other memory in the local scope.
Added the
Floatable
andFloatableRaising
traits to denote types that can be converted to aFloat64
value using the builtinfloat
function. MadeSIMD
andFloatLiteral
conform to theFloatable
trait. (PR #3163)
fn foo[F: Floatable](v: F): ...var f = float(Int32(45))
fn foo[F: Floatable](v: F): ...var f = float(Int32(45))
The
rebind()
standard library function now works with memory-only types in addition to@register_passable("trivial")
ones, without requiring a copy. For more information, see Therebind()
builtin in the Mojo Manual.Introduced the
random.shuffle()
function for randomizing the elements of aList
. (PR #3327)
Example:
from random import shufflevar l = List[Int](1, 2, 3, 4, 5)shuffle(l)
from random import shufflevar l = List[Int](1, 2, 3, 4, 5)shuffle(l)
The
Dict.__getitem__()
method now returns a reference instead of a copy of the value (or raises). This improves the performance of common code that usesDict
by allowing borrows from theDict
elements.Slice.step
is now anOptional[Int]
, matching the optionality ofslice.step
in Python. (PR #3160)There is now a
Byte
alias to better express intent when working with a pack of bits. (PR #3670).Expanded
os.path
with new functions:
Added a
reserve()
method and new constructor to theString
struct to allocate additional capacity. (PR #3755).A new
StringLiteral.get[some_stringable]()
method is available. It allows forming a runtime-constantStringLiteral
from a compile-time-dynamicStringable
value.Span
has moved from theutils
module to thememory
module.Span
now implements__reversed__()
. This means that one can get a reverse iterator over aSpan
usingreversed(my_span)
. Users should currently prefer this method overmy_span[::-1]
.A new
AsBytes
trait has been added to enable taking aSpan[Byte]
from any type that implementsas_bytes()
.String.as_bytes()
andString.as_bytes_slice()
have been consolidated underString.as_bytes()
to return aSpan[Byte]
. If you require a copy, you can convert theSpan
to aList
withList(my_string.as_bytes())
.StringSlice
now implementsstrip()
,rstrip()
, andlstrip()
.StringRef
now implementssplit()
which can be used to split aStringRef
into aList[StringRef]
by a delimiter. (PR #2705)StringRef
is now representable sorepr(StringRef("hello"))
will returnStringRef('hello')
.More things have been removed from the auto-exported set of entities in the
prelude
module from the Mojo standard library:
UnsafePointer
has been removed. Please explicitly import it viafrom memory import UnsafePointer
.StringRef
has been removed. Please explicitly import it viafrom utils import StringRef
.
Restored implicit copyability of
Tuple
andListLiteral
.The aliases for C foreign function interface (FFI) have been renamed:
C_int
->c_int
,C_long
->c_long
and so on.Float32
andFloat64
are now printed and converted to strings with roundtrip guarantee and shortest representation:
Value Old NewFloat64(0.3) 0.29999999999999999 0.3Float32(0.3) 0.30000001192092896 0.3Float64(0.0001) 0.0001 0.0001Float32(0.0001) 9.9999997473787516e-05 0.0001Float64(-0.00001) -1.0000000000000001e-05 -1e-05Float32(-0.00001) -9.9999997473787516e-06 -1e-05Float32(0.00001234) 1.2339999557298142e-05 1.234e-05Float32(-0.00000123456) -1.2345600453045336e-06 -1.23456e-06Float64(1.1234567e-320) 1.1235052786429946e-320 1.1235e-320Float64(1.234 * 10**16) 12340000000000000.0 1.234e+16
Value Old NewFloat64(0.3) 0.29999999999999999 0.3Float32(0.3) 0.30000001192092896 0.3Float64(0.0001) 0.0001 0.0001Float32(0.0001) 9.9999997473787516e-05 0.0001Float64(-0.00001) -1.0000000000000001e-05 -1e-05Float32(-0.00001) -9.9999997473787516e-06 -1e-05Float32(0.00001234) 1.2339999557298142e-05 1.234e-05Float32(-0.00000123456) -1.2345600453045336e-06 -1.23456e-06Float64(1.1234567e-320) 1.1235052786429946e-320 1.1235e-320Float64(1.234 * 10**16) 12340000000000000.0 1.234e+16
The
StaticIntTuple
data structure in theutils
package has been renamed toIndexList
. The data structure now allows one to specify the index bitwidth of the elements along with whether the underlying indices are signed or unsigned.Added
DLHandle.get_symbol()
, for getting a pointer to a symbol in a dynamic library. This is more general purpose than the existing methods for getting function pointers.
Tooling changes
The VS Code Mojo Debugger now has a
buildArgs
JSON debug configuration setting that can be used in conjunction withmojoFile
to define the build arguments when compiling the Mojo file.The VS Code extension now supports a
Configure Build and Run Args
command that helps set the build and run args for actions fileRun Mojo File
andDebug Mojo File
. A corresponding button appears inRun and Debug
selector in the top right corner of a Mojo File.The VS Code extension now has the
mojo.run.focusOnTerminalAfterLaunch
setting, which controls whether to focus on the terminal used by theMojo: Run Mojo File
command or on the editor after launch. Issue #3532.The VS Code extension now has the
mojo.SDK.additionalSDKs
setting, which allows the user to provide a list of MAX SDKs that the extension can use when determining a default SDK to use. The user can select the default SDK to use with theMojo: Select the default MAX SDK
command.The VS Code extension now supports setting data breakpoints as well as function breakpoints.
The Mojo LLDB debugger now supports symbol breakpoints, for example,
b main
orb my_module::main
.Error messages that include type names no longer include inferred or defaulted parameters when they aren't needed. For example, previously Mojo complained about things like:
... cannot be converted from 'UnsafePointer[UInt, 0, _default_alignment::AnyType](), MutableAnyOrigin]' to 'UnsafePointer[Int, 0, _default_alignment[::AnyType](), MutableAnyOrigin]'
... cannot be converted from 'UnsafePointer[UInt, 0, _default_alignment::AnyType](), MutableAnyOrigin]' to 'UnsafePointer[Int, 0, _default_alignment[::AnyType](), MutableAnyOrigin]'
it now complains more helpfully that:
... cannot be converted from 'UnsafePointer[UInt]' to 'UnsafePointer[Int]'
... cannot be converted from 'UnsafePointer[UInt]' to 'UnsafePointer[Int]'
Tooling now prints the origins of
ref
arguments and results correctly, and printsself
instead ofself: Self
in methods.The Mojo Language Server and generated documentation now print parametric result types correctly, e.g. showing
SIMD[type, simd_width]
instead ofSIMD[$0, $1]
.Generated API documentation now shows the signatures for structs, and identifies
@register_passable
and@register_passable("trivial")
types.The VS Code extension now allows cancelling the installation of its private MAX SDK.
The VS Code extension now opens the Run and Debug tab automatically whenever a debug session starts.
The
mojo debug --vscode
command now support the--init-command
and--stop-on-entry
flags. Executemojo debug --help
for more information.The Mojo LLDB debugger on VS Code now supports inspecting the raw attributes of variables that are handled as synthetic types, e.g.
List
from Mojo orstd::vector
from C++.The VS Code extension now allows selecting a default SDK when multiple are available.
Removed
- The
UnsafePointer.bitcast()
overload forDType
has been removed. Wrap yourDType
in aScalar[my_dtype]
to call the only overload ofbitcast()
now.
Fixed
Lifetime tracking is now fully field sensitive, which makes the uninitialized variable checker more precise.
Issue #1310 - Mojo permits the use of any constructor for implicit conversions
Issue #1632 - Mojo produces weird error when inout function is used in non mutating function
Issue #3444 - Raising init causing use of uninitialized variable
Issue #3544 - Known mutable
ref
argument are not optimized asnoalias
by LLVM.Issue #3559 - VariadicPack doesn't extend the lifetimes of the values it references.
Issue #3627 - Compiler overlooked exclusivity violation caused by
ref [MutableAnyOrigin] T
Issue #3710 - Mojo frees memory while reference to it is still in use.
Issue #3805 - Crash When Initializing !llvm.ptr.
Issue #3816 - Ternary if-operator doesn't propagate origin information.
Issue #3815 - [BUG] Mutability not preserved when taking the union of two origins.
Issue #3829 - Poor error message when invoking a function pointer upon an argument of the wrong origin
Issue #3830 - Failures emitting register RValues to ref arguments.
The VS Code extension now auto-updates its private copy of the MAX SDK.
The variadic initializer for
SIMD
now works in parameter expressions.The VS Code extension now downloads its private copy of the MAX SDK in a way that prevents
ETXTBSY
errors on Linux.The VS Code extension now allows invoking a mojo formatter from SDK installations that contain white spaces in their path.
Special thanks
Special thanks to our community contributors: @soraos, @jjvraw, @bgreni, @thatstoasty, @szbergeron, @rd4com, @fknfilewalker, @gabrieldemarmiesse, @avitkauskas, and @martinvuyk.