ponylang / ponyc

Pony is an open-source, actor-model, capabilities-secure, high performance programming language
http://www.ponylang.io
BSD 2-Clause "Simplified" License
5.73k stars 415 forks source link

Tuple literals not matching correctly #2227

Open sgebbie opened 7 years ago

sgebbie commented 7 years ago

Summary

While trying to build a simple "event sourcing" style application I ran into problems with tuple matching.

Essentially if I build a tuple as a literal:

    let cc: Change = ((0,0), "bob", Dependency, (Link, "123"))

then the subsequent match matches incorrectly (not just a failed match but an incorrect match).

While, if I build the same tuple in two steps:

    let vv: DependencyOp = (Link, "123")
    let cc: Change = ((0,0), "bob", Dependency, vv)

The ponyc version is: 0.19.0-cf45938 [release]

Example Code

Bellow is a pared down version of my code that includes just the enough of the types in order to be able to trigger the problem. Note if Change has only the DependencyOp command in its type definition (versus including the NOP command) then the problem goes away and the tests succeed.

cat _test_tuples.pony

use "pony_test"
use "collections"

// -- types

type TimeStamp is (I64, I64)
type Principal is String

primitive NOP
primitive Dependency

primitive Link
primitive Unlink
primitive Spawn

type ID is String

type DependencyOp is ((Link, ID) | (Unlink, ID) | Spawn)

type Change is (
    //  when        principal   aspect       value
      ( TimeStamp , Principal , NOP        , None           ) // <-- needed in order to trigger the bug
    | ( TimeStamp , Principal , Dependency , DependencyOp   )
    // ... other journal command types
)

// -- tests

actor Main is TestList

  new create(env: Env) =>
    PonyTest(env, this)

  new make() =>
    None

  fun tag tests(test: PonyTest) =>
        test(_TestTupleNestLiteral)
        test(_TestTupleNestConstructed)

// --

class iso _TestTupleNestLiteral is UnitTest
    fun name(): String => "tuplenest:literal"

    fun ref apply(h: TestHelper) =>
        // building the Change using the following literal tuple does _not_ matche correctly
        let cc: Change = ((0,0), "bob", Dependency, (Link, "123"))
        CheckChange.check(cc,h)

class iso _TestTupleNestConstructed is UnitTest
    fun name(): String => "tuplenest:constructed"

    fun ref apply(h: TestHelper) =>
        // building the Change using the following construction matches correctly
        let vv: DependencyOp = (Link, "123")
        let cc: Change = ((0,0), "bob", Dependency, vv)
        CheckChange.check(cc,h)

primitive CheckChange
    fun check(cc: Change, h: TestHelper) =>
        match(cc)
        | ( let t: TimeStamp , let p: Principal, let a: Dependency, let v: DependencyOp ) =>
            match (v)
            | (Link, let vw: ID)    => h.complete(true)
            | (Unlink, let vw: ID)  => h.fail("expected link - got unlink")
            | (Spawn)       => h.fail("expected link - got spawn")
            end
        else
            h.fail("didn't match outer")
        end

Example Output

130 09:57 stewart@flatfoot:~/opt/pony/bugs/tuple-literal$ export PONYC=~/opt/pony/bleed/build/release/ponyc; ${PONYC} -d; ./tuple-literal ; ${PONYC} -v 
Building builtin -> /home/stewart/opt/pony/bleed/packages/builtin
Building . -> /home/stewart/opt/pony/bugs/tuple-literal
Building ponytest -> /home/stewart/opt/pony/bleed/packages/ponytest
Building time -> /home/stewart/opt/pony/bleed/packages/time
Building collections -> /home/stewart/opt/pony/bleed/packages/collections
Generating
 Reachability
 Selector painting
 Data prototypes
 Data types
 Function prototypes
 Functions
 Descriptors
Writing ./tuple-literal.o
Linking ./tuple-literal
Warning: environment variable $CC undefined, using cc as the linker
1 test started, 0 complete: tuplenest:literal started
2 tests started, 0 complete: tuplenest:constructed started
2 tests started, 1 complete: tuplenest:literal complete
2 tests started, 2 complete: tuplenest:constructed complete
**** FAILED: tuplenest:literal
expected link - got spawn
---- Passed: tuplenest:constructed
----
---- 2 tests ran.
---- Passed: 1
**** FAILED: 1 test, listed below:
**** FAILED: tuplenest:literal
0.19.0-cf45938 [release]
compiled with: llvm 3.9.1 -- cc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
jemc commented 7 years ago

At first glance, I think this might be a "tuple of unions vs union of tuples" issue, which is a known limitation of the compiler (see https://github.com/ponylang/ponyc/issues/1892). But I could be wrong, as I haven't looked at it in detail.

It's also possible this is related to the change in #1937. This could be confirmed by testing against ponyc version 0.14.0 or earlier.

SeanTAllen commented 7 years ago

I tested this with the Wallaroo Labs ponyc version (which is ponyc 0.9 more or less) and it worked then. can confirm it doesnt work with 0.19.0. Also works with 0.14.0. Does not work with 0.15.0.

jemc commented 7 years ago

Okay, sounds like it's a side effect of #1937, then.

aturley commented 6 years ago

Removing "needs discussion", this still needs to be investigated.

SeanTAllen commented 2 years ago

@jemc do you know if you ever looked into this? i'm assuming no.

jemc commented 2 years ago

No, I haven't looked into it.