Commit graph

698 commits

Author SHA1 Message Date
Richard Feldman
c59aa22402
Reproduce mono::ir panic 2022-02-06 07:38:32 -05:00
ayazhafiz
097c5afc73 Check lower bounds for numeric literals, and permit 128-bit literals 2022-02-02 23:35:57 -05:00
ayazhafiz
df8113ce32 Typecheck numeric suffixes in patterns 2022-02-01 23:35:14 -05:00
ayazhafiz
320827167f Parse number literal width suffixes
Supports [u,i][8,16,32,64,128] and [nat,dec]

Part of #2350
2022-02-01 22:48:48 -05:00
ayazhafiz
5943873654 Inline polymorphic calls at usage sites
This is a bit.. ugly, or at least seems suboptimal, but I can't think of
a better way to do it currently aside from demanding a uniform
representation, which we probably don't want to do.

Another option is something like the defunctionalization we perform
today, except also capturing potential uses of nested functions in the
closure tag of an encompassing lambda. So for example,

```
f = \x -> \y -> 1
```

would now record a lambdaset with the data `[Test.f
[TypeOfInnerClos1]]`, where `TypeOfInnerClos1` is e.g.
`[Test.f.innerClos1 I8, Test.f.innerClos1 I16]`, symbolizing that the
inner closure may be specialized to take an I8 or I16. Then at the time
that we create the capture set for `f`, we create a tag noting what
specialization should be used for the inner closure, and apply the
current defunctionalization algorithm. So effectively, the type of the
inner closure becomes a capture.

I'm not sure if this is any better, or if it has more problems.
@folkertdev any thoughts?

Closes #2322
2022-01-28 23:49:19 -05:00
Folkert
0ed259a80d phase 3 2022-01-26 14:37:32 +01:00
Folkert
74932a4cab phase 2 2022-01-26 14:30:37 +01:00
Folkert de Vries
6dd769aa38
Merge pull request #2393 from rtfeldman/i/2343
Generate unique symbols for shadowing identifiers
2022-01-24 11:49:51 +01:00
ayazhafiz
0eede1cd86 Generate unique symbols for shadowing identifiers
This code has a shadowing error:

```
b = False
f = \b -> b
f b
```

but prior to this commit, the compiler would hit an internal error
during monomorphization and not even get to report the error. The reason
was that when we entered the closure `\b -> b`, we would try to
introduce the identifier `b` to the scope, see that it shadows an
existing identifier, and not insert the identifier. But this meant that
when checking the body of `\b -> b`, we would think that we captured the
value `b` in the outer scope, but that's incorrect!

The present patch fixes the issue by generating new symbols for
shadowing identifiers, so deeper scopes pick up the correct reference.
This also means in the future we may be able to compile and execute code
with shadows, even though it will still be an error.

Closes #2343
2022-01-23 12:35:31 -05:00
ayazhafiz
b2f2fcd6a8 Collect tags from extension variables during monomorphization
Fixes #2365
2022-01-23 12:33:22 -05:00
Folkert de Vries
c0ea664141
Merge pull request #2375 from rtfeldman/expression-monomorphization-inlined
Monomorphize polymorphic non-function values
2022-01-21 20:10:42 +01:00
ayazhafiz
53be0e2674 Reduce visibility of partial exprs 2022-01-20 17:56:43 -05:00
Folkert de Vries
82c7e8c37e
Merge pull request #2372 from rtfeldman/effect-forever
Add `Effect.forever`
2022-01-20 09:16:32 +01:00
ayazhafiz
e7e2fa063f Specialize polymorphic values in record updates 2022-01-20 01:23:31 -05:00
ayazhafiz
8fd139ba67 Handle unspecialized symbols captured in closures 2022-01-20 00:34:11 -05:00
ayazhafiz
ae104c3791 Elide unnecessary lifetimes 2022-01-19 23:16:48 -05:00
ayazhafiz
a5de224626 Specialize polymorphic non-function expressions
This commit fixes a long-standing bug wherein bindings to polymorphic,
non-function expressions would be lowered at binding site, rather than
being specialized at the call site.

Concretely, consider the program

```
main =
    n = 1

    idU8 : U8 -> U8
    idU8 = \m -> m

    idU8 n
```

Prior to this commit, we would lower `n = 1` as part of the IR, and the
`n` at the call site `idU8 n` would reference the lowered definition.
However, at the definition site, `1` has the polymorphic type `Num *` -
it is not until the the call site that we are able to refine the type
bound by `n`, but at that point it's too late. Since the default layout
for `Num *` is a signed 64-bit int, we would generate IR like

```
procedure main():
    let App.n : Builtin(Int(I64)) = 1i64;
    ...
    let App.5 : Builtin(Int(U8)) = CallByName Add.idU8 App.n;
    ret App.5;
```

But we know `idU8` expects a `u8`; giving it an `i64` is nonsense.
Indeed this would trigger LLVM miscompilations later on.

To remedy this, we now keep a sidecar table that maps symbols to the
polymorphic expression they reference, when they do so. We then
specialize references to symbols on the fly at usage sites, similar to
how we specialize function usages.

Looking at our example, the definition `n = 1` is now never lowered to
the IR directly. We only generate code for `1` at each place `n` is
referenced. As a larger example, you can imagine that

```
main =
    n = 1

    asU8 : U8 -> U8
    asU32 : U32 -> U8

    asU8 n + asU32 n
```

is lowered to the moral equivalent of

```
main =
    asU8 : U8 -> U8
    asU32 : U32 -> U8

    asU8 1 + asU32 1
```

Moreover, transient usages of polymorphic expressions are lowered
successfully with this approach. See for example the
`monomorphized_tag_with_polymorphic_arg_and_monomorphic_arg` test in
this commit, which checks that

```
main =
    mono : U8
    mono = 15
    poly = A
    wrap = Wrapped poly mono

    useWrap1 : [Wrapped [A] U8, Other] -> U8
    useWrap1 =
        \w -> when w is
            Wrapped A n -> n
            Other -> 0

    useWrap2 : [Wrapped [A, B] U8] -> U8
    useWrap2 =
        \w -> when w is
            Wrapped A n -> n
            Wrapped B _ -> 0

    useWrap1 wrap * useWrap2 wrap
```

has proper code generated for it, in the presence of the polymorphic
`wrap` which references the polymorphic `poly`.

https://github.com/rtfeldman/roc/pull/2347 had a different approach to
this - polymorphic expressions would be converted to (possibly capturing) thunks.
This has the benefit of reducing code size if there are many polymorphic
usages, but may make the generated code slower and makes integration
with the existing IR implementation harder. In practice I think the
average number of polymorphic usages of an expression will be very
small.

Closes https://github.com/rtfeldman/roc/issues/2336
Closes https://github.com/rtfeldman/roc/issues/2254
Closes https://github.com/rtfeldman/roc/issues/2344
2022-01-19 22:52:15 -05:00
Folkert
72e883a20b make symbol debug formatting consistent 2022-01-19 23:21:18 +01:00
Folkert
4c445f9f24 recognize functions that become tail-recursive after closure conversion 2022-01-19 20:09:20 +01:00
Folkert de Vries
e1d990896a
Merge branch 'trunk' into mono-display 2022-01-14 13:55:52 +01:00
ayazhafiz
9f78eb2e01 Fix bug that caused extraneous assignment in IR generation
Previously we would expand optional record fields to assignments when
converting record patterns to "when" expressions. This resulted in
incorrect code being generated.
2022-01-13 18:34:25 -05:00
ayazhafiz
72ee2d6327 Mark pretty_print_ir_symbols public 2022-01-13 16:35:09 -05:00
ayazhafiz
c38ca2dfa4 Anything for you mr paperclippy 2022-01-13 16:33:26 -05:00
ayazhafiz
8d372edda1 Add config variables for printing IR during mono stages 2022-01-13 16:33:26 -05:00
ayazhafiz
e655ab7d3b Module comments for reset-reuse
Figuring out what this module was doing, and why, took me a bit less
than half an hour. We should document what's happening for others in the
future so they don't need to follow up on Zulip necessarily.
2022-01-13 16:33:23 -05:00
ayazhafiz
103e85f339 Pretty-print laayouts when PRETTY_PRINT_IR_SYMBOLS is true 2022-01-10 19:21:18 -05:00
Folkert
fc4cea9f75 don't throw away a jump 2022-01-03 16:50:43 +01:00
Folkert
7044e95df8 fix imported function thunk 2022-01-03 16:18:53 +01:00
Folkert
ee9f0b2f04 force imported thunks when assigned to a variable 2021-12-31 21:44:07 +01:00
Brian Carroll
59472d3310 Slightly improve pretty printing of inc statement 2021-12-30 09:01:22 +00:00
ayazhafiz
1f81a598f7 Presence constraint flag -> Enum 2021-12-23 19:40:18 -06:00
ayazhafiz
b97ff380e3 Presence constraints for tag union types
This work is related to restricting tag union sizes in input positions.
As an example, for something like

```
\x -> when x is
    A M -> X
    A N -> X
    A _ -> X
```

we'd like to infer `[A [M, N]* ]` rather than the `[A, [M, N]* ]*` we
infer today. Notice the difference is that the former type tells us we
only accepts `A`s, but the argument of the `A` can be `M`, `N` or
anything else (hence the `_`).

So what's the idea? It's an encoding of the "must have"/"might have"
design discussed in https://github.com/rtfeldman/roc/issues/1758. Let's
take our example above and walk through unification of each branch.

Suppose `x` starts off as a flex var `t`.

```
\x -> when x is
    A M -> X
```

Now we introduce a new kind of constraint called a "presence"
constraint. It says "t has at least [A [M]]". I'll notate this as `t +=
[A [M]]`. When `t` is free as it is here, this is equivalent to `t ~
[A [M]]`.

```
\x -> when x is
    ...
    A N -> X
```

At this branch we introduce the presence constraint `[A [M]] += [A [N]]`.
Notice that there's two tag unions we care about resolving here - one is
the toplevel one that says "I have an `A ...` inside of me", and the
other one is the tag union that's the tyarg to `A`. They are distinct
and at different depths.

For the toplevel one, we first figure out if the number of tags in the
union needs to expand. It does not - we're hoping to resolve the type
`[A [M, N]]`, which only has `A` in the toplevel union. So, we don't
need to do anything extra there, other than the merge the nested tag
unions.

We recurse on the shared tags, and now we have the presence constraint
`[M] += [N]`. At this point it's important to remember that the left and
right hand types are backed by type variables, so this is really
something like `t11 [M] += t12 [N]`, where `[M]` and `[N]` are just what
we know the variables `t11` and `t12` to be at this moment. So how do we
solve for `t11 [M, N]` from here? Well, we can encode this constraint as
a type variable definition and a unification constraint we already know
how to solve:

```
New definition: t11 [M]a    (a fresh)
New constraint: a ~ t12 [N]
```

That's it; upon unification, `t11 [M, N]` falls out.

Okay, last step.

```
\x -> when x is
    ...
    A _ -> X
```

We now have `[A [M, N]] += [A a]`, where `a` is a fresh unbound
variable. Again nothing has to happen on the toplevel. We walk down and
find `t11 [M, N] += t21 a`. This is actually called an "open constraint"; we
differentiate it at the time we generate constraints because it follows
syntactically from the presence of an `_`, but it's semantically
equivalent to the presence constraint `t11 [M, N] += t21 a`. It's just
called opening because literally the only way `t11 [M, N] += t21 a` can
be true is if we set `t11 a`. Well, actually, we assume `a` is a tag
union, so we just make `t11` the open tag union `[M, N]a`. Since `a` is
unbound, this eventually becomes a wildcard and hence falls out `[M, N]*`.
Also, once we open a tag union with an open constraint, we never close
it again.

That's it. The rest falls out recursively. This gives us a really easy
way to encode these ordering constraints in the unification-based system
we have today with minimal additional intervention. We do have to patch
variables in-place sometimes, and the additive nature of these
constraints feels about out-of-place relative to unification, but it
seems to work well.

Resolves #1758
2021-12-23 19:40:18 -06:00
ayazhafiz
a626214852 Fix use of undeclared symbol
090a8923c5 changed `Located -> Loc`, but
5d7aff373c introduced another instance of
`Located` and didn't have the commit history of 090a8923c5
2021-12-23 17:58:12 -06:00
Folkert de Vries
5f7476d54f
Merge pull request #2266 from rtfeldman/joshuawarner32/loc
Parser refactor: always group (Row, Col) into Position
2021-12-24 00:02:13 +01:00
Folkert de Vries
db44d03e66
Merge pull request #2259 from rtfeldman/i/2227-record-layout-hang
Turn invalid record field types into runtime errors
2021-12-23 20:17:34 +01:00
Joshua Warner
22e2545fd6 format 2021-12-22 20:46:42 -08:00
Joshua Warner
f19220473a Rename Located -> Loc 2021-12-22 19:18:22 -08:00
ayazhafiz
ac54a5e024 Remove nonsene panic 2021-12-22 19:38:10 -06:00
ayazhafiz
ed64ff912a Implement List.dropIf
This was referenced in the `List` documentation and in the
[tutorial](./TUTORIAL.md), but wasn't actually implemented prior to this
commit!

Part of #2227
2021-12-22 12:34:48 -06:00
ayazhafiz
903fa7d363 Fix clippy warning: implement From over Into 2021-12-21 19:55:50 -06:00
ayazhafiz
576f1293fd Turn invalid record field types into runtime errors
By emitting a runtime error rather than panicking when we can't layout
a record, we help programs like

```
main =
    get = \{a} -> a
    get {b: "hello world"}
```

execute as

```
Mismatch in compiler/unify/src/unify.rs Line 1071 Column 13
Trying to unify two flat types that are incompatible: EmptyRecord ~ { 'a' : Demanded(122), }<130>

🔨 Rebuilding host...
── TYPE MISMATCH ───────────────────────────────────────────────────────────────

The 1st argument to get is not what I expect:

8│      get {b: "hello world"}
            ^^^^^^^^^^^^^^^^^^

This argument is a record of type:

    { b : Str }

But get needs the 1st argument to be:

    { a : a }b

Tip: Seems like a record field typo. Maybe a should be b?

Tip: Can more type annotations be added? Type annotations always help
me give more specific messages, and I think they could help a lot in
this case

────────────────────────────────────────────────────────────────────────────────

'+fast-variable-shuffle' is not a recognized feature for this target (ignoring feature)
'+fast-variable-shuffle' is not a recognized feature for this target (ignoring feature)
Done!
Application crashed with message

    Can't create record with improper layout

Shutting down
```

rather than the hanging

```
Mismatch in compiler/unify/src/unify.rs Line 1071 Column 13
Trying to unify two flat types that are incompatible: EmptyRecord ~ { 'a' : Demanded(122), }<130>

thread '<unnamed>' panicked at 'invalid layout from var: UnresolvedTypeVar(104)', compiler/mono/s
rc/layout.rs:1510:52
```

that was previously produced.

Part of #2227
2021-12-21 19:11:59 -06:00
Folkert
28b4388488 remove unneeded field 2021-12-05 15:25:46 +01:00
Richard Feldman
e6bec46898
Merge pull request #2109 from rtfeldman/refactor-passed-function
refactor passed (to higher order lowlevel) funcion
2021-12-01 08:17:39 -05:00
Chelsea Troy
0e5f82526a Account for SingleQuote in the case statements for the cli, plus some errata
+ Evidently I failed to finish fixing merge conflicts
+ Some of the types that the SingleQuote code mentioned didn't exist according to the build step. I looked around and switched them out for types it LOOKED like they were supposed to be, but someone should probably check this
+ Don't make commits like this; it's multiple unrelated changes thrown together. I'm still figuring out my way around here
2021-12-01 00:13:15 -06:00
Folkert
bec74c36c5 refactor passed (to higher order lowlevel) funcion 2021-11-30 21:50:27 +01:00
Brian Carroll
c2a2ff2957 Create Expr::to_pretty in mono IR 2021-11-30 09:57:26 +00:00
Brian Carroll
61575cea7e Generate calls to refcount procs from Wasm backend 2021-11-30 09:57:00 +00:00
Chelsea Troy
6cf755ad8d Resolve a bunnnch of merge conflicts 2021-11-29 23:14:29 -06:00
Folkert
ab1787937d shrink CallSpecId and UpdateModeId to u32; assuming a 4GiB file that should be more than enough 2021-11-28 22:59:23 +01:00
Folkert
aefe719e56 hook up update mode for reset/reuse 2021-11-28 14:25:51 +01:00