Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sean/purus #42

Merged
merged 201 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 177 commits
Commits
Show all changes
201 commits
Select commit Hold shift + click to select a range
04eece1
flake
gnumonik Nov 29, 2023
c6c8930
shell
gnumonik Nov 29, 2023
3e3562c
Added uplc command line option for , pulled in plutus-core dep from C…
gnumonik Nov 30, 2023
99c51cb
PlutusIR dependency sorted out
gnumonik Nov 30, 2023
75012d1
Typed CoreFn conversion & pretty printer (messy)
gnumonik Dec 6, 2023
62c4685
More detailed tracing to investigate type reprs
gnumonik Dec 6, 2023
b173baf
Switched to a typed CoreFn data type (instead of stashing type info i…
Jan 12, 2024
5b02fe1
Preserving ForAll quantifiers in output CoreFn AST (WIP/maybe broken)
Jan 17, 2024
822c6d4
Let bindings/declaration groups debugging, working on quantifier pres…
gnumonik Jan 18, 2024
23fac0a
Working on conversion of typeclass dictionaries. (Pretty messy, using…
gnumonik Jan 20, 2024
f3a86eb
Adjusted typeclass desugaring to use real source locations in the cas…
gnumonik Jan 24, 2024
28a850e
Conversion to typed CoreFn for desugared typeclass dictionaries seems…
gnumonik Jan 24, 2024
282d951
Typed CoreFn conversion now works with MPTCs, cleaned up a bunch of u…
gnumonik Jan 25, 2024
cdd4bb1
Substantial cleanup + documentation pass
gnumonik Jan 25, 2024
766b580
Merge pull request #17 from mlabs-haskell/sean/typedCoreFn.typeclasse…
gnumonik Jan 25, 2024
6e2ca01
Nested 'let' expressions w/ mix of type sigs/no type sigs w/ quantifiers
gnumonik Jan 25, 2024
51344c8
Mutually recursive binding groups, binders, attempt at generalizing T…
gnumonik Feb 1, 2024
9ffcbcf
Merge pull request #19 from mlabs-haskell/sean/typedCoreFn.wip
gnumonik Feb 1, 2024
722a0cc
fixed small mistake, deleted some traces, added comment or two
gnumonik Feb 1, 2024
e6237d8
Merge branch 'sean/typedCoreFn.wip' into sean/typedCoreFn
gnumonik Feb 1, 2024
02129dd
Fixed mutual recursion bug in declToCoreFn, removed let generalizatio…
gnumonik Feb 3, 2024
b2befc1
Fixed problem w/ object literal binders, cleaned up the interface of …
gnumonik Feb 6, 2024
5f464c5
Primitive infrastructure for golden tests, removed some dead options
gnumonik Feb 21, 2024
aa95066
testing infrastructure, ported some tests/purs/passing tests to debug…
gnumonik Feb 22, 2024
5a83437
Fixed bug discovered in test #4301 (I hope...)
gnumonik Feb 27, 2024
c99c476
Fixed issue w/ transitive imports resulting from explicitly desguarin…
gnumonik Feb 29, 2024
293acc9
Documenting/Explaining the use of new utils
gnumonik Feb 29, 2024
1e17804
Type inference/checking machinery removed from CoreFn desugaring mach…
gnumonik Mar 1, 2024
161bdef
Added some empty list tests
gnumonik Mar 1, 2024
f35cdb0
Prettyprinter replacement implemented (still needs some tweaking)
gnumonik Mar 2, 2024
b4f557e
prettyprinter improvements
gnumonik Mar 2, 2024
7876fdb
even prettier
gnumonik Mar 2, 2024
c862bd5
extremely pretty
gnumonik Mar 2, 2024
4b6112c
Refactored pretty printer update to use Reader monad (hopefully makes…
gnumonik Mar 5, 2024
cb11738
Final cleanup/tweaks to pretty printer
gnumonik Mar 5, 2024
d295a01
Module-ized prettyprinter + some small tweaks
gnumonik Mar 6, 2024
ae4f703
Nix setup
t4ccer Feb 18, 2024
991c758
Trigger CI
t4ccer Feb 18, 2024
4214ae6
Remove unused configs
t4ccer Feb 18, 2024
6349472
Disable typos check
t4ccer Feb 18, 2024
ed35645
Remove Nix Plutarch wrapper
t4ccer Feb 23, 2024
a9f7a14
Removed some dead comments, testing pre-commit hooks
gnumonik Mar 6, 2024
115cb65
working on monomorphizer (seems to work w/ non-recursive binding grou…
gnumonik Mar 15, 2024
cada4c7
re-implementing monomorphizer (wip)
gnumonik Mar 16, 2024
584cf12
monomorphizer works on the simplest possible mutually recursive examp…
gnumonik Mar 19, 2024
babc876
Support for PLC Builtins and primitive types
gnumonik Mar 20, 2024
db81559
re-organize modules
gnumonik Mar 20, 2024
3a1302d
utilities for object desugaring
gnumonik Mar 20, 2024
7106f6f
Conversion to Bound, object desugaring
gnumonik Mar 21, 2024
d08e03e
Prettyprinter for Bound AST, fixed some bugs in object desguaring, re…
gnumonik Mar 22, 2024
9e83557
Reworked final IR, prettyprinters, debugging + reworking monomorphize…
gnumonik Mar 22, 2024
8a84e77
forgot to commit new file
gnumonik Mar 22, 2024
9dbd7b7
full Purs->UPLC pipeline working for very simple examples. builtins w…
gnumonik Mar 23, 2024
71add6a
remoted test output dirs from gitignore (so can link to things)
gnumonik Mar 23, 2024
3b24eef
wrong output file name in test
gnumonik Mar 23, 2024
3f8183d
working on case expressions
gnumonik Mar 26, 2024
87fd8cc
basic PLC test infrastructure
gnumonik Mar 26, 2024
e076b6a
fixed some tests
gnumonik Mar 26, 2024
e6cb3ba
architecture doc
gnumonik Mar 28, 2024
d3a263c
Removed type annotations from CoreFn and ctors
gnumonik Mar 29, 2024
809249c
Working on better case desugaring. (Their algorithm works for us but …
gnumonik Apr 13, 2024
c8fac0a
Guard/case desugaring w/ correct types
gnumonik Apr 19, 2024
1b55f26
Fix objects introduced by forall without typeclass constraints
t4ccer Apr 24, 2024
e19e729
Add tests for objects with forall
t4ccer Apr 25, 2024
5d12065
Fix arrays introduced by forall
t4ccer Apr 25, 2024
dd62554
Remove FFI codegen
t4ccer Apr 22, 2024
722270d
Tentative fix for #30 (superclass method access)
gnumonik Apr 30, 2024
c06ac6b
Parametrize IR AST with type
t4ccer May 1, 2024
376ef2f
Initial CoreFn -> IR transformation
t4ccer May 2, 2024
ac9137b
Track object presence on type level
t4ccer May 5, 2024
b971e9c
Remove guarded patterns
t4ccer May 5, 2024
8aedd54
Merge branch 'sean/monomorph-cleanup' into t4/ast2
t4ccer May 5, 2024
5d70096
Ignore `cache-db.json` files
t4ccer May 5, 2024
1ddbe4e
WIP Monomorphizer rework for AST
t4ccer May 5, 2024
f74e778
Some stuff
t4ccer May 8, 2024
3ad78bf
Parameterized module, TypeLike class for common operations on types, …
gnumonik May 9, 2024
d1dd427
IndexedPlated instance for Exp
gnumonik May 10, 2024
df5cc44
changed IndexedPlated to Plated
gnumonik May 10, 2024
33476ce
monomorphizer utils, started reworking inlineAs
gnumonik May 11, 2024
eca9e88
types mostly line up, might break things in a sec
gnumonik May 14, 2024
1b17a50
made the types line up in the monomorphizer rewrite
gnumonik May 15, 2024
96d4b9e
monomorphizer rewrite works for simple examples
gnumonik May 16, 2024
f05bf14
Changed the body of BindE to Exps (from Scopes), cleanup, doc comments
gnumonik May 16, 2024
0993609
Removed dead code, misc cleanup
gnumonik May 16, 2024
fe6d66e
disabled UPLC tests while we rewrite things
gnumonik May 16, 2024
8d2d2df
initial draft of simplified datatype binding/translation machinery
gnumonik May 17, 2024
ee3b27e
started implementing mandatory kinds. compiles but very broken atm, n…
gnumonik May 18, 2024
764b71c
trying to fix mandatory kinds design flaws & bugs (compiles but broke…
gnumonik May 22, 2024
69397fd
Restrict kind annotations to just identifiers and arrows
klntsky May 22, 2024
8b06941
Update the parser: use kind everywhere for TypeKinded
klntsky May 22, 2024
291750e
Fixed a few bugs resulting from mandatory kind annotations for TyVars…
gnumonik May 23, 2024
fb2838f
Use square brackets for rows
klntsky May 23, 2024
faf2514
pre-merge backup commit
gnumonik May 23, 2024
426c4ff
Merge branch 'klntsky/parser-tweaks/sean/mandatory-kinds' into sean/m…
gnumonik May 23, 2024
8838a77
Disallow named instances in the parser
klntsky May 24, 2024
bbe329e
Add quantifiers for instances
klntsky May 24, 2024
141c11f
restrict kinds in `forall (a :: kind)` parser to be kinds only
klntsky May 24, 2024
ff0b89f
fixed bugs in backticked infix expressions & superclass variables types
gnumonik May 25, 2024
27d8648
fixed a bug in the CST grouper, cleaned up old passing tests
gnumonik May 25, 2024
ceb7ddb
Merge branch 'klntsky/parser-tweaks/sean/mandatory-kinds' into sean/m…
gnumonik May 25, 2024
7f10e5a
better row syntax tests to help vladimir debug
gnumonik May 25, 2024
1de91e0
more row syntax tests
gnumonik May 25, 2024
89162e4
linting
gnumonik May 28, 2024
5777b4e
Fixed mistake (ignored TVBinders in instance chains), cleaned up/fixe…
gnumonik May 28, 2024
abf5382
Rewrote object desugarer to use our new IR, started work on PIR conve…
gnumonik May 30, 2024
a875d50
rewrote most of PIR conversion, updated repl-testing tools and test i…
gnumonik May 31, 2024
6411de7
removed Constructor nodes from CoreFn and IR Expr AST (this breaks th…
gnumonik Jun 1, 2024
f6f39ea
Reworking compiler machinery for handling datatypes/constructors
gnumonik Jun 1, 2024
45417e1
reworking datatype machinery, continued
gnumonik Jun 4, 2024
94e0227
Tweaks to datatype machinery (NOTE: I broke the renamer, trying to fi…
gnumonik Jun 5, 2024
b3f24e7
Primitive Array & Boolean datatypes (needed for codegen)
gnumonik Jun 6, 2024
d27cf25
tuples
gnumonik Jun 6, 2024
6d8b975
removed old monomorphize module
gnumonik Jun 6, 2024
70861cb
Tupled case scrutinees and patterns in IR
gnumonik Jun 6, 2024
49dadde
working on case expression compilation (doesn't compile / wip)
gnumonik Jun 7, 2024
f488867
Finished draft of PIR conversion rewrite, need to change some other t…
gnumonik Jun 12, 2024
76c848c
Desugar array & boolean literals to their ADT forms
gnumonik Jun 13, 2024
6f7697d
debugging
gnumonik Jun 14, 2024
104d705
debugging (something's wrong with our Scope transversals -_-)
gnumonik Jun 14, 2024
24d3a6c
reworked object desugarer/monomorphizer to fix our broken understandi…
gnumonik Jun 18, 2024
e32aa70
debugging, fixes
gnumonik Jun 20, 2024
776ac5e
fixed monomorphizer, many small fixes, tests for demo video
gnumonik Jun 21, 2024
c717ae2
Reworking case machinery, making changes to earlier parts of the pipe…
Jul 2, 2024
15ccf4f
still working on case expressions
Jul 3, 2024
454d92b
debugging & fixes
Jul 4, 2024
5372b2d
Debugging. Very close to appeasing the PIR typechecker for 'complex' …
Jul 5, 2024
115245f
Fixed a bunch of errors related to case expression compilation. Still…
Jul 10, 2024
2794a0b
fixed VarP/WildP catchall patterns, probably about to break something
Jul 11, 2024
acd1ef0
case expression compilation seems to work flawlessly, need to fix var…
Jul 11, 2024
9c7374e
fixed type deduction bug that was breaking the compiler in a few cont…
Jul 12, 2024
44a4333
Fixed a bunch of minor bugs (mainly related to TyInsts and Constructo…
Jul 13, 2024
56ef532
initial implementation of tyabs, reworked monomorphizer, still have a…
Jul 24, 2024
5f9a2a2
seems to work for every test except 'guardedCase'
Jul 27, 2024
85c41d8
initial implementation of lifting machinery (buggy, needs fixes)
Aug 2, 2024
4b0a293
Rewrote lifting machinery, needs debugging
Aug 3, 2024
d5059a4
Lifting machinery generally does what it should except for a few smal…
Aug 4, 2024
cd7b87c
lifting machinery works for simple examples. TODO: cleanup/tests
Aug 5, 2024
7546bd7
ran the formatter (for the first time in half a year)
Aug 5, 2024
8f80062
cleaned up / documented lifting machinery
Aug 5, 2024
f5e52c7
Implemented type-abstraction lifting utility to 'correct' the types o…
Aug 6, 2024
e7cc0a6
reorganized some modules
Aug 11, 2024
8d93ad0
started draft of inliner/loop breaker
Aug 12, 2024
0f6a00e
finished inliner draft, debugging
Aug 13, 2024
5a1d7d8
it works? maybe?
Aug 13, 2024
f31ca65
reworked inliner in line w/ koz's suggestions
Aug 14, 2024
b48524e
reorganized modules, fixed variable binding bug in corefn conversion
Aug 15, 2024
77e0bc8
inliner & lifer *appear* to work
Aug 15, 2024
7ade596
added a few test cases, fixed a few small bugs
Aug 16, 2024
6e76672
fixed some TyAbs bugs in DesugarCore, draft of new instantiation mach…
Aug 20, 2024
f8ea321
Reworking Lifting machinery to minimize unnecessary type abstractions…
Aug 21, 2024
66bff6e
fixed a printer bug, better polymorphic lift test case
Aug 21, 2024
cb40120
Ord1 instance for Exp
kozross Aug 22, 2024
e281c0c
Merge pull request #40 from mlabs-haskell/koz/ord1
gnumonik Aug 22, 2024
67d46ba
fixed a few bugs introduced in the lifter/inliner rework
Aug 22, 2024
5eacda5
reorganizing module (committing in case I accidentally delete somethi…
Aug 23, 2024
22f45c6
Working on module reorganization/cleanup/better monad stacks
Aug 23, 2024
da981b7
reorganization/cleanup complete
Aug 24, 2024
1c6b40c
removed some deleted modules from cabal file
Aug 24, 2024
a57c0e1
ran the formatter, fixed the tests
Aug 24, 2024
06af1d9
generalized instantiate to work with any of our Exp types, more clean…
Aug 24, 2024
5bcc87e
Initial ledger types
kozross Aug 7, 2024
dc7503d
Initial ledger types
kozross Aug 7, 2024
ab7e833
Refactor type definitions into own module
kozross Aug 13, 2024
76c073f
Ledger API types
kozross Aug 15, 2024
0420911
Refactor
kozross Aug 19, 2024
5b0562d
Remove vestiges from Environment
kozross Aug 27, 2024
7d615f2
Merge pull request #38 from mlabs-haskell/koz/ledger-api-types
kozross Aug 27, 2024
9013f2e
Rest of ledger decls
kozross Aug 27, 2024
16f6266
Merge pull request #41 from mlabs-haskell/koz/ledger-api-types-3
kozross Aug 27, 2024
283f11e
Pipeline rebuilt, changed test output file name format, misc small fi…
Aug 27, 2024
8106999
ledger types available to typechecking environment
Aug 27, 2024
9f900af
Refactored Koz's declarations to work with SourceType instead of Ty, …
Aug 28, 2024
e97450b
compiler appears to work!
Aug 28, 2024
787fa77
ran the formatter + wrote some more test cases + fixed some minor bugs
Aug 28, 2024
7487fbd
Serializations into prelude
kozross Aug 29, 2024
8f9338b
More prelude
kozross Aug 29, 2024
f097c35
Fixed implementation for literal pattern desugaring, added unit type,…
Aug 29, 2024
0de32f9
more cleaning up, more removing dead code, more writing comments
Aug 29, 2024
2074564
ran the formatter
Aug 29, 2024
1b99050
Merge branch 'sean/purus' into koz/prelude
kozross Aug 29, 2024
3e3f096
Ensure tests pass
kozross Aug 29, 2024
ecb2383
Things in the Builtin namespace in Language.Purus.Prim.* should now h…
Aug 29, 2024
8cec3fb
Ensure tests pass
kozross Aug 29, 2024
c0c3f40
Merge branch 'koz/prelude' of github.com:mlabs-haskell/purus into koz…
kozross Aug 29, 2024
3d23fa8
More prelude
kozross Aug 29, 2024
b30a6a3
Prelude compiles
kozross Aug 30, 2024
8eb43cf
Merge pull request #43 from mlabs-haskell/koz/prelude
kozross Aug 30, 2024
05b145d
Expr Plated instance
kozross Sep 4, 2024
a7a7b21
added/fixed runFullPipeline for end-to-end experimentation and testing
Aug 30, 2024
8b75059
removed gh workflows
Sep 4, 2024
3743173
TH splice for Module CTE loads
kozross Sep 4, 2024
2cb3f8c
Addressed review comments related to outdated notes, mistake in Pipel…
Sep 4, 2024
8fd7f8a
Removed some unnecessary/unused imports & pinned all dependencies w/ …
Sep 4, 2024
069070d
Array -> List in the compiler (mainly committing bc about to do a ver…
Sep 4, 2024
1b4952b
Array -> List in tests.
Sep 4, 2024
18dc58e
CI not working? Maybe this will fix
Sep 4, 2024
9806d82
Removed cabal freeze file, was breaking nix/ci
Sep 4, 2024
c756531
Merge pull request #45 from mlabs-haskell/koz/module-th
gnumonik Sep 4, 2024
b1a60c8
Merge pull request #44 from mlabs-haskell/koz/plated
gnumonik Sep 4, 2024
986a5d0
Fixed some problems that arose from merging Koz's PRs, re-enabled the…
Sep 4, 2024
eb9a832
Removed a probably-will-come-back-to-bite-us semigroup/monoid instanc…
Sep 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use flake
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ bower_components/
node_modules
tmp/
.stack-work/
output
# output
tests/purs/docs/docs/
core-tests/full-core-docs.md
tests/support/package-lock.json
.psc-ide-port
.psc-package/
tags
TAGS
.nvimrc

# Gather source map files from golden tests
.source-maps
Expand All @@ -38,3 +39,8 @@ TAGS
*.ps
*.svg
tests/purs/make/
.direnv/
/.pre-commit-config.yaml
/result*

tests/purus/passing/**/cache-db.json
100 changes: 100 additions & 0 deletions Architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Architecture

This document contains an overview of the *current* architecture of our compiler pipeline. It is not meant to be exhaustive and is intended to serve as a guide for onboarding new developers / make the giant PRs more accessible.


## Step 1: Type Deduction/Synthesis (Language.PureScript.CoreFn.Desugar)

During the research phase of this project, we determined that PIR (Plutus Intermediate Representation) should be our ultimate compilation target (with final compilation to UPLC handled by the PIR compiler). Because PIR is an explicitly typed language, and because the vanilla `CoreFn` AST is not explicitly typed, it is necessary to convert the `Language.PureScript.AST` AST into a typed variant.

Because conversion to `CoreFn` occurs after the initial (vanilla PS) typechecker pass, we receive *most* expressions (but not all of them) annotated with the inferred or explicitly declared type. Desugared expressions or declarations involving type classes, however, are not ignored by the PS typechecker, but we require explicit annotations for explicit type class dictionaries and the functions that operate on them.

This step consists of two main phases:

- First, we traverse every *type* annotation in the vanilla PS `Module` that is the input to our conversion function and desugar constraint types to types that require explicit dictionary arguments. E.g. `Eq a => a -> (...)` becomes `Eq$Dict a -> a -> (...)`.
- Next, we deduce the types. Because top-level declarations are always explicitly typed, we proceed "top-down" from the top-level signature as far as we can, and switch to a "bottom-up" synthesis strategy in cases where the type cannot be determined by the top-level signature.

Some notes:

- We want to preserve quantifiers in this step. While some quantifiers can be eliminated during monomorphization, there is no guarantee that *all* of them will be eliminated (this is not a problem, because PIR supports universal quantification). This requires special machinery when performing type deduction on expressions that contain quantified polymorphic functions, since we must take care to ensure that the type variables "line up".
- We run our desugarer in the same monad stack as the PS TypeChecker, but this is largely a convenience (since it lets us use the PS machinery for binding local variables or type variables, etc). We should *never* perform type inference or make any calls to `unify`.
- The trickiest part of this is ensuring that type information for explicit type class dictionaries is introduced at the correct point. Again, type class dictionaries are not processed by the PS typechecker.

## Step 2: Monomorphization & Inlining (Language.PureScript.CoreFn.Convert.Monomorphize)

PureScript's implementation of Records employs Row Types. Moreover, PureScript supports *polymorphic* records, which are backed by *open rows* (e.g. `{a :: Foo | r}`).

Records in PureScript (unlike in Haskell) are not just syntatic sugar for products - the order of fields in the record is *not* determined by the order of fields in the declaration or expression that introduces the record. *An* order can be established for any fully instantiated (i.e. closed - doesn't contain any type variables of kind `Row Type`) record types - we choose a lexicographic ordering to mirror PureScript's `RowToList` sorting but this is not essenital.

We must, therefore, perform monomorphization on record types in order to transform Object Literals to literal products, transform record accessors into `case` analysis of the product that corresponds to the original record, and transform record updates into product updates.

Because a single polymorphic record type may be instantiated to different concrete types at different places in the AST, we must also inline while we monomorphize.

The general monomorphization procedure is as follows (not a full algorithm):

1. We traverse the AST until we reach an `App` node.
2. We "peel" the App node and get an `(f,args)` where `f` is the "terminal" function expression and `args` is a list of the argument expressions to which it is applied.
3. We check whether the type of `f` is already monomorphic. If it is, we make no change to the node.
4. If `f` is not monomorphic, we strip the quantifiers and check whether we can specialize any bound type variables to a concrete type. E.g. if `f :: forall x. Tuple x x -> x -> Int` and the arguments are `[Tuple String String, String]`, we instantiate `x` to `String`.
5. We recurse down the list of arguments. If we encounter an argument that is a free (term-level) variable that is *not* a Plutus builtin, we inline it, monomorphizing it to the concrete type of the argument if possible.
6. We apply the (possibly monomorphized & inlined) argument to the function and procede to the next argument
until we run out of arguments to process.
7. Finally, we re-quantify the type of `f` in the resulting expression. (It may contain free type variables of kind `Type`, which can be represented in PIR)

The procedure for inlining is:
1. We check whether the (term level) variable we aim to inline is locally scoped (i.e. qualified by source position) or globally scoped (e.g. qualified by module name). For now, we only attempt to inline globally scoped variables (...I forget why...)
2. If the variable is globally scoped (i.e. is the name of a module-level declaration), we lookup the body of the declaration. There are two possibilities here: Either the declaration will be a single non-recursive binding, or it will be a member of a mutually recursive binding group. (PS compiler sorts these for us)
- If the declaration is non-recursive we "walk" its expression-body and monomorphize/inline the sub-expressions as necessary in order to properly assign the expression the type that it is to be monomorphized to.
- If the declaration the member of a recursive binding group, we pause inlining, walk the expression, and "collect" a `Map Name (Name,SourceType,Expr)` where the key is the original name of the expression, and the values are, respectively: The new "fresh" name to give to the monomorphized expression, the monomorphic type that we must assign the expression to, and the body of the declaration. We do this recursively until we have collected every member of the recursive binding group used in the target expression. Finally, we use that map to construct a *monomorphic* mutually recursive binding group (where the names are all fresh) and create a `Let`-binding for the monomorphized mutually recursive group.
gnumonik marked this conversation as resolved.
Show resolved Hide resolved

The implementation of the monomorphizer/inliner consists in a few key functions that call each other recursively. To make reviewing easier, here's a brief explanation of what the key functions do (or are supposed to do at any rate):

- `monomorphizeA` is the entry point that checks whether the node is an `App`, peels the arguments and function parts from the `App`, and calls `handleFunction` on the function expression and its arguments.
- `handleFunction` branches depending on the function expression it is passed:
- If it is passed a `Var` qualified by modulename, and the modulename is `Builtin`, it just returns the variable (since Builtins cannot be meaningfully inlined).
- If it is passed an `Abs`, `handleFunction` tries to instantiate the type variables of the function type with corresponding concrete types of the arguments. If it succeeds, it subsitutes the concrete type in for the bound type variable in all sub-expressions and their types, then calls itself recursively on the body of the `Abs` until the type has been fully monomorphized.
- If it is passed a `Var` that is not a builtin, `handleFunction` attempts to inline the expression the `Var` refers to by calling `inlineAs` with the monomorphized type. If this succeeds, `handleFunction` calls itself recursively with the monomorphized/inlined expression.
- If it is passed anything else as the `f`, it checks whether the function type is monomorphic.
- If the `f` is monomorphic, it applies it to its arguments and returns the resulting expresion.
- If the `f` is not monomorphic, `handleFunction` throws an error.
- `inlineAs` performs inlining and implements the above algorithm. Note that `inlineAs` is passed a PS `Type` argument, which represents the type that the expression corresponding to the `Name` being inlined *should* have after inlining.
- `monomorphizeWithType` rewrites the type of an expression to match the supplied type and (much more importantly) rewrites the types of all sub-expressions to conform with the supplied type of the top-level expression.

## Step 3: Object desugaring and final IR (Language.PureScript.CoreFn.[IR / DesugarObjects])

By the end of step 2, all polymorphic records have been monommorphized that can be monomorphized, but record-specific expression nodes (object updates/accessors/literals) still remain in the AST. In order to ensure that all "invalid" expressions and types have been desugared/eliminated prior to final PIR conversion, we define a restricted AST and `Type` type such that only expressions which can be converted into PIR can be represented - a kind of "parse-don't-validate" approach. (This AST is implemented with the `Bound` library.)

At this stage, we construct a set of dictionaries for type and data constructors. When constructing these maps, we add an arbitrary number of constructors for anonymous products (i.e. tuples) to accommodate objects. Specifically, we add constructors for tuples of up to 100 (they look like `data $GEN.~Tuple1 a = $GEN.~Tuple1 a` etc). These dictionaries serve two purposes:
- We construct them in such a way that the SOP representation of the underlying data type is very explicit. I.e. for each *type* constructor, we construct an `[(Int,[Type])]` where the `Int` represents the corresponding data constructor's index in the data type, where this information (the constructor's index & arguments) is also available in the dictionary for each *data* constructor. (Due to the implementation of the PS AST, we need both of these dictionaries, even though in principle only the tycon dictionary is necessary)
- Embedding generated tuple types into these dictionaries allows us to treat desugared records as "normal" data types in the final compilation stage (i.e. they don't require any special handling).

Conversion into this restricted IR AST is, aside from object expressions, very straightforward. Therefore, in the rest of this section I will explain the object desugaring process.

### Object Literals

1. We extract a `Map PSString SourceType` from the object literal expression by inspecting the expressions in each field.
2. We sort the fields lexicographically (which establishes the uniform order of the product that will be constructed).
3. We generate "fake" names for the product's type and constructor. E.g. `$GEN.~Tuple2 a b`.
4. We construct a specialized function type for the product's data constructor using the sorted arguments.
5. We assemble the literal with the "fake" constructor function and the arguments.

### Record Accessors
1. We perform steps 1-4 of Object Literals conversion on the expression the accessor is being applied to, except we construct a Constructor `Binder` (a pattern), where the arguments are wildcard binders for every argument except the one that corresponds to the field being accessed.
2. We use that pattern to construct a case expression that extracts the value corresponding to the field.
- This is kind of hard to explain without an example. Suppose we have `foo = {a: 1, b :: "yup"}` in `foo.b`
- That gets turned into (something like) `case foo of {$GEN.Tuple2 _ $HERE -> $HERE} `

### Record Updates
1. Proceeds much like the accessor case, except we return a product in our case expression instead of returning a field.
- Using the above definition of `foo`, if we have `foo {b = "hello"}`, this turns into:
- `case foo of {$GEN.Tuple2 a _ -> $GEN.Tuple2 a "hello"}`

## Step 4: Final Conversion to PIR (Language.PureScript.CoreFn.Convert.ToPIR)

The final step of compilation is conceptually simple: We match on the constructors of our final IR and translate expressions (and the types they contain) into PIR `Term`s and `Type`s, using some machinery to generate fresh names when we need to construct a lambda (which should only happen when desugaring case expressions).

NOTE: The *implementation* of case expressions is incredibly complex. At the moment we support matching on simple constructor patterns. Going forward, we ought to weak the final IR so that case expressions are presented in a form that makes it simpler to handle.




135 changes: 135 additions & 0 deletions CompilerBugs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
NOT COMPILING:
gnumonik marked this conversation as resolved.
Show resolved Hide resolved

* mutuallyRecursiveBindinGroup
- Not abstracting variables correctly in lambda bodies
- Probably we use an abstract fn that only looks for the var bound in the lambda, should be easy to fix
-------------
letrec
!f_111 : integer -> integer = \(x_112 : integer) -> g_109 2
!g_109 : integer -> integer = \(y_110 : integer) -> h_106 (f_105 y_110) 3
!h_106 : integer -> integer -> integer
= \(x_107 : integer) (y_108 : integer) -> y_108
in
g_109 3
*** Exception: user error (Error during PIR typechecking:
Free variable at () : f)
-------------


* mutuallyRecursiveBindinGroupNoTypes
- Same as above


* aFunction4
- This *should* fail b/c it mentions a polymorphic record in the type sig
- it works when applied to an argument that lets us monomorphize, see aFunction5


* aFunction6
- Fails during object desugaring, seems like an unknown remains in there, likely related to the above list issue
-------------
let
go#185 = \(v#186 :: forall (z :: Prim.Type). ((z :: Prim.Type) -> (Prim.Int))) ->
(10 :: Prim.Int)
in \(any#181 :: Array (t148)) ->
\(f#182 :: (forall (y :: Prim.Type). ((y :: Prim.Type) -> (Prim.Int)) -> (Prim.Int))) ->
f#182 # any#181
# Prim.Nil
# go#185
*** Exception: user error (Unsupported type:
t148)
-------------


* recF1 / recG1 (mutually recursive)
- We're getting 'free variable' errors, probably what's happening is that
we need to bind all top level module identifiers like we do for let binding groups (should be ez fix)
-------------
/\x_96 -> \(x_48 : x_96) -> recF1_47 {x_96} x_48
*** Exception: user error (Error during PIR typechecking:
Free variable at () : recF1)
-------------


* nestedApplications
- Case expression wasn't eliminated properly. This is easy to fix, we just need to port over the
catchall handling machinery from `desugarConstructorPattern` to `desugarLiteralPattern`
-------------
*** Exception: Case expressions should be eliminated by now, but found:

case v#86 of
2 ->
(3 :: Prim.Int)
_ ->
(5 :: Prim.Int)
CallStack (from HasCallStack):
error, called at src/Language/PureScript/CoreFn/Convert/ToPIR.hs:269:17 in purescript-0.15.13-inplace:Language.PureScript.CoreFn.Convert.ToPIR
-------------


* consEmptyList1 / consEmptyList2
- Same error as the other list stuff
-------------
(/\a_191 ->
\(x_136 : integer) ->
/\a_191 -> \(xs_137 : Array_190 a_191) -> Cons_194 {integer} x_136 Nil_193)
1
Nil_193
*** Exception: user error (Error during PIR typechecking:
Type mismatch at () in term
'[ { Cons (con integer) } x ]'.
Expected type
'(fun * *)',
found type
'[ Array (con integer) ]')
-------------


* testEqViaOrd
- We expect the dictionary to have a record type in DesugarObjects but getting the dict via
superclass is a fn from the dict to the subclass method
-------------
\(dictOrd#129 :: forall (a :: Prim.Type). ((Lib.Ord$Dict ((a :: Prim.Type))) -> (((a :: Prim.Type) -> (((a :: Prim.Type) -> (Prim.Boolean))))))) ->
\(a#130 :: (a :: Prim.Type)) ->
\(b#131 :: (a :: Prim.Type)) ->
\(dict#125 :: forall (a :: Prim.Type). (Lib.Eq$Dict ((a :: Prim.Type)))) ->
case dict#125 of
Eq$Dict v126@({ eq :: ((a :: Prim.Type) -> (((a :: Prim.Type) -> (Prim.Boolean)))) }) ->
(v#126).eq
# a#130
# (dictOrd#129).Eq0 # ({} :: (Prim.Record ({})))
# b#131
*** Exception: ERROR: Record expression:
dictOrd#129
should have a Record type, but instead has type:
(Lib.Ord$Dict ((a :: Prim.Type)))
CallStack (from HasCallStack):
error, called at src/Language/PureScript/CoreFn/Convert/DesugarObjects.hs:444:35 in purescript-0.15.13-inplace:Language.PureScript.CoreFn.Convert.DesugarObjects
-------------


* testValidatorApplied
- Free type variable. We lost the quantifiers somewhere here. Probably in the monomorphizer? This seems annoying b/c it worked last week, some of the other fixes must have broken it -_-
- Weirdly, the unapplied version works. I think that adding the explicit type abstractions is interacting weirdly with the monomorphizer.
-------------
==========END desugarCoreDecl: aBool==========
\(datum#20 :: Prim.String) ->
\(redeemer#21 :: (b :: Prim.Type)) ->
\(context#22 :: (c :: Prim.Type)) ->
Prim.True
# ("datum" :: Prim.String)
# ("redeemer" :: Prim.String)
# ("context" :: Prim.String)
tryConvertExpr result:
\(datum#20 :: Prim.String) ->
\(redeemer#21 :: (b :: *)) ->
\(context#22 :: (c :: *)) ->
Prim.True
# ("datum" :: Prim.String)
# ("redeemer" :: Prim.String)
# ("context" :: Prim.String)

*** Exception: Free type variable in IR: c
CallStack (from HasCallStack):
error, called at src/Language/PureScript/CoreFn/Convert/Datatypes.hs:186:16 in purescript-0.15.13-inplace:Language.PureScript.CoreFn.Convert.Datatypes
-------------
19 changes: 19 additions & 0 deletions cabal.project
Original file line number Diff line number Diff line change
@@ -1,2 +1,21 @@
repository cardano-haskell-packages
url: https://input-output-hk.github.io/cardano-haskell-packages
secure: True
root-keys:
3e0cce471cf09815f930210f7827266fd09045445d65923e6d0238a6cd15126f
443abb7fb497a134c343faf52f0b659bd7999bc06b7f63fa76dc99d631f9bea1
a86a1f6ce86c449c46666bda44268677abf29b5b2d2eb5ec7af903ec2f117a82
bcec67e8e99cabfa7764d75ad9b158d72bfacf70ca1d0ec8bc6b4406d1bf8413
c00aae8461a256275598500ea0e187588c35a5d5d7454fb57eac18d9edb86a56
d4a35cd3121aa00d18544bb0ac01c3e1691d618f462c46129271bccf39f7e8ee


packages:
purescript.cabal

-- HACK: plutus core cannot build without it, remove after bump.
constraints:
nothunks < 0.2

index-state:
, cardano-haskell-packages 2024-06-27T10:04:00Z
Loading
Loading