Skip to content

Releases: ponylang/ponyc

0.44.0

03 Sep 02:59
Compare
Choose a tag to compare

Fixed a compile-time crash related to Pony-specific optimizations

Ticket #3784 tracked an issue related the MergeMessageSend optimization pass, which does Pony-specific optimizations within the LLVM optimizer pipeline.

It turned out that this pass was not written to handle the case of being run on a code block that contained sections of code that had already been optimized by this pass, and in such a case it failed an assertion error, crashing the compiler on such a program.

The fix was to disable running the pass on blocks in which we could detect signs of the optimization of that pass already being present.

Programs that were previously compiling okay should not see any difference in behavior or performance - the only programs that could potentially benefit from the skipped optimization were crashing, so there is no regression in their behavior.

Split FilePath construction into two methods

FilePath previously had only one constructor, the default create, which used a union of (AmbientAuth | FilePath). The first half of this union AmbientAuth could never error, while the second FilePath could error. By splitting construction into two methods, we now have a default create constructor which cannot error and a new from constructor which can error. The default create constructor now accepts a new "files" package root authority FileAuth as well as the global root authority AmbientAuth, while the new from constructor uses FilePath.

The result of this change is that three user changes are needed, namely around create, from, and mkdtemp. Any place where previously AmbientAuth was accepted now also accepts FileAuth.

Prior to this change, create could be used with AmbientAuth as in:

let ambient: AmbientAuth = ...
let filepath: FilePath = FilePath(ambient, path)?

After this change, create can be used with AmbientAuth or FileAuth -- note that this can no longer fail:

let ambient: AmbientAuth = ...
let filepath: FilePath = FilePath(ambient, path)

or

let fileauth: FileAuth = ...
let filepath: FilePath = FilePath(fileauth, path)

Prior to this change, create could be used with FilePath as in:

let filepath: FilePath = ...
let subpath = FilePath(filepath, path)?

After this change, construction with an existing FilePath must use from:

let filepath: FilePath = ...
let subpath = FilePath.from(filepath, path)?

Prior to this change, mkdtemp could be used with AmbientAuth or FilePath as in:

let ambient: AmbientAuth = ...
let tempdir = FilePath.mkdtemp(ambient, prefix)?

or

let filepath: FilePath = ...
let tempdir = FilePath.mkdtemp(filepath, prefix)?

After this change, mkdtemp can also use FileAuth -- note can still fail:

let fileauth: FileAuth = ...
let tempdir = FilePath.mkdtemp(fileauth, prefix)?

[0.44.0] - 2021-09-03

Fixed

  • Fix a compile-time crash related to Pony-specific optimizations. (PR #3831)

Changed

  • Update FilePath constructors to allow a non-partial way to create a FilePath (PR #3819)

0.43.2

28 Aug 12:59
Compare
Choose a tag to compare

Clean up child process exits on Windows

Fixed the ProcessMonitor class sometimes waiting on an invalid process handle on Windows.

Fixed Windows TCP faulty connection error

Fixed a bug where a TCPConnection could connect to a socket that wasn't listening.

Fixed zombie Windows TCP connection error

Fixed a bug where socket events were sometimes never unsubscribed to which would lead to "zombie" connections that were open but couldn't receive data.

Fixed "oversleeping" on Windows

Previously, we were calling Sleep rather than SleepEx when putting scheduler threads to sleep. This could have caused Windows IO events to be missed.

Fix broken libponyc-standalone.a

When we switched to LLVM 12, we accidentally picked up zlib being required to link against libponyc-standalone.a. That additional dependency makes the standalone library not so standalone.

We've fixed our LLVM configuration so that zlib is no longer needed.

[0.43.2] - 2021-08-28

Fixed

  • Clean up child process exits on Windows (PR #3817)
  • Cleanup and fixes for Windows sockets (PR #3816)
  • Stop standalone libponyc from needing zlib (PR #3827)

0.43.1

03 Aug 02:23
Compare
Choose a tag to compare

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

Added

0.43.0

14 Jul 19:53
Compare
Choose a tag to compare

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

0.42.0

07 Jul 13:34
Compare
Choose a tag to compare

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

29 Jun 18:25
Compare
Choose a tag to compare

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

  • Fix "iftype" expressions not being usable in lambdas or object literals (PR #3763)
  • Fix code generation for variadic FFI functions on arm64 (PR #3768)

0.41.1

22 May 11:38
Compare
Choose a tag to compare

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

07 May 12:47
Compare
Choose a tag to compare

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

  • Improve error message for match on structs (PR #3746)
  • RFC 68: Mandatory FFI declarations (PR #3739)
  • Change return type of String.add to String iso^ (PR #3752)
  • Improve error message on destructuring of non-tuple types (PR #3753)

0.40.0

01 May 00:18
Compare
Choose a tag to compare

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 to math package (PR #3738)

Changed

  • Change supported FreeBSD to 13.0 (PR #3743)

0.39.1

29 Mar 17:45
Compare
Choose a tag to compare

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

  • Fix compiler crash related to type parameter references (PR #3725)
  • Fix early pipe shutdown with Windows ProcessMonitor (PR #3726)
  • Fix literal inference through partial function (PR #3729)