Commit graph

4405 commits

Author SHA1 Message Date
Ayaz Hafiz
058644aa96
Implement weakening of variables introduced in branch patterns
Variables introduced in branch patterns should never be generalized in
the new weakening model. This implements that. The strategy is:

- when we have a let-binding that should be weakened, do not introduce
  its bound variables in a new (higher) rank
- instead, introduce them at the current rank, and also solve the
  let-binding at the current rank
- if any of those variables should then be generalized relative to the
  current rank, they will be so when the current rank is popped and
  generalized
2023-01-11 14:28:46 -06:00
Ayaz Hafiz
7febddd1ea
Get rid of unneeded unsafe code and explain max_rank adjustment 2023-01-11 14:28:46 -06:00
Ayaz Hafiz
ddda00036e
Add more comments to solve 2023-01-11 14:28:46 -06:00
Ayaz Hafiz
5db82ad965
Explain why we currently cannot mark degeneralization in when headers 2023-01-11 14:28:46 -06:00
Ayaz Hafiz
c2cb94a927
Decide rank to work in for weakening 2023-01-11 14:28:46 -06:00
Ayaz Hafiz
5ccedca093
Implement de-generalization for weakened let bindings 2023-01-11 14:28:45 -06:00
Ayaz Hafiz
cb18291aa8
Loosen weakening restriction for now 2023-01-11 14:28:45 -06:00
Folkert de Vries
d8b2ff07f8
Merge pull request #4802 from roc-lang/valgrind-unit-tests
Valgrind unit tests
2023-01-11 19:45:28 +01:00
Richard Feldman
94ccb0fd8d
Merge pull request #4849 from roc-lang/intern-layouts-5-lambda-set-layout-cache
Reduce layout intern allocations
2023-01-10 20:35:09 -05:00
Folkert de Vries
ca43da2804
Merge pull request #4873 from roc-lang/refcount-nullable-wrapped
Make sure to bump index of nullable-wrapped tag indices after null variants
2023-01-10 22:01:14 +01:00
Folkert de Vries
700ac4660c
Merge pull request #4875 from roc-lang/no-redundant-check-in-rank-adjustment
Remove check for redundancy before doing rank adjustment
2023-01-10 21:57:26 +01:00
Ayaz
9a146d80a4
Merge pull request #4874 from roc-lang/borrow-own-host-exposed
force host-exposed to always own params
2023-01-10 14:09:09 -06:00
Ayaz Hafiz
dc30dbc8a4
Add rank-generalization test 2023-01-10 12:46:34 -06:00
Folkert
a9cd6c6832
test forcing host-exposed always owning params 2023-01-10 19:17:39 +01:00
Ayaz
73020ca696
Merge pull request #4869 from roc-lang/josh-recursive-union-bug-2
Skip nullable ID in nullable wrapped tags when iterating
2023-01-10 12:05:42 -06:00
Ayaz Hafiz
cb9f776781
Remove check for redundancy before doing rank adjustment
Presently while generalizing type variables, we check variables
introduced at a scope for redundancy (whether they are not the root of
some unified set of variables). If a variable is redundant, its rank is
not adjusted. I believe the current logic to be the following:

- Each root of a unification tree will be introduced at some point,
  exactly once. Its point of introduction will determine the rank of the
  tree it's the root of
- If a variable is redundant, all of its redundant usages must be at the
  same rank (assuming let generalization proceeds correctly),
  so there is no need to adjust their rank as well
- As such, there is no need to adjust the rank of redundant variables,
  as a performance optimization.

I believe this to be a hold-over from the original version of the solver
derived from the elm-compiler.

In our implementation however rank adjustment is very cheap (thanks to
SoA, ranks are likely in the cache lines already anyway because we just
adjusted variables at this point).

However, there is a larger problem here - ranks must be adjusted for
redundant variables as we begin to support weakened type variables.

The motivating case is

```
\x -> when x is
  _x -> Green
```

we would like this code generalized as `* -> [Green]*`. `when`
expressions have each branch solved via let-bindings; in particular, for
the singleton branch we introduce `_x` of the appropriate type and solve
the body as `[Green]*`.

Today, `[Green]*` would be generalized in the context of the inner scope
that binds `_x`, which means it is generalized in the body `\x -> ...`
as a whole.

However, with weakening, we do not want this behavior! In particular, we
do not want to actually generalize `_x` in the context of the branch
body. Doing so means you could write things like

```
main = \{} -> when Red is
    x ->
        y : [Red]
        y = x

        z : [Red, Green]
        z = x

        {y, z}
```

which is exactly the kind of spurious generalization that the weakening
design is trying to avoid.

So, we want to introduce `[Green]*` at the rank of the body `\x -> ...`;
let's call this `rank_body`, and let's say `[Green]*` is introduced as
`branch_var`. Let's say the return type variable is `ret_var`.

Now we must be careful. If after unification `ret_var ~ branch_var` we have that
`branch_var` becomes the root, then despite `ret_var` (and `branch_var`) being at
`rank_body` (which is also the rank that will promoted to generalization),
the tree given by `branch_var` won't be generalized, because `ret_var` will be
seen as redundant! In fact it is, because `branch_var` was introdued
previously, but that doesn't matter - we want the variable to be
generalized at the level of the outer let-binding `main = \{} -> ...`.

This problem is not unique to when-branches; for example we can observe
the same symptom with

```
main = \{} ->
    x = Green
    x
```

where here we'd like `x` to not be generalized inside the body of
`main`, but have it be generalized relative to the body of `main` (that
is, main should have signature `{} -> [Green]*`, but you cannot use `x`
itself polymorphically inside the body of `main`).

As such, the easiest solution as far as I can see, in the presence of
weakening, is to allow rank-adjustment and generalization of redundant
variables if they are permitted to be generalized relative to a lower
scope.

This should preserve soundness; the main source of unsoundness in
rank-based let generalization is making sure something like

```
\x ->
    y = \z -> x z
    y
```

has type `(a -> b) -> (a -> b)` and not e.g. `(a -> b) -> (c -> d)` due
to `x` being instantiated at a higher rank in `y = ...` than it
actually is. Note that this change cannot affect this case at all, since
we are still doing the rank-adjustment pass at higher ranks, unifying
lowers ranked variables to their minimum relative rank, and introduction
only happens in the lower-ranked scopes.
2023-01-10 12:05:06 -06:00
Folkert de Vries
a659b6b560
Merge pull request #4858 from roc-lang/parse-http
Example parser for HTTP messages
2023-01-10 19:03:56 +01:00
Folkert
546a3dd0c4
fix unused import 2023-01-10 18:54:38 +01:00
Anton-4
867067dfaf
fix unused warning on macos 2023-01-10 17:21:34 +01:00
Ayaz Hafiz
066bc7d953
Make sure to bump index of nullable-wrapped tag indices after null variants
Fixes a bug in ref-counting.
2023-01-10 10:01:50 -06:00
Anton-4
6406834c4e
moved building to lib with Once 2023-01-10 16:48:22 +01:00
Ayaz Hafiz
26f08c999c
Store interened wrapped layout of lambda set on LambdaSet struct
The `LambdaSet` struct is frequently used independently to examine how a
lambda set should be packed or unpacked. However, it is also often
converted into a full layout via `Layout::LambdaSet(LambdaSet)` to be a
part of function arguments, for example.

In preparing to intern all layouts, we need a way to cheaply go from a
`lambda_set` to an interned `Layout::LambdaSet(lambda_set)`, since this
is a very common operation. The proposed solution is to keep the wrapped
layout cached on `LambdaSet` itself, which this PR does.

The tricky bit of inserting a lambda set is we need to fill in the
interned `full_layout` only after the lambda set is inserted,
but we don't want to allocate a new interned slot if the same lambda set
layout has already been inserted with a different `full_layout` slot.

For example, if we insert `LambdaSet { set : [A] }` twice in two
different threads, we want the `full_layout` they map to to be the same.
So we nede to check if an interned representation with a full_layout
exists, before we allocate a new full_layout and insert a fresh lambda
set.

So,
  - check if the "normalized" lambda set (with a void full_layout slot) maps to an
    inserted lambda set in
    - in a thread-local cache, or globally
  - if so, use that one immediately
  - otherwise, allocate a new (global) slot, intern the lambda set, and then fill the slot in
    - save the interned layout and lambda set mapping thread-locally
2023-01-10 09:47:13 -06:00
Ayaz Hafiz
ce717dca8b
Do not require allocating Layouts in arena before interning
This should reduce memory spend, the interner has its own effective
arena anyway
2023-01-10 09:47:13 -06:00
Brian Carroll
0ee8de2bc8
parser/Http: add a cli test and a new method for library testing 2023-01-10 08:53:48 +00:00
Ayaz Hafiz
ba2527a020
Check in mono test case 2023-01-09 16:35:25 -06:00
Folkert
c8467c1a52
remove cfg(test) in build script 2023-01-09 23:32:26 +01:00
Folkert
e926bced10
refactor load/file logic 2023-01-09 23:31:19 +01:00
Folkert de Vries
61a2091b27
Merge pull request #4851 from JTeeuwissen/main
replace borrowed boolean with ownership enum
2023-01-09 23:24:39 +01:00
J.Teeuwissen
c2e14864ab
from_layout 2023-01-09 19:19:20 +01:00
Ayaz Hafiz
b2688dd3b1
Skip nullable ID in nullable wrapped tags when iterating 2023-01-09 11:54:51 -06:00
J.Teeuwissen
b28b32cdc4
moved Ownership to borrow 2023-01-09 18:15:34 +01:00
Richard Feldman
ab7de647e4
Merge pull request #4863 from joshuawarner32/better-scalar-literals
Improve parsing of scalar literals
2023-01-09 11:42:44 -05:00
Folkert
7b8b2a40f6
add test for str concat on non-unique first argument 2023-01-09 12:18:12 +01:00
Folkert
8a622a310d
use capacity instead of length in decref 2023-01-09 12:18:11 +01:00
Anton-4
4797979202
don't build valgrind crate for regular build 2023-01-09 10:35:51 +01:00
Ayaz
b1431ebea2
Merge pull request #4864 from roc-lang/str-concat-non-unique-first-argument
str concat non unique first argument
2023-01-08 19:38:34 -06:00
Ayaz
7c61d0d278
Merge pull request #4843 from roc-lang/pattern-as-can
Pattern as can
2023-01-08 19:36:40 -06:00
Folkert
148d24662e
use capacity instead of length in decref 2023-01-08 22:01:35 +01:00
Folkert
cb53e46cdd
clippy 2023-01-08 17:46:13 +01:00
Folkert
c2ddeb0de0
fix and test as pattern type inference 2023-01-08 16:40:03 +01:00
Folkert
57f2233278
cleanup 2023-01-08 15:47:56 +01:00
Folkert
9d9ae290fe
rebuild the platform without doing anything else 2023-01-08 15:39:47 +01:00
Joshua Warner
94070e8ba6
Improve parsing of scalar literals
* Unify parsing of string literals and scalar literals, to (e.g.) ensure escapes are handled uniformly. Notably, this makes unicode escapes valid in scalar literals.
* Add a variety of custom error messages about specific failure cases of parsing string/scalar literals. For example, if we're expecting a string (e.g. a package name in the header) and the user tried using single quotes, give a clear message about that.
* Fix formatting of unicode escapes (they previously used {}, now correctly use () to match roc strings)
2023-01-07 15:12:52 -08:00
J.Teeuwissen
a11d94aee2
Replaced equality check with enum 2023-01-06 08:55:13 +01:00
J.Teeuwissen
be73d3cfc4
Removed ! 2023-01-06 08:54:44 +01:00
Folkert de Vries
2a8c08e77e
Merge pull request #4855 from roc-lang/weakening-1
Print weak variables in tests and mark constraints that can't be generalized
2023-01-05 23:09:47 +01:00
Folkert de Vries
6989eca6f0
Merge pull request #4848 from roc-lang/intern-layouts-4
Inline interners into the layout interner module
2023-01-05 23:08:37 +01:00
Ayaz
4ff7c13ab3
Merge pull request #4847 from roc-lang/intern-layouts-3
Wrap layout interners in own trait
2023-01-05 16:07:46 -06:00
J.Teeuwissen
1f10d0cb92
Added traits and updated remaining borrowed 2023-01-05 12:02:20 +01:00
Ayaz
314e2d8707
Merge pull request #4846 from joshuawarner32/lenient-records
Be more lenient with indentation in record parsing
2023-01-04 17:06:17 -06:00