Releases: ponylang/ponyc
0.43.1
Fixed compiler build issues on FreeBSD host
Added relevant include and lib search paths under /usr/local
prefix on FreeBSD, to satisfy build dependencies for Pony compiler.
Add FileMode.u32
Adds a public method on FileMode to get an OS-specific representation of the FileMode as a u32.
Make working with Promise[Promise[B]] chains easier
We've added a new method flatten_next
to Promise
in order to make working with promises of promises easier.
flatten_next
is a companion to next
. It operates in an identical fashion except for the type of the fulfilled promise. Whereas next
takes a function that returns a type B
, flatten_next
takes a function that returns Promise[B]
.
Why is flatten_next
valuable given that next could take a B
that is of a type like Promise[String]
? Let's start with some code to demonstrate the problem that arises when returning Promise[Promise[B]]
from next
.
Let's say we have a library for accessing the GitHub REST API:
class GitHub
new create(personal_access_token: String)
fun get_repo(repo: String): Promise[Repository]
class Repository
fun get_issue(number: I64): Promise[Issue]
class Issue
fun title(): String
And we want to use this promise based API to look up the title of an issue. Without flatten_next
, we could attempt to do the following using next
:
actor Main
new create(env: Env) =>
let repo: Promise[Repository] =
GitHub("my token").get_repo("ponylang/ponyc")
//
// do something with the repo once the promise is fulfilled
// in our case, get the issue
//
let issue = Promise[Promise[Issue]] =
repo.next[Promise[Issue]](FetchIssue~apply(1))
// once we get the issue, print the title
issue.next[None](PrintIssueTitle~apply(env.out))
primitive FetchIssue
fun apply(number: I64, repo: Repository): Promise[Issue] =>
repo.get_issue(number)
primitive PrintIssueTitle
fun apply(out: OutStream, issue: Promise[Issue]) =>
// O NO! We can't print the title
// We don't have an issue, we have a promise for an issue
Take a look at what happens in the example, when we get to PrintIssueTitle
, we can't print anything because we "don't have anything". In order to print the issue title, we need an Issue
not a Promise[Issue]
.
We could solve this by doing something like this:
primitive PrintIssueTitle
fun apply(out: OutStream, issue: Promise[Issue]) =>
issue.next[None](ActuallyPrintIssueTitle~apply(out))
primitive ActuallyPrintIssueTitle
fun apply(out: OutStream, issue: Issue) =>
out.print(issue.title())
That will work, however, it is kind of awful. When looking at:
let repo: Promise[Repository] =
GitHub("my token").get_repo("ponylang/ponyc")
let issue = Promise[Promise[Issue]] =
repo.next[Promise[Issue]](FetchIssue~apply(1))
issue.next[None](PrintIssueTitle~apply(env.out))
it can be hard to follow what is going on. We can only tell what is happening because we gave PrintIssueTitle
a very misleading name; it doesn't print an issue title.
flatten_next
addresses the problem of "we want the Issue
, not the intermediate Promise
". flatten_next
takes an intermediate promise and unwraps it into the fulfilled type. You get to write your promise chain without having to worry about intermediate promises.
Updated to use flatten_next
, our API example becomes:
actor Main
new create(env: Env) =>
let repo: Promise[Repository] =
GitHub("my token").get_repo("ponylang/ponyc")
let issue = Promise[Issue] =
repo.flatten_next[Issue](FetchIssue~apply(1))
issue.next[None](PrintIssueTitle~apply(env.out))
primitive FetchIssue
fun apply(number: I64, repo: Repository): Promise[Issue] =>
repo.get_issue(number)
primitive PrintIssueTitle
fun apply(out: OutStream, issue: Issue) =>
out.print(issue.title())
Our promise Issue
, is no longer a Promise[Promise[Issue]]
. By using flatten_next
, we have a much more manageable Promise[Issue]
instead.
Other than unwrapping promises for you, flatten_next
otherwise acts the same as next
so all the same rules apply to fulfillment and rejection.
[0.43.1] - 2021-08-03
Fixed
- Fixed Makefile for FreeBSD (PR #3808)
Added
0.43.0
Add prebuilt ponyc binaries for Rocky Linux 8
Prebuilt nightly versions of ponyc are now available from our Cloudsmith nightlies repo. Release versions will be available in the release repo starting with this release.
CentOS 8 releases were added as we currently support CentOS 8, but it will be discontinued in a few months and Rocky Linux provides a seamless transition path.
If you are a Pony user and are looking for prebuilt releases for your distribution, open an issue and let us know. We'll do our best to add support for any Linux distribution version that is still supported by their creators.
Fix OOM error when running ponyc built with xcode 12.5
Changes in Big Sur and xcode as of 12.5 have lead to an out of memory error with ponyc. If pony's allocator is built with usage of VM_FLAGS_SUPERPAGE_SIZE_ANY on, it will run out of memory if xcode 12.5 was used to build.
VM_FLAGS_SUPERPAGE_SIZE_ANY isn't required on earlier versions. It does however, improve performance when allocating. Usage of VM_FLAGS_SUPERPAGE_SIZE_ANY has been removed as it also doesn't work on newer M1 based machines and thus, is on its way out in general.
Fix API mismatch errors when linking pony programs on MacOS
We have been setting a minimal API version for ponyc that didn't match the LLVM value. This resulted in errors about how the link versions didn't match. The warnings caused no issues running programs, but did lead to confusion amongst new users. They were also annoying to look at all the time.
We did some testing and determined that there's no need to set the value as we can build ponyc and other pony programs on Big Sur and still use on earlier versions of MacOS.
There might be some issues that crop up in the future, but as far as we can tell, for normal ponyc MacOS usage, we dont need to set macosx-version-min
.
Fix broken IsPrime
standard library feature
Any prime after 1321 wasn't being correctly identified.
Prevent non-opaque structs from being used as behaviour parameters
When a non-opaque object is sent across actors, its type descriptor is used by the garbage collector in order to trace it. Since structs lack a type descriptor, using a val
or iso
struct as a parameter behaviour could lead to a runtime segfault. This also applies to tuple parameters where at least one element is a non-opaque struct.
This is a breaking change. Existing code will need to wrap struct parameters in classes or structs, or use structs with a tag
capability. Where you previously had code like:
struct Foo
actor Main
new create(env: Env) =>
inspect(recover Foo end)
be inspect(f: Foo iso) =>
// Do something with f
you will now need
struct Foo
class Bar
let f: Foo = Foo
actor Main
new create(env: Env) =>
inspect(recover Bar end)
be inspect(wrap: Bar iso) =>
// Do something with wrap.f
When using tuples with struct elements, you don't need to wrap the entire tuple. It is enough to wrap the struct elements.
Update to LLVM 12.0.1
We've updated the LLVM used to build pony to LLVM 12.0.1 and in the process, we've dropped support for 32-bit ARM as supported platform.
We might bring 32-bit Arm back as a supported platform if the Arm fixes we need to do to get ponyc working on M1 also fix the current issues we have with 32-bit Arm with LLVM 12. The errors currently present the same so we assume that adding M1 support will bring 32-bit ARM along with it. If fixing the M1 issues doesn't fix 32-bit Arm issues then we'll have to make a decision about whether we bring back 32-bit Arm support.
[0.43.0] - 2021-07-14
Fixed
- Fix OOM on MacOS when using xcode 12.5 (PR #3793)
- Fix MacOS version mismatch warnings when linking Pony programs (PR #3798)
- Fix the calculation of "is prime" for numbers after 1321. (PR #3799)
- Prevent non-opaque structs from being used as behaviour parameters (PR #3781)
Added
- Add support for prebuilt Rocky Linux versions (PR #3783)
Changed
- Update to LLVM 12.0.1 (PR #3745)
0.42.0
Fix bug where Flags.remove could set flags in addition to unsetting them
Flags.remove when given a flag to remove that wasn't currently present in the set, would turn the flag on.
It should only be turning flags off, not turning them on.
Allow Flags instances to be created with a set bit encoding
Extending Flags.create to (optionally) allow initialization of a Flags
object with the numeric representation populated. This value defaults
to 0 (no flags set).
Don't allow PONYPATH to override standard library
Prior to this change, a library could contain a package called builtin
that would override to standard library version. This could be an attack vector. You can still override the standard library location by using the ponyc --paths
option.
Any code which relied on the PONYPATH items being before the standard library in the package search path will need to switch to using --paths
on the ponyc command line.
[0.42.0] - 2021-07-07
Fixed
- Fix bug where Flags.remove could set flags in addition to unsetting them (PR #3777)
Added
- Allow Flags instances to be created with a set bit encoding (PR #3778)
Changed
- Don't allow PONYPATH to override standard library (PR #3780)
0.41.2
Fix "iftype" expressions not being usable in lambdas or object literals
This release fixes an issue where the compiler would hit an assertion error when compiling programs that placed iftype
expressions inside lambdas or object literals.
Fix code generation for variadic FFI functions on arm64
This release fixes an issue with code generation of variadic functions on arm64 architectures. The arm64 calling convention specifies that the named arguments of a variadic function (those arguments that are not optional) must be placed on registers, or on the stack if there are no available registers. Anonymous arguments (those that are optional) must always be placed on the stack. The Pony compiler would treat all variadic functions as if all their arguments were anonymous, thus placing every argument on the stack, even if there were available registers. This would cause issues on the C side of a variadic function, as programs would try and read from registers first, potentially finding uninitialized values.
[0.41.2] - 2021-06-29
Fixed
0.41.1
Fix type constraint check against NullablePointer being omitted in FFI declarations
This release fixes an issue where the compiler would not perform some type checks against FFI declarations. Specifically, the compiler would fail to validate that the type parameter to the NullablePointer
type had to be a struct type. This check is important since a program that used a non-struct type in a NullablePointer
could theoretically segfault at runtime.
[0.41.1] - 2021-05-22
Fixed
- Fix NullablePointer type constraint check being omitted in FFI declarations (PR #3758)
0.41.0
Fix unsound checks for return subtyping
Changed the subtyping model used in the compiler,
fixing some unsound cases that were allowed for function returns.
This also will result in changed error messages, with more
instances of unaliasing instead of aliasing. The tutorial has
been updated with these changes.
This is a breaking change, as some code which used to be accepted
by the typechecker is now rejected. This could include sound code
which was not technically type-safe, as well as unsound code.
This code used to be erroneously allowed and is now rejected
(it would allow a val and an iso to alias):
class Foo
let x: Bar iso = Bar
fun get_bad(): Bar val =>
x
In addition, the standard library Map class now has a weaker
type signature as it could not implement its current type signature.
The upsert
and insert_if_absent
methods now return T! instead of T
Improve error messages when matching on struct types
A struct type doesn't have a type descriptor, which means that they cannot be used in match or "as" statements. Before this change, the compiler would incorrectly warn that matching against a struct wasn't possible due to a violation of capabilities, which was confusing. With this release, the compiler will now show a more helpful error message, explicitly mentioning that struct types can't be used in union types.
As an example, the following piece of Pony code:
struct Rect
actor Main
new create(env: Env) =>
let a: (Rect | None) = None
match a
| let a': Rect => None
| None => None
end
would fail to compile on ponyc 0.40.0 with the following error message:
Error:
main.pony:7:7: this capture violates capabilities, because the match would need to differentiate by capability at runtime instead of matching on type alone
| let a': Rect => None
^
Info:
main.pony:5:18: the match type allows for more than one possibility with the same type as pattern type, but different capabilities. match type: (Rect ref | None val)
let a: (Rect | None) = None
^
main.pony:7:7: pattern type: Rect ref
| let a': Rect => None
^
main.pony:7:15: matching (Rect ref | None val) with Rect ref could violate capabilities
| let a': Rect => None
^
Starting with this release, the error message is:
Error:
main.pony:7:7: this capture cannot match, since the type Rect ref is a struct and lacks a type descriptor
| let a': Rect => None
^
Info:
main.pony:5:18: a struct cannot be part of a union type. match type: (Rect ref | None val)
let a: (Rect | None) = None
^
main.pony:7:7: pattern type: Rect ref
| let a': Rect => None
^
main.pony:7:15: matching (Rect ref | None val) with Rect ref is not possible, since a struct lacks a type descriptor
| let a': Rect => None
^
Make FFI declarations mandatory (RFC 68)
This release introduces a breaking change for code that uses the C-FFI (Foreign Function Interface). It is now mandatory to declare all FFI functions via use
statements. In addition, it is now a syntax error to specify the return type of an FFI function at the call site. The tutorial has been updated with these changes.
Where you previously had code like:
let ptr = @pony_alloc[Pointer[U8]](@pony_ctx[Pointer[None]](), USize(8))
Array[U8].from_cpointer(ptr, USize(8))
you now need
// At the beginning of the file
use @pony_ctx[Pointer[None]]()
use @pony_alloc[Pointer[U8]](ctx: Pointer[None], size: USize)
// ...
let ptr = @pony_alloc(@pony_ctx(), USize(8))
Array[U8].from_cpointer(ptr, USize(8))
If you're calling a C function with a variable number of arguments (like printf
), use ...
at the end of the declaration:
use @printf[I32](fmt: Pointer[U8] tag, ...)
// ...
@printf("One argument\n".cpointer())
@printf("Two arguments: %u\n".cpointer(), U32(10))
@printf("Three arguments: %u and %s\n".cpointer(), U32(10), "string".cpointer())
FFI declarations are visible to an entire package, so you don't need to add type signatures to all Pony files.
Change the return type of String.add to String iso^ (RFC 69)
This release introduces a breaking change by changing the return type of String.add
from String val
to String iso^
.
Where you previously had code like:
let c = Circle
let str = "Radius: " + c.get_radius().string() + "\n"
env.out.print(str)
you now need:
let c = Circle
let str = recover val "Radius: " + c.get_radius().string() + "\n" end
env.out.print(str)
or you can also let the compiler do the work for you by using explicit type declarations:
let c = Circle
let str: String = "Radius: " + c.get_radius().string() + "\n"
env.out.print(str)
The above code works since val
is the default reference capability of the String
type.
The new type makes it simpler to implement the Stringable
interface by using String.add
. Where before you had code like:
class MyClass is Stringable
let var1: String = "hello"
let var2: String = " world"
fun string(): String iso^ =>
recover
String.create(var1.size() + var1.size())
.>append(var1)
.>append(var2)
end
you can now implement the string
method as such:
class MyClass is Stringable
let var1: String = "hello"
let var2: String = " world"
fun string(): String iso^ =>
var1 + var2
Improve error message when attempting to destructure non-tuple types
Sometimes, the compiler will infer that the return type of an expression is an union or an intersection of multiple types. If the user tries to destructure such result into a tuple, the compiler will emit an error, but it won't show the user what the inferred type is. This could be confusing to users, as they wouldn't know what went wrong with the code, unless they added explicit type annotations to the assigned variables.
Starting with this release, the compiler will now show what the inferred type is, so that the user can spot the problem without needing to explicitly annotate their code.
As an example, the following piece of Pony code:
actor Main
new create(env: Env) =>
(let str, let size) =
if true then
let str' = String(5) .> append("hello")
(str', USize(5))
else
("world", USize(5))
end
would fail to compile on previous releases with the following error message:
Error:
main.pony:3:25: can't destructure a union using assignment, use pattern matching instead
(let str, let size) =
^
Starting with this release, the error message will show the inferred type of the expression:
Error:
main.pony:3:25: can't destructure a union using assignment, use pattern matching instead
(let str, let size) =
^
Info:
main.pony:4:7: inferred type of expression: ((String ref, USize val^) | (String val, USize val^))
if true then
^
Fix memory corruption of chopped Arrays and Strings
With the introduction of chop
on Array
and String
a few years ago, a constraint for the memory allocator was violated. This resulted in an optimization in the realloc code of the allocator no longer being safe.
Prior to this fix, the following code would print cats
and sog
. After the fix, it doesn't corrupt memory and correctly prints cats
and dog
.
actor Main
new create(env: Env) =>
let catdog = "catdog".clone().iso_array()
(let cat, let dog) = (consume catdog).chop(3)
cat.push('s')
env.out.print(consume cat)
env.out.print(consume dog)
[0.41.0] - 2021-05-07
Fixed
- Change to Steed's model of subtyping (PR #3643)
- Fix memory corruption with Array.chop and String.chop (PR #3755)
Changed
0.40.0
Add IsPrime
to math
package
Quickly determine if a given number is prime using the 6k ± 1 method.
All integers (excluding 2 and 3), can be expressed as (6k + i), where i = -1, 0, 1, 2, 3, or 4. Since 2 divides (6k + 0), (6k + 2), and (6k + 4), while 3 divides (6k + 3) that leaves only (6k - 1) and (6k + 1) for expressing primes
Fix possible memory leak
A possible memory leak in the process package was fixed.
Update supported FreeBSD to FreeBSD 13.0
As of this release, we now do all FreeBSD testing on FreeBSD 13.0 and all ponyc prebuilt packages are built on FreeBSD 13.0. We will make a best effort to not break prior versions of FreeBSD while they are "supported".
[0.40.0] - 2021-05-01
Fixed
- Use built-in offset argument to cpointer (PR #3741)
Added
- Add
IsPrime
checker tomath
package (PR #3738)
Changed
- Change supported FreeBSD to 13.0 (PR #3743)
0.39.1
Fix compiler crash related to type parameter references
Previously, if a method signature in a trait or interface referenced a type
parameter before the type parameter itself was defined, the compiler would
crash. This is now fixed.
Fix early pipe shutdown with Windows' ProcessMonitor
Due to incorrect handling of a Windows pipe return value, the ProcessMonitor would sometimes shut down its pipe connections to external processes before it should have.
Fix literal inference with partial functions
Before this change, code such as 1~add(2)
would hit an assertion error when the compiler tried to infer the type of the literal 2
. The compiler tries to find the type of the receiver of the function (in this case 1
), but before it lacked the ability to do so when using partial functions. In those cases, the compiler would try to look at the type of the ~
token, which is not a valid value literal, and as such it would fail.
[0.39.1] - 2021-03-29
Fixed
0.39.0
Fix calculating the number of CPU cores on FreeBSD/DragonFly
The number of CPU cores is used by Pony to limit the number of scheduler threads (--ponymaxthreads
) and also used as the default number of scheduler threads.
Previously, sysctl hw.ncpu
was incorrectly used to determine the number of CPU cores on FreeBSD and DragonFly. On both systems sysctl hw.ncpu
reports the number of logical CPUs (hyperthreads) and NOT the number of physical CPU cores.
This has been fixed to use kern.smp.cores
on FreeBSD and hw.cpu_topology_core_ids
* hw.cpu_topology_phys_ids
on DragonFly to correctly determine the number of physical CPU cores.
This change only affects FreeBSD and DragonFly systems with hardware that support hyperthreading. For instance, on a 4-core system with 2-way HT, previously 8 scheduler threads would be used by default. After this change, the number of scheduler threads on the same system is limited to 4 (one per CPU core).
Change supported FreeBSD version to 12.2
We only maintain support for a single version of FreeBSD at a time due to limited usage of Pony of FreeBSD. We've switched from testing and building releases for 12.1 to 12.2, We would have done this sooner, but we hadn't noticed that 12.2 had been released.
Fix FFI declarations ignoring partial annotation
Previously, the compiler would ignore any ?
annotations on FFI declarations, which could result in the generated code lacking any guards for errors, causing the final program to abort at runtime. This change fixes the problem by ensuring that the compiler checks if FFI declarations specify a partial annotation.
Fix building ponyc on DragonFly BSD
DragonFly BSD is lightly used as a ponyc platform. It is also "unsupported" due to lack of CI. Over time, ponyc fell out of being able to be built on DragonFly.
As of this release, you should be able to use ponyc on DragonFly again. However, do to the unsupported nature of the DragonFly port, it might break again in which case, updates from anyone using Pony on DragonFly will be needed.
Create a standalone libponyc on Linux
It's possible to use libponyc from projects other than ponyc. Using the library gives you access to all the various compiler functionality. However, it is hard to use the library because, you need to link in the correct libstdc++, libblake, and LLVM. Figuring out what is the correct version of each is very difficult.
With this change, a new library libponyc-standalone.a
will be created as part of the build process.
Applications like the "in pony documentation generator" that we are working on will be able to link to libponyc-standalone and pick up all it's required dependencies.
Windows, BSD, and macOS libraries are not created at this time but can be added as needed in the future.
Fix symbol table patching for default implementations that replaces another method
This release fixes a compiler crash that could happen when a default implementation replaced another method with the same signature. An example of this is when intersecting two interfaces that both have a method with the same signature and the second interface provides a default implementation:
interface A
fun f(): U32
interface B
fun f(): U32 =>
let x: U32 = 42
x
interface C is (A & B)
In this case, the default implementation was copied to C
, but without its symbol table, subsequently resulting in a compiler crash.
Fix tuple related compiler segfaults
Andreas Stührk indentified and fixed the source of two different open issues with tuple handling that caused the pony compiler to crash.
[0.39.0] - 2021-02-27
Fixed
- Fix calculation of # CPU cores (FreeBSD/DragonFly) (PR #3707)
- Fix partial FFI declarations ignoring partial annotation (PR #3713)
- Fix building ponyc on DragonFly BSD (PR #3676)
- Fix symbol table patching for overriding default methods (PR #3719)
- Fix tuple related compiler segfaults (PR #3723)
Added
- Create a standalone libponyc on Linux (PR #3716)
Changed
- Update supported FreeBSD to 12.2 (PR #3706)
0.38.3
Fix memory safety problem with Array.from_cpointer
Previously, the from_cpointer
method in arrays would trust the user to pass a valid pointer. This created an issue where the user could pass a null pointer using Pointer.create
, leading to a situation where memory safety could be violated by trying to access an element of the array. This change makes it safe to pass a null pointer to from_cpointer
, which will create a zero-length array.
Fix bad package names in generated documentation
Previously when you used ponyc's documentation generation functions on a code base that used relative imports like use "../foo"
, the package name in the generated documentation would be incorrect.