mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Merge pull request #5668 from roc-lang/checkmate
Add "checkmate", a tool for the solver
This commit is contained in:
commit
6225b80e01
56 changed files with 21512 additions and 423 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -85,3 +85,6 @@ www/src/roc-tutorial
|
|||
|
||||
# snapshot tests temp file
|
||||
*.pending-snap
|
||||
|
||||
# checkmate
|
||||
checkmate_*.json
|
||||
|
|
168
Cargo.lock
generated
168
Cargo.lock
generated
|
@ -88,6 +88,21 @@ dependencies = [
|
|||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.3.2"
|
||||
|
@ -473,6 +488,21 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"time 0.1.45",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
|
@ -1094,6 +1124,12 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
|
@ -1394,7 +1430,7 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
|
@ -1653,6 +1689,29 @@ dependencies = [
|
|||
"tokio-rustls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys 0.8.4",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iced-x86"
|
||||
version = "1.18.0"
|
||||
|
@ -1975,7 +2034,7 @@ dependencies = [
|
|||
"libc",
|
||||
"log",
|
||||
"thiserror",
|
||||
"time",
|
||||
"time 0.3.21",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
|
@ -2106,7 +2165,7 @@ checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
|
@ -3095,6 +3154,7 @@ dependencies = [
|
|||
"page_size",
|
||||
"roc_builtins",
|
||||
"roc_can",
|
||||
"roc_checkmate",
|
||||
"roc_collections",
|
||||
"roc_error_macros",
|
||||
"roc_load",
|
||||
|
@ -3105,6 +3165,7 @@ dependencies = [
|
|||
"roc_region",
|
||||
"roc_reporting",
|
||||
"roc_solve",
|
||||
"roc_solve_schema",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
|
@ -3203,6 +3264,27 @@ dependencies = [
|
|||
"ven_pretty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roc_checkmate"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"roc_checkmate_schema",
|
||||
"roc_module",
|
||||
"roc_solve_schema",
|
||||
"roc_types",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roc_checkmate_schema"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roc_cli"
|
||||
version = "0.0.1"
|
||||
|
@ -3311,11 +3393,13 @@ version = "0.0.1"
|
|||
dependencies = [
|
||||
"bumpalo",
|
||||
"roc_can",
|
||||
"roc_checkmate",
|
||||
"roc_collections",
|
||||
"roc_derive_key",
|
||||
"roc_error_macros",
|
||||
"roc_module",
|
||||
"roc_region",
|
||||
"roc_solve_schema",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
]
|
||||
|
@ -3564,11 +3648,13 @@ version = "0.0.1"
|
|||
dependencies = [
|
||||
"bumpalo",
|
||||
"roc_can",
|
||||
"roc_checkmate",
|
||||
"roc_collections",
|
||||
"roc_derive",
|
||||
"roc_error_macros",
|
||||
"roc_module",
|
||||
"roc_solve",
|
||||
"roc_solve_schema",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
]
|
||||
|
@ -3630,6 +3716,7 @@ dependencies = [
|
|||
"pretty_assertions",
|
||||
"roc_builtins",
|
||||
"roc_can",
|
||||
"roc_checkmate",
|
||||
"roc_collections",
|
||||
"roc_constrain",
|
||||
"roc_debug_flags",
|
||||
|
@ -3917,6 +4004,7 @@ dependencies = [
|
|||
"regex",
|
||||
"roc_builtins",
|
||||
"roc_can",
|
||||
"roc_checkmate",
|
||||
"roc_collections",
|
||||
"roc_debug_flags",
|
||||
"roc_derive",
|
||||
|
@ -3932,6 +4020,7 @@ dependencies = [
|
|||
"roc_reporting",
|
||||
"roc_solve",
|
||||
"roc_solve_problem",
|
||||
"roc_solve_schema",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
"roc_unify",
|
||||
|
@ -3952,6 +4041,13 @@ dependencies = [
|
|||
"roc_types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roc_solve_schema"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roc_std"
|
||||
version = "0.0.1"
|
||||
|
@ -4011,11 +4107,12 @@ dependencies = [
|
|||
name = "roc_unify"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"roc_checkmate",
|
||||
"roc_collections",
|
||||
"roc_debug_flags",
|
||||
"roc_error_macros",
|
||||
"roc_module",
|
||||
"roc_solve_schema",
|
||||
"roc_tracing",
|
||||
"roc_types",
|
||||
]
|
||||
|
@ -4161,6 +4258,30 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"schemars_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
|
@ -4249,6 +4370,17 @@ dependencies = [
|
|||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.96"
|
||||
|
@ -4803,6 +4935,17 @@ dependencies = [
|
|||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.21"
|
||||
|
@ -4947,7 +5090,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"time",
|
||||
"time 0.3.21",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
|
@ -5257,6 +5400,12 @@ dependencies = [
|
|||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
@ -5581,6 +5730,15 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
|
|
|
@ -82,6 +82,7 @@ bumpalo = { version = "3.12.0", features = ["collections"] }
|
|||
bytemuck = { version = "1.13.1", features = ["derive"] }
|
||||
capstone = { version = "0.11.0", default-features = false }
|
||||
cgmath = "0.18.0"
|
||||
chrono = "0.4.26"
|
||||
clap = { version = "4.2.7", default-features = false, features = ["std", "color", "suggestions", "help", "usage", "error-context"] }
|
||||
colored = "2.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
@ -141,6 +142,7 @@ reqwest = { version = "0.11.14", default-features = false, features = ["blocking
|
|||
rlimit = "0.9.1"
|
||||
rustyline = { git = "https://github.com/roc-lang/rustyline", rev = "e74333c" }
|
||||
rustyline-derive = { git = "https://github.com/roc-lang/rustyline", rev = "e74333c" }
|
||||
schemars = "0.8.12"
|
||||
serde = { version = "1.0.153", features = ["derive"] } # update roc_std/Cargo.toml on change
|
||||
serde-xml-rs = "0.6.0"
|
||||
serde_json = "1.0.94" # update roc_std/Cargo.toml on change
|
||||
|
|
|
@ -10,6 +10,7 @@ version.workspace = true
|
|||
[dependencies]
|
||||
roc_builtins = { path = "../compiler/builtins" }
|
||||
roc_can = { path = "../compiler/can" }
|
||||
roc_checkmate = { path = "../compiler/checkmate" }
|
||||
roc_collections = { path = "../compiler/collections" }
|
||||
roc_error_macros = { path = "../error_macros" }
|
||||
roc_load = { path = "../compiler/load" }
|
||||
|
@ -20,6 +21,7 @@ roc_problem = { path = "../compiler/problem" }
|
|||
roc_region = { path = "../compiler/region" }
|
||||
roc_reporting = { path = "../reporting" }
|
||||
roc_solve = { path = "../compiler/solve" }
|
||||
roc_solve_schema = { path = "../compiler/solve_schema" }
|
||||
roc_target = { path = "../compiler/roc_target" }
|
||||
roc_types = { path = "../compiler/types" }
|
||||
roc_unify = { path = "../compiler/unify" }
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
#![allow(dead_code)]
|
||||
use bumpalo::Bump;
|
||||
use roc_can::expected::{Expected, PExpected};
|
||||
use roc_checkmate::with_checkmate;
|
||||
use roc_collections::all::{BumpMap, BumpMapDefault, MutMap};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_solve::module::Solved;
|
||||
use roc_solve_schema::UnificationMode;
|
||||
use roc_types::subs::{
|
||||
self, AliasVariables, Content, Descriptor, FlatType, Mark, OptVariable, Rank, RecordFields,
|
||||
Subs, SubsSlice, TagExt, UnionLambdas, UnionTags, Variable, VariableSubsSlice,
|
||||
|
@ -17,9 +19,8 @@ use roc_types::types::{
|
|||
RecordField,
|
||||
};
|
||||
use roc_unify::unify::unify;
|
||||
use roc_unify::unify::Env as UEnv;
|
||||
use roc_unify::unify::Mode;
|
||||
use roc_unify::unify::Unified::*;
|
||||
use roc_unify::Env as UEnv;
|
||||
|
||||
use crate::constrain::{Constraint, PresenceConstraint};
|
||||
use crate::lang::core::types::Type2;
|
||||
|
@ -228,10 +229,13 @@ fn solve<'a>(
|
|||
);
|
||||
|
||||
match unify(
|
||||
&mut UEnv::new(subs),
|
||||
&mut with_checkmate!({
|
||||
on => UEnv::new(subs, None),
|
||||
off => UEnv::new(subs),
|
||||
}),
|
||||
actual,
|
||||
expected,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::OF_VALUE,
|
||||
) {
|
||||
Success {
|
||||
|
@ -326,10 +330,13 @@ fn solve<'a>(
|
|||
);
|
||||
|
||||
match unify(
|
||||
&mut UEnv::new(subs),
|
||||
&mut with_checkmate!({
|
||||
on => UEnv::new(subs, None),
|
||||
off => UEnv::new(subs),
|
||||
}),
|
||||
actual,
|
||||
expected,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::OF_VALUE,
|
||||
) {
|
||||
Success {
|
||||
|
@ -402,10 +409,13 @@ fn solve<'a>(
|
|||
|
||||
// TODO(ayazhafiz): presence constraints for Expr2/Type2
|
||||
match unify(
|
||||
&mut UEnv::new(subs),
|
||||
&mut with_checkmate!({
|
||||
on => UEnv::new(subs, None),
|
||||
off => UEnv::new(subs),
|
||||
}),
|
||||
actual,
|
||||
expected,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::OF_PATTERN,
|
||||
) {
|
||||
Success {
|
||||
|
@ -718,10 +728,13 @@ fn solve<'a>(
|
|||
let includes = type_to_var(arena, mempool, subs, rank, pools, cached_aliases, &tag_ty);
|
||||
|
||||
match unify(
|
||||
&mut UEnv::new(subs),
|
||||
&mut with_checkmate!({
|
||||
on => UEnv::new(subs, None),
|
||||
off => UEnv::new(subs),
|
||||
}),
|
||||
actual,
|
||||
includes,
|
||||
Mode::PRESENT,
|
||||
UnificationMode::PRESENT,
|
||||
Polarity::OF_PATTERN,
|
||||
) {
|
||||
Success {
|
||||
|
|
19
crates/compiler/checkmate/Cargo.toml
Normal file
19
crates/compiler/checkmate/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "roc_checkmate"
|
||||
description = "A framework for debugging the solver."
|
||||
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
roc_checkmate_schema = { path = "../checkmate_schema" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_solve_schema = { path = "../solve_schema" }
|
||||
roc_types = { path = "../types" }
|
||||
chrono.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
roc_checkmate_schema = { path = "../checkmate_schema" }
|
||||
serde_json.workspace = true
|
5
crates/compiler/checkmate/README.md
Normal file
5
crates/compiler/checkmate/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# `checkmate`
|
||||
|
||||
A tool to debug the solver (checker + inference + specialization engine).
|
||||
|
||||
See [the document](https://rwx.notion.site/Type-debugging-tools-de42260060784cacbaf08ea4d61e0eb9?pvs=4).
|
13
crates/compiler/checkmate/build.rs
Normal file
13
crates/compiler/checkmate/build.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
use std::fs;
|
||||
|
||||
use roc_checkmate_schema::AllEvents;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=../checkmate_schema");
|
||||
let schema = AllEvents::schema();
|
||||
fs::write(
|
||||
"schema.json",
|
||||
serde_json::to_string_pretty(&schema).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
907
crates/compiler/checkmate/schema.json
Normal file
907
crates/compiler/checkmate/schema.json
Normal file
|
@ -0,0 +1,907 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "AllEvents",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Event"
|
||||
},
|
||||
"definitions": {
|
||||
"AliasKind": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Structural"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Opaque"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"AliasTypeVariables": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"infer_ext_in_output_position_variables",
|
||||
"lambda_set_variables",
|
||||
"type_variables"
|
||||
],
|
||||
"properties": {
|
||||
"infer_ext_in_output_position_variables": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
},
|
||||
"lambda_set_variables": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
},
|
||||
"type_variables": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ClosureType": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"environment",
|
||||
"function"
|
||||
],
|
||||
"properties": {
|
||||
"environment": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
},
|
||||
"function": {
|
||||
"$ref": "#/definitions/Symbol"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Content": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Flex"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Rigid"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"abilities",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"abilities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Symbol"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"FlexAble"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"abilities",
|
||||
"name",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"abilities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Symbol"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"RigidAble"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"structure",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"structure": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Recursive"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ambient_function",
|
||||
"solved",
|
||||
"type",
|
||||
"unspecialized"
|
||||
],
|
||||
"properties": {
|
||||
"ambient_function": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"recursion_var": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"solved": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ClosureType"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"LambdaSet"
|
||||
]
|
||||
},
|
||||
"unspecialized": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/UnspecializedClosureType"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ErasedLambda"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"name",
|
||||
"real_variable",
|
||||
"type",
|
||||
"variables"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"$ref": "#/definitions/AliasKind"
|
||||
},
|
||||
"name": {
|
||||
"$ref": "#/definitions/Symbol"
|
||||
},
|
||||
"real_variable": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Alias"
|
||||
]
|
||||
},
|
||||
"variables": {
|
||||
"$ref": "#/definitions/AliasTypeVariables"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"symbol",
|
||||
"type",
|
||||
"variables"
|
||||
],
|
||||
"properties": {
|
||||
"symbol": {
|
||||
"$ref": "#/definitions/Symbol"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Apply"
|
||||
]
|
||||
},
|
||||
"variables": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"arguments",
|
||||
"lambda_type",
|
||||
"ret",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"arguments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
},
|
||||
"lambda_type": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"ret": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"extension",
|
||||
"fields",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"extension": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"fields": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/RecordField"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Record"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"elements",
|
||||
"extension",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"elements": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
},
|
||||
"extension": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Tuple"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"extension",
|
||||
"tags",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"extension": {
|
||||
"$ref": "#/definitions/TagUnionExtension"
|
||||
},
|
||||
"tags": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"TagUnion"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"extension",
|
||||
"functions",
|
||||
"tags",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"extension": {
|
||||
"$ref": "#/definitions/TagUnionExtension"
|
||||
},
|
||||
"functions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Symbol"
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"FunctionOrTagUnion"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"extension",
|
||||
"recursion_var",
|
||||
"tags",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"extension": {
|
||||
"$ref": "#/definitions/TagUnionExtension"
|
||||
},
|
||||
"recursion_var": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"tags": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"RecursiveTagUnion"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"EmptyRecord"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"EmptyTuple"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"EmptyTagUnion"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"range",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"range": {
|
||||
"$ref": "#/definitions/NumericRange"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"RangedNumber"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Error"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Event": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"left",
|
||||
"mode",
|
||||
"right",
|
||||
"subevents",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"left": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"mode": {
|
||||
"$ref": "#/definitions/UnificationMode"
|
||||
},
|
||||
"right": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"subevents": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Event"
|
||||
}
|
||||
},
|
||||
"success": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Unification"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"from",
|
||||
"to",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"from": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"to": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"VariableUnified"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"variable"
|
||||
],
|
||||
"properties": {
|
||||
"content": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Content"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"rank": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Rank"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"VariableSetDescriptor"
|
||||
]
|
||||
},
|
||||
"variable": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"NumericRange": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"min_width",
|
||||
"signed"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"$ref": "#/definitions/NumericRangeKind"
|
||||
},
|
||||
"min_width": {
|
||||
"type": "integer",
|
||||
"format": "uint32",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"signed": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NumericRangeKind": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Int"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"AnyNum"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Rank": {
|
||||
"type": "integer",
|
||||
"format": "uint32",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"RecordField": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"field_type",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"field_type": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"kind": {
|
||||
"$ref": "#/definitions/RecordFieldKind"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RecordFieldKind": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Demanded"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"rigid",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"rigid": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Required"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"rigid",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"rigid": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Optional"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Symbol": {
|
||||
"type": "string"
|
||||
},
|
||||
"TagUnionExtension": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"variable"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Openness"
|
||||
]
|
||||
},
|
||||
"variable": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"variable"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Any"
|
||||
]
|
||||
},
|
||||
"variable": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"UnificationMode": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Eq"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Present"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"LambdaSetSpecialization"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"UnspecializedClosureType": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ability_member",
|
||||
"lambda_set_region",
|
||||
"specialization"
|
||||
],
|
||||
"properties": {
|
||||
"ability_member": {
|
||||
"$ref": "#/definitions/Symbol"
|
||||
},
|
||||
"lambda_set_region": {
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"specialization": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Variable": {
|
||||
"type": "integer",
|
||||
"format": "uint32",
|
||||
"minimum": 0.0
|
||||
}
|
||||
}
|
||||
}
|
175
crates/compiler/checkmate/src/collector.rs
Normal file
175
crates/compiler/checkmate/src/collector.rs
Normal file
|
@ -0,0 +1,175 @@
|
|||
use std::error::Error;
|
||||
|
||||
use roc_checkmate_schema::{AllEvents, Event};
|
||||
use roc_types::subs as s;
|
||||
|
||||
use crate::convert::AsSchema;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Collector {
|
||||
events: AllEvents,
|
||||
current_event_path: Vec<usize>,
|
||||
}
|
||||
|
||||
impl Default for Collector {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Collector {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
events: AllEvents(Vec::new()),
|
||||
current_event_path: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unify(&mut self, subs: &s::Subs, from: s::Variable, to: s::Variable) {
|
||||
let to = to.as_schema(subs);
|
||||
let from = from.as_schema(subs);
|
||||
self.add_event(Event::VariableUnified { to, from });
|
||||
}
|
||||
|
||||
pub fn set_content(&mut self, subs: &s::Subs, var: s::Variable, content: s::Content) {
|
||||
let variable = var.as_schema(subs);
|
||||
let content = content.as_schema(subs);
|
||||
self.add_event(Event::VariableSetDescriptor {
|
||||
variable,
|
||||
content: Some(content),
|
||||
rank: None,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_rank(&mut self, subs: &s::Subs, var: s::Variable, rank: s::Rank) {
|
||||
let variable = var.as_schema(subs);
|
||||
let rank = rank.as_schema(subs);
|
||||
self.add_event(Event::VariableSetDescriptor {
|
||||
variable,
|
||||
rank: Some(rank),
|
||||
content: None,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_descriptor(&mut self, subs: &s::Subs, var: s::Variable, descriptor: s::Descriptor) {
|
||||
let variable = var.as_schema(subs);
|
||||
let rank = descriptor.rank.as_schema(subs);
|
||||
let content = descriptor.content.as_schema(subs);
|
||||
self.add_event(Event::VariableSetDescriptor {
|
||||
variable,
|
||||
rank: Some(rank),
|
||||
content: Some(content),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn start_unification(
|
||||
&mut self,
|
||||
subs: &s::Subs,
|
||||
left: s::Variable,
|
||||
right: s::Variable,
|
||||
mode: roc_solve_schema::UnificationMode,
|
||||
) {
|
||||
let left = left.as_schema(subs);
|
||||
let right = right.as_schema(subs);
|
||||
let mode = mode.as_schema(subs);
|
||||
let subevents = Vec::new();
|
||||
self.add_event(Event::Unification {
|
||||
left,
|
||||
right,
|
||||
mode,
|
||||
subevents,
|
||||
success: None,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn end_unification(
|
||||
&mut self,
|
||||
subs: &s::Subs,
|
||||
left: s::Variable,
|
||||
right: s::Variable,
|
||||
success: bool,
|
||||
) {
|
||||
let current_event = self.get_path_event();
|
||||
match current_event {
|
||||
EventW::Sub(Event::Unification {
|
||||
left: l,
|
||||
right: r,
|
||||
success: s,
|
||||
..
|
||||
}) => {
|
||||
assert_eq!(left.as_schema(subs), *l);
|
||||
assert_eq!(right.as_schema(subs), *r);
|
||||
assert!(s.is_none());
|
||||
*s = Some(success);
|
||||
}
|
||||
_ => panic!("end_unification called when not in a unification"),
|
||||
}
|
||||
self.current_event_path.pop();
|
||||
}
|
||||
|
||||
pub fn write(&self, writer: impl std::io::Write) -> Result<(), Box<dyn Error>> {
|
||||
self.events.write(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_event(&mut self, event: impl Into<Event>) {
|
||||
let mut event = event.into();
|
||||
let is_appendable = EventW::Sub(&mut event).appendable();
|
||||
let event = event;
|
||||
|
||||
let path_event = self.get_path_event();
|
||||
let new_event_index = path_event.append(event);
|
||||
if is_appendable {
|
||||
self.current_event_path.push(new_event_index);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_path_event(&mut self) -> EventW {
|
||||
let mut event = EventW::Top(&mut self.events);
|
||||
for i in &self.current_event_path {
|
||||
event = event.index(*i);
|
||||
}
|
||||
event
|
||||
}
|
||||
}
|
||||
|
||||
enum EventW<'a> {
|
||||
Top(&'a mut AllEvents),
|
||||
Sub(&'a mut Event),
|
||||
}
|
||||
|
||||
impl<'a> EventW<'a> {
|
||||
fn append(self, event: Event) -> usize {
|
||||
let list = self.subevents_mut().unwrap();
|
||||
let index = list.len();
|
||||
list.push(event);
|
||||
index
|
||||
}
|
||||
|
||||
fn appendable(self) -> bool {
|
||||
self.subevents().is_some()
|
||||
}
|
||||
|
||||
fn index(self, index: usize) -> EventW<'a> {
|
||||
Self::Sub(&mut self.subevents_mut().unwrap()[index])
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> EventW<'a> {
|
||||
fn subevents(self) -> Option<&'a Vec<Event>> {
|
||||
use EventW::*;
|
||||
match self {
|
||||
Top(events) => Some(&events.0),
|
||||
Sub(Event::Unification { subevents, .. }) => Some(subevents),
|
||||
Sub(Event::VariableUnified { .. } | Event::VariableSetDescriptor { .. }) => None,
|
||||
}
|
||||
}
|
||||
fn subevents_mut(self) -> Option<&'a mut Vec<Event>> {
|
||||
use EventW::*;
|
||||
match self {
|
||||
Top(events) => Some(&mut events.0),
|
||||
Sub(Event::Unification { subevents, .. }) => Some(subevents),
|
||||
Sub(Event::VariableUnified { .. } | Event::VariableSetDescriptor { .. }) => None,
|
||||
}
|
||||
}
|
||||
}
|
323
crates/compiler/checkmate/src/convert.rs
Normal file
323
crates/compiler/checkmate/src/convert.rs
Normal file
|
@ -0,0 +1,323 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use roc_module::{ident, symbol};
|
||||
use roc_types::{
|
||||
num,
|
||||
subs::{self, GetSubsSlice, Subs, SubsIndex, SubsSlice, UnionLabels},
|
||||
types,
|
||||
};
|
||||
|
||||
use roc_checkmate_schema::{
|
||||
AliasKind, AliasTypeVariables, ClosureType, Content, NumericRange, NumericRangeKind, Rank,
|
||||
RecordField, RecordFieldKind, Symbol, TagUnionExtension, UnificationMode,
|
||||
UnspecializedClosureType, Variable,
|
||||
};
|
||||
|
||||
pub trait AsSchema<T> {
|
||||
fn as_schema(&self, subs: &Subs) -> T;
|
||||
}
|
||||
|
||||
impl<T, U> AsSchema<Option<U>> for Option<T>
|
||||
where
|
||||
T: AsSchema<U>,
|
||||
T: Copy,
|
||||
{
|
||||
fn as_schema(&self, subs: &Subs) -> Option<U> {
|
||||
self.map(|i| i.as_schema(subs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> AsSchema<Vec<U>> for &[T]
|
||||
where
|
||||
T: AsSchema<U>,
|
||||
{
|
||||
fn as_schema(&self, subs: &Subs) -> Vec<U> {
|
||||
self.iter().map(|i| i.as_schema(subs)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> AsSchema<U> for SubsIndex<T>
|
||||
where
|
||||
Subs: std::ops::Index<SubsIndex<T>, Output = T>,
|
||||
T: AsSchema<U>,
|
||||
{
|
||||
fn as_schema(&self, subs: &Subs) -> U {
|
||||
subs[*self].as_schema(subs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> AsSchema<Vec<U>> for SubsSlice<T>
|
||||
where
|
||||
Subs: GetSubsSlice<T>,
|
||||
T: AsSchema<U>,
|
||||
{
|
||||
fn as_schema(&self, subs: &Subs) -> Vec<U> {
|
||||
subs.get_subs_slice(*self)
|
||||
.iter()
|
||||
.map(|i| i.as_schema(subs))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<Content> for subs::Content {
|
||||
fn as_schema(&self, subs: &Subs) -> Content {
|
||||
use {subs::Content as A, Content as B};
|
||||
match self {
|
||||
A::FlexVar(name) => B::Flex(name.as_schema(subs)),
|
||||
A::RigidVar(name) => B::Rigid(name.as_schema(subs)),
|
||||
A::FlexAbleVar(name, abilities) => {
|
||||
B::FlexAble(name.as_schema(subs), abilities.as_schema(subs))
|
||||
}
|
||||
A::RigidAbleVar(name, abilities) => {
|
||||
B::RigidAble(name.as_schema(subs), abilities.as_schema(subs))
|
||||
}
|
||||
A::RecursionVar {
|
||||
structure,
|
||||
opt_name,
|
||||
} => B::Recursive(opt_name.as_schema(subs), structure.as_schema(subs)),
|
||||
A::LambdaSet(lambda_set) => lambda_set.as_schema(subs),
|
||||
A::ErasedLambda => B::ErasedLambda(),
|
||||
A::Structure(flat_type) => flat_type.as_schema(subs),
|
||||
A::Alias(name, type_vars, real_var, kind) => B::Alias(
|
||||
name.as_schema(subs),
|
||||
type_vars.as_schema(subs),
|
||||
real_var.as_schema(subs),
|
||||
kind.as_schema(subs),
|
||||
),
|
||||
A::RangedNumber(range) => B::RangedNumber(range.as_schema(subs)),
|
||||
A::Error => B::Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<Content> for subs::FlatType {
|
||||
fn as_schema(&self, subs: &Subs) -> Content {
|
||||
match self {
|
||||
subs::FlatType::Apply(symbol, variables) => {
|
||||
Content::Apply(symbol.as_schema(subs), variables.as_schema(subs))
|
||||
}
|
||||
subs::FlatType::Func(arguments, closure, ret) => Content::Function(
|
||||
arguments.as_schema(subs),
|
||||
closure.as_schema(subs),
|
||||
ret.as_schema(subs),
|
||||
),
|
||||
subs::FlatType::Record(fields, ext) => {
|
||||
Content::Record(fields.as_schema(subs), ext.as_schema(subs))
|
||||
}
|
||||
subs::FlatType::Tuple(elems, ext) => {
|
||||
Content::Tuple(elems.as_schema(subs), ext.as_schema(subs))
|
||||
}
|
||||
subs::FlatType::TagUnion(tags, ext) => {
|
||||
Content::TagUnion(tags.as_schema(subs), ext.as_schema(subs))
|
||||
}
|
||||
subs::FlatType::FunctionOrTagUnion(tags, functions, ext) => {
|
||||
Content::FunctionOrTagUnion(
|
||||
functions.as_schema(subs),
|
||||
tags.as_schema(subs),
|
||||
ext.as_schema(subs),
|
||||
)
|
||||
}
|
||||
subs::FlatType::RecursiveTagUnion(rec_var, tags, ext) => Content::RecursiveTagUnion(
|
||||
rec_var.as_schema(subs),
|
||||
tags.as_schema(subs),
|
||||
ext.as_schema(subs),
|
||||
),
|
||||
subs::FlatType::EmptyRecord => Content::EmptyRecord(),
|
||||
subs::FlatType::EmptyTuple => Content::EmptyTuple(),
|
||||
subs::FlatType::EmptyTagUnion => Content::EmptyTagUnion(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<Content> for subs::LambdaSet {
|
||||
fn as_schema(&self, subs: &Subs) -> Content {
|
||||
let subs::LambdaSet {
|
||||
solved,
|
||||
unspecialized,
|
||||
recursion_var,
|
||||
ambient_function,
|
||||
} = self;
|
||||
|
||||
Content::LambdaSet(
|
||||
solved.as_schema(subs),
|
||||
unspecialized.as_schema(subs),
|
||||
recursion_var.as_schema(subs),
|
||||
ambient_function.as_schema(subs),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<String> for ident::Lowercase {
|
||||
fn as_schema(&self, _subs: &Subs) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<Symbol> for symbol::Symbol {
|
||||
fn as_schema(&self, _subs: &Subs) -> Symbol {
|
||||
Symbol(format!("{:#?}", self))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<Variable> for subs::Variable {
|
||||
fn as_schema(&self, _subs: &Subs) -> Variable {
|
||||
Variable(self.index())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<Option<Variable>> for subs::OptVariable {
|
||||
fn as_schema(&self, _subs: &Subs) -> Option<Variable> {
|
||||
self.into_variable().map(|i| i.as_schema(_subs))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<Vec<ClosureType>> for UnionLabels<symbol::Symbol> {
|
||||
fn as_schema(&self, subs: &Subs) -> Vec<ClosureType> {
|
||||
self.iter_from_subs(subs)
|
||||
.map(|(function, environment)| ClosureType {
|
||||
function: function.as_schema(subs),
|
||||
environment: environment.as_schema(subs),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<UnspecializedClosureType> for types::Uls {
|
||||
fn as_schema(&self, subs: &Subs) -> UnspecializedClosureType {
|
||||
let types::Uls(specialization, ability_member, lambda_set_region) = self;
|
||||
|
||||
UnspecializedClosureType {
|
||||
specialization: specialization.as_schema(subs),
|
||||
ability_member: ability_member.as_schema(subs),
|
||||
lambda_set_region: *lambda_set_region,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<AliasTypeVariables> for subs::AliasVariables {
|
||||
fn as_schema(&self, subs: &Subs) -> AliasTypeVariables {
|
||||
let type_variables = self.type_variables().as_schema(subs);
|
||||
let lambda_set_variables = self.lambda_set_variables().as_schema(subs);
|
||||
let infer_ext_in_output_position_variables =
|
||||
self.infer_ext_in_output_variables().as_schema(subs);
|
||||
|
||||
AliasTypeVariables {
|
||||
type_variables,
|
||||
lambda_set_variables,
|
||||
infer_ext_in_output_position_variables,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<AliasKind> for types::AliasKind {
|
||||
fn as_schema(&self, _subs: &Subs) -> AliasKind {
|
||||
match self {
|
||||
types::AliasKind::Structural => AliasKind::Structural,
|
||||
types::AliasKind::Opaque => AliasKind::Opaque,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<HashMap<String, RecordField>> for subs::RecordFields {
|
||||
fn as_schema(&self, subs: &Subs) -> HashMap<String, RecordField> {
|
||||
let mut map = HashMap::new();
|
||||
for (name, var, field) in self.iter_all() {
|
||||
let name = name.as_schema(subs);
|
||||
let field_type = var.as_schema(subs);
|
||||
let kind = field.as_schema(subs);
|
||||
map.insert(name, RecordField { field_type, kind });
|
||||
}
|
||||
map
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<RecordFieldKind> for types::RecordField<()> {
|
||||
fn as_schema(&self, _subs: &Subs) -> RecordFieldKind {
|
||||
match self {
|
||||
types::RecordField::Demanded(_) => RecordFieldKind::Demanded,
|
||||
types::RecordField::Required(_) => RecordFieldKind::Required { rigid: false },
|
||||
types::RecordField::Optional(_) => RecordFieldKind::Optional { rigid: false },
|
||||
types::RecordField::RigidRequired(_) => RecordFieldKind::Required { rigid: true },
|
||||
types::RecordField::RigidOptional(_) => RecordFieldKind::Optional { rigid: true },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<HashMap<u32, Variable>> for subs::TupleElems {
|
||||
fn as_schema(&self, subs: &Subs) -> HashMap<u32, Variable> {
|
||||
let mut map = HashMap::new();
|
||||
for (index, var) in self.iter_all() {
|
||||
let name = subs[index] as _;
|
||||
let var = var.as_schema(subs);
|
||||
map.insert(name, var);
|
||||
}
|
||||
map
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<HashMap<String, Vec<Variable>>> for subs::UnionTags {
|
||||
fn as_schema(&self, subs: &Subs) -> HashMap<String, Vec<Variable>> {
|
||||
let mut map = HashMap::new();
|
||||
for (tag, payloads) in self.iter_from_subs(subs) {
|
||||
map.insert(tag.as_schema(subs), payloads.as_schema(subs));
|
||||
}
|
||||
map
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<TagUnionExtension> for subs::TagExt {
|
||||
fn as_schema(&self, subs: &Subs) -> TagUnionExtension {
|
||||
match self {
|
||||
subs::TagExt::Openness(var) => TagUnionExtension::Openness(var.as_schema(subs)),
|
||||
subs::TagExt::Any(var) => TagUnionExtension::Any(var.as_schema(subs)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<NumericRange> for num::NumericRange {
|
||||
fn as_schema(&self, _subs: &Subs) -> NumericRange {
|
||||
let kind =
|
||||
match self {
|
||||
num::NumericRange::IntAtLeastSigned(_)
|
||||
| num::NumericRange::IntAtLeastEitherSign(_) => NumericRangeKind::Int,
|
||||
num::NumericRange::NumAtLeastSigned(_)
|
||||
| num::NumericRange::NumAtLeastEitherSign(_) => NumericRangeKind::AnyNum,
|
||||
};
|
||||
|
||||
let min_width = self.min_width();
|
||||
let (signedness, width) = min_width.signedness_and_width();
|
||||
let signed = signedness.is_signed();
|
||||
|
||||
NumericRange {
|
||||
kind,
|
||||
signed,
|
||||
min_width: width,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<String> for ident::TagName {
|
||||
fn as_schema(&self, _subs: &Subs) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<Rank> for subs::Rank {
|
||||
fn as_schema(&self, _subs: &Subs) -> Rank {
|
||||
Rank(self.into_usize() as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSchema<UnificationMode> for roc_solve_schema::UnificationMode {
|
||||
fn as_schema(&self, _subs: &Subs) -> UnificationMode {
|
||||
if self.is_eq() {
|
||||
UnificationMode::Eq
|
||||
} else if self.is_present() {
|
||||
UnificationMode::Present
|
||||
} else if self.is_lambda_set_specialization() {
|
||||
UnificationMode::LambdaSetSpecialization
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
62
crates/compiler/checkmate/src/lib.rs
Normal file
62
crates/compiler/checkmate/src/lib.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
mod collector;
|
||||
mod convert;
|
||||
|
||||
pub use collector::Collector;
|
||||
|
||||
pub fn is_checkmate_enabled() -> bool {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let flag = std::env::var("ROC_CHECKMATE");
|
||||
flag.as_deref() == Ok("1")
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! debug_checkmate {
|
||||
($opt_collector:expr, $cm:ident => $expr:expr) => {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
if let Some($cm) = $opt_collector.as_mut() {
|
||||
$expr
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! dump_checkmate {
|
||||
($opt_collector:expr) => {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
if let Some(cm) = $opt_collector.as_ref() {
|
||||
$crate::dump_checkmate(cm);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn dump_checkmate(collector: &Collector) {
|
||||
let timestamp = chrono::Local::now().format("%Y%m%d_%H-%M-%S");
|
||||
let filename = format!("checkmate_{timestamp}.json");
|
||||
let fi = std::fs::File::create(&filename).unwrap();
|
||||
collector.write(fi).unwrap();
|
||||
eprintln!("Wrote checkmate output to {filename}");
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! with_checkmate {
|
||||
({ on => $on:expr, off => $off:expr, }) => {{
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
$on
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
$off
|
||||
}
|
||||
}};
|
||||
}
|
17
crates/compiler/checkmate/www/.gitignore
vendored
Normal file
17
crates/compiler/checkmate/www/.gitignore
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
/coverage
|
||||
|
||||
/build
|
||||
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
18504
crates/compiler/checkmate/www/package-lock.json
generated
Normal file
18504
crates/compiler/checkmate/www/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
45
crates/compiler/checkmate/www/package.json
Normal file
45
crates/compiler/checkmate/www/package.json
Normal file
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"name": "checkmate",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "build:codegen && react-scripts build",
|
||||
"build:codegen": "node ./scripts/gen_schema_dts.js",
|
||||
"check": "tsc",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.18.38",
|
||||
"@types/react": "^18.2.15",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"json-schema-to-typescript": "^13.0.2",
|
||||
"react-scripts": "5.0.1",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
14
crates/compiler/checkmate/www/public/index.html
Normal file
14
crates/compiler/checkmate/www/public/index.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="checkmate in N" />
|
||||
<title>Checkmate</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
24
crates/compiler/checkmate/www/scripts/gen_schema_dts.js
Normal file
24
crates/compiler/checkmate/www/scripts/gen_schema_dts.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
const {compileFromFile} = require("json-schema-to-typescript");
|
||||
const fs = require("node:fs/promises");
|
||||
const path = require("node:path");
|
||||
|
||||
const SCHEMA_PATH = path.resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
"..",
|
||||
"schema.json"
|
||||
);
|
||||
|
||||
const DTS_PATH = path.resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
"src",
|
||||
"schema.d.ts"
|
||||
);
|
||||
|
||||
async function main() {
|
||||
const result = await compileFromFile(SCHEMA_PATH);
|
||||
await fs.writeFile(DTS_PATH, result);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
13
crates/compiler/checkmate/www/src/App.tsx
Normal file
13
crates/compiler/checkmate/www/src/App.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import React from "react";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<p>
|
||||
Edit <code>src/App.tsx</code> and save to reload.
|
||||
</p>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
}
|
3
crates/compiler/checkmate/www/src/index.css
Normal file
3
crates/compiler/checkmate/www/src/index.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
13
crates/compiler/checkmate/www/src/index.tsx
Normal file
13
crates/compiler/checkmate/www/src/index.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById("root") as HTMLElement
|
||||
);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
239
crates/compiler/checkmate/www/src/schema.d.ts
vendored
Normal file
239
crates/compiler/checkmate/www/src/schema.d.ts
vendored
Normal file
|
@ -0,0 +1,239 @@
|
|||
/* eslint-disable */
|
||||
/**
|
||||
* This file was automatically generated by json-schema-to-typescript.
|
||||
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
|
||||
* and run json-schema-to-typescript to regenerate this file.
|
||||
*/
|
||||
|
||||
export type Event =
|
||||
| {
|
||||
left: Variable;
|
||||
mode: UnificationMode;
|
||||
right: Variable;
|
||||
subevents: Event[];
|
||||
success?: boolean | null;
|
||||
type: "Unification";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
from: Variable;
|
||||
to: Variable;
|
||||
type: "VariableUnified";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
content?: Content | null;
|
||||
rank?: Rank | null;
|
||||
type: "VariableSetDescriptor";
|
||||
variable: Variable;
|
||||
[k: string]: unknown;
|
||||
};
|
||||
export type Variable = number;
|
||||
export type UnificationMode =
|
||||
| {
|
||||
type: "Eq";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
type: "Present";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
type: "LambdaSetSpecialization";
|
||||
[k: string]: unknown;
|
||||
};
|
||||
export type Content =
|
||||
| {
|
||||
name?: string | null;
|
||||
type: "Flex";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
name: string;
|
||||
type: "Rigid";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
abilities: Symbol[];
|
||||
name?: string | null;
|
||||
type: "FlexAble";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
abilities: Symbol[];
|
||||
name: string;
|
||||
type: "RigidAble";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
name?: string | null;
|
||||
structure: Variable;
|
||||
type: "Recursive";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
ambient_function: Variable;
|
||||
recursion_var?: Variable | null;
|
||||
solved: ClosureType[];
|
||||
type: "LambdaSet";
|
||||
unspecialized: UnspecializedClosureType[];
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
kind: AliasKind;
|
||||
name: Symbol;
|
||||
real_variable: Variable;
|
||||
type: "Alias";
|
||||
variables: AliasTypeVariables;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
symbol: Symbol;
|
||||
type: "Apply";
|
||||
variables: Variable[];
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
arguments: Variable[];
|
||||
lambda_type: Variable;
|
||||
ret: Variable;
|
||||
type: "Function";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
extension: Variable;
|
||||
fields: {
|
||||
[k: string]: RecordField;
|
||||
};
|
||||
type: "Record";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
elements: {
|
||||
[k: string]: Variable;
|
||||
};
|
||||
extension: Variable;
|
||||
type: "Tuple";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
extension: TagUnionExtension;
|
||||
tags: {
|
||||
[k: string]: Variable[];
|
||||
};
|
||||
type: "TagUnion";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
extension: TagUnionExtension;
|
||||
functions: Symbol[];
|
||||
tags: string[];
|
||||
type: "FunctionOrTagUnion";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
extension: TagUnionExtension;
|
||||
recursion_var: Variable;
|
||||
tags: {
|
||||
[k: string]: Variable[];
|
||||
};
|
||||
type: "RecursiveTagUnion";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
type: "EmptyRecord";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
type: "EmptyTuple";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
type: "EmptyTagUnion";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
range: NumericRange;
|
||||
type: "RangedNumber";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
type: "Error";
|
||||
[k: string]: unknown;
|
||||
};
|
||||
export type Symbol = string;
|
||||
export type AliasKind =
|
||||
| {
|
||||
type: "Structural";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
type: "Opaque";
|
||||
[k: string]: unknown;
|
||||
};
|
||||
export type RecordFieldKind =
|
||||
| {
|
||||
type: "Demanded";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
rigid: boolean;
|
||||
type: "Required";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
rigid: boolean;
|
||||
type: "Optional";
|
||||
[k: string]: unknown;
|
||||
};
|
||||
export type TagUnionExtension =
|
||||
| {
|
||||
type: "Openness";
|
||||
variable: Variable;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
type: "Any";
|
||||
variable: Variable;
|
||||
[k: string]: unknown;
|
||||
};
|
||||
export type NumericRangeKind =
|
||||
| {
|
||||
type: "Int";
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| {
|
||||
type: "AnyNum";
|
||||
[k: string]: unknown;
|
||||
};
|
||||
export type Rank = number;
|
||||
export type AllEvents = Event[];
|
||||
|
||||
export interface ClosureType {
|
||||
environment: Variable[];
|
||||
function: Symbol;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface UnspecializedClosureType {
|
||||
ability_member: Symbol;
|
||||
lambda_set_region: number;
|
||||
specialization: Variable;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface AliasTypeVariables {
|
||||
infer_ext_in_output_position_variables: Variable[];
|
||||
lambda_set_variables: Variable[];
|
||||
type_variables: Variable[];
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface RecordField {
|
||||
field_type: Variable;
|
||||
kind: RecordFieldKind;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface NumericRange {
|
||||
kind: NumericRangeKind;
|
||||
min_width: number;
|
||||
signed: boolean;
|
||||
[k: string]: unknown;
|
||||
}
|
12
crates/compiler/checkmate/www/tailwind.config.js
Normal file
12
crates/compiler/checkmate/www/tailwind.config.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
mode: 'jit',
|
||||
content: [
|
||||
"./src/**/*.{js,jsx,ts,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
20
crates/compiler/checkmate/www/tsconfig.json
Normal file
20
crates/compiler/checkmate/www/tsconfig.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
13
crates/compiler/checkmate_schema/Cargo.toml
Normal file
13
crates/compiler/checkmate_schema/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "roc_checkmate_schema"
|
||||
description = "Schema for checkmate."
|
||||
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
schemars.workspace = true
|
225
crates/compiler/checkmate_schema/src/lib.rs
Normal file
225
crates/compiler/checkmate_schema/src/lib.rs
Normal file
|
@ -0,0 +1,225 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use schemars::{schema::RootSchema, schema_for, JsonSchema};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Constraint {}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug, PartialEq)]
|
||||
pub struct Variable(pub u32);
|
||||
|
||||
macro_rules! impl_content {
|
||||
($($name:ident { $($arg:ident: $ty:ty,)* },)*) => {
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Content {
|
||||
$(
|
||||
$name {
|
||||
$($arg: $ty),*
|
||||
},
|
||||
)*
|
||||
}
|
||||
|
||||
impl Content {
|
||||
$(
|
||||
#[allow(non_snake_case)]
|
||||
pub fn $name($($arg: $ty),*) -> Self {
|
||||
Self::$name { $($arg),* }
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_content! {
|
||||
Flex {
|
||||
name: Option<String>,
|
||||
},
|
||||
Rigid {
|
||||
name: String,
|
||||
},
|
||||
FlexAble {
|
||||
name: Option<String>,
|
||||
abilities: Vec<Symbol>,
|
||||
},
|
||||
RigidAble {
|
||||
name: String,
|
||||
abilities: Vec<Symbol>,
|
||||
},
|
||||
Recursive {
|
||||
name: Option<String>,
|
||||
structure: Variable,
|
||||
},
|
||||
LambdaSet {
|
||||
solved: Vec<ClosureType>,
|
||||
unspecialized: Vec<UnspecializedClosureType>,
|
||||
recursion_var: Option<Variable>,
|
||||
ambient_function: Variable,
|
||||
},
|
||||
ErasedLambda {},
|
||||
Alias {
|
||||
name: Symbol,
|
||||
variables: AliasTypeVariables,
|
||||
real_variable: Variable,
|
||||
kind: AliasKind,
|
||||
},
|
||||
Apply {
|
||||
symbol: Symbol,
|
||||
variables: Vec<Variable>,
|
||||
},
|
||||
Function {
|
||||
arguments: Vec<Variable>,
|
||||
lambda_type: Variable,
|
||||
ret: Variable,
|
||||
},
|
||||
Record {
|
||||
fields: HashMap<String, RecordField>,
|
||||
extension: Variable,
|
||||
},
|
||||
Tuple {
|
||||
elements: HashMap<u32, Variable>,
|
||||
extension: Variable,
|
||||
},
|
||||
TagUnion {
|
||||
tags: HashMap<String, Vec<Variable>>,
|
||||
extension: TagUnionExtension,
|
||||
},
|
||||
FunctionOrTagUnion {
|
||||
functions: Vec<Symbol>,
|
||||
tags: Vec<String>,
|
||||
extension: TagUnionExtension,
|
||||
},
|
||||
RecursiveTagUnion {
|
||||
recursion_var: Variable,
|
||||
tags: HashMap<String, Vec<Variable>>,
|
||||
extension: TagUnionExtension,
|
||||
},
|
||||
EmptyRecord {},
|
||||
EmptyTuple {},
|
||||
EmptyTagUnion {},
|
||||
RangedNumber {
|
||||
range: NumericRange,
|
||||
},
|
||||
Error {},
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct ClosureType {
|
||||
pub function: Symbol,
|
||||
pub environment: Vec<Variable>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct UnspecializedClosureType {
|
||||
pub specialization: Variable,
|
||||
pub ability_member: Symbol,
|
||||
pub lambda_set_region: u8,
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum AliasKind {
|
||||
Structural,
|
||||
Opaque,
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct AliasTypeVariables {
|
||||
pub type_variables: Vec<Variable>,
|
||||
pub lambda_set_variables: Vec<Variable>,
|
||||
pub infer_ext_in_output_position_variables: Vec<Variable>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct RecordField {
|
||||
pub kind: RecordFieldKind,
|
||||
pub field_type: Variable,
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum RecordFieldKind {
|
||||
Demanded,
|
||||
Required { rigid: bool },
|
||||
Optional { rigid: bool },
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
#[serde(tag = "type", content = "variable")]
|
||||
pub enum TagUnionExtension {
|
||||
Openness(Variable),
|
||||
Any(Variable),
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct NumericRange {
|
||||
pub kind: NumericRangeKind,
|
||||
pub signed: bool,
|
||||
pub min_width: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum NumericRangeKind {
|
||||
Int,
|
||||
AnyNum,
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct Rank(pub u32);
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct Descriptor {
|
||||
pub content: Content,
|
||||
pub rank: Rank,
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct Symbol(
|
||||
// TODO: should this be module ID + symbol?
|
||||
pub String,
|
||||
);
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum UnificationMode {
|
||||
Eq,
|
||||
Present,
|
||||
LambdaSetSpecialization,
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Event {
|
||||
Unification {
|
||||
left: Variable,
|
||||
right: Variable,
|
||||
mode: UnificationMode,
|
||||
success: Option<bool>,
|
||||
subevents: Vec<Event>,
|
||||
},
|
||||
VariableUnified {
|
||||
from: Variable,
|
||||
to: Variable,
|
||||
},
|
||||
VariableSetDescriptor {
|
||||
variable: Variable,
|
||||
rank: Option<Rank>,
|
||||
content: Option<Content>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, JsonSchema, Debug)]
|
||||
pub struct AllEvents(pub Vec<Event>);
|
||||
|
||||
impl AllEvents {
|
||||
pub fn schema() -> RootSchema {
|
||||
schema_for!(AllEvents)
|
||||
}
|
||||
|
||||
pub fn write(&self, writer: impl std::io::Write) -> Result<(), serde_json::Error> {
|
||||
serde_json::to_writer(writer, self)
|
||||
}
|
||||
}
|
|
@ -9,11 +9,13 @@ version.workspace = true
|
|||
|
||||
[dependencies]
|
||||
roc_can = { path = "../can" }
|
||||
roc_checkmate = { path = "../checkmate" }
|
||||
roc_collections = { path = "../collections" }
|
||||
roc_derive_key = { path = "../derive_key" }
|
||||
roc_error_macros = { path = "../../error_macros" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_region = { path = "../region" }
|
||||
roc_solve_schema = { path = "../solve_schema" }
|
||||
roc_types = { path = "../types" }
|
||||
roc_unify = { path = "../unify" }
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use roc_can::{abilities::SpecializationLambdaSets, module::ExposedByModule};
|
||||
use roc_checkmate::with_checkmate;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::{IdentIds, Symbol};
|
||||
use roc_solve_schema::UnificationMode;
|
||||
use roc_types::{
|
||||
subs::{instantiate_rigids, Subs, Variable},
|
||||
types::Polarity,
|
||||
|
@ -71,13 +73,20 @@ impl Env<'_> {
|
|||
}
|
||||
|
||||
pub fn unify(&mut self, left: Variable, right: Variable) {
|
||||
use roc_unify::unify::{unify, Env, Mode, Unified};
|
||||
use roc_unify::{
|
||||
unify::{unify, Unified},
|
||||
Env,
|
||||
};
|
||||
|
||||
let unified = unify(
|
||||
&mut Env::new(self.subs),
|
||||
// TODO(checkmate): pass checkmate through
|
||||
&mut with_checkmate!({
|
||||
on => Env::new(self.subs, None),
|
||||
off => Env::new(self.subs),
|
||||
}),
|
||||
left,
|
||||
right,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::OF_PATTERN,
|
||||
);
|
||||
|
||||
|
@ -103,15 +112,22 @@ impl Env<'_> {
|
|||
specialization_type: Variable,
|
||||
ability_member: Symbol,
|
||||
) -> SpecializationLambdaSets {
|
||||
use roc_unify::unify::{unify_introduced_ability_specialization, Env, Mode, Unified};
|
||||
use roc_unify::{
|
||||
unify::{unify_introduced_ability_specialization, Unified},
|
||||
Env,
|
||||
};
|
||||
|
||||
let member_signature = self.import_builtin_symbol_var(ability_member);
|
||||
|
||||
let unified = unify_introduced_ability_specialization(
|
||||
&mut Env::new(self.subs),
|
||||
// TODO(checkmate): pass checkmate through
|
||||
&mut with_checkmate!({
|
||||
on => Env::new(self.subs, None),
|
||||
off => Env::new(self.subs),
|
||||
}),
|
||||
member_signature,
|
||||
specialization_type,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
);
|
||||
|
||||
match unified {
|
||||
|
|
|
@ -1890,7 +1890,7 @@ fn build_tag<'a, 'ctx>(
|
|||
let roc_union =
|
||||
RocUnion::untagged_from_slices(layout_interner, env.context, &[other_fields]);
|
||||
|
||||
if tag_id == *nullable_id as _ {
|
||||
if tag_id == *nullable_id as u16 {
|
||||
let output_type = roc_union.struct_type().ptr_type(AddressSpace::default());
|
||||
|
||||
return output_type.const_null().into();
|
||||
|
|
|
@ -800,7 +800,7 @@ fn build_clone_tag_help<'a, 'ctx>(
|
|||
let mut cases = Vec::with_capacity_in(other_tags.len(), env.arena);
|
||||
|
||||
for i in 0..other_tags.len() + 1 {
|
||||
if i == nullable_id as _ {
|
||||
if i == nullable_id as usize {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,13 @@ version.workspace = true
|
|||
|
||||
[dependencies]
|
||||
roc_can = { path = "../can" }
|
||||
roc_checkmate = { path = "../checkmate" }
|
||||
roc_collections = { path = "../collections" }
|
||||
roc_derive = { path = "../derive" }
|
||||
roc_error_macros = { path = "../../error_macros" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_solve = { path = "../solve" }
|
||||
roc_solve_schema = { path = "../solve_schema" }
|
||||
roc_types = { path = "../types" }
|
||||
roc_unify = { path = "../unify" }
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::sync::{Arc, RwLock};
|
|||
use bumpalo::Bump;
|
||||
use roc_can::abilities::AbilitiesStore;
|
||||
use roc_can::module::ExposedByModule;
|
||||
use roc_checkmate::with_checkmate;
|
||||
use roc_collections::MutMap;
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_error_macros::internal_error;
|
||||
|
@ -15,11 +16,13 @@ use roc_solve::ability::AbilityResolver;
|
|||
use roc_solve::specialize::{compact_lambda_sets_of_vars, Phase};
|
||||
use roc_solve::Pools;
|
||||
use roc_solve::{DerivedEnv, SolveEnv};
|
||||
use roc_solve_schema::UnificationMode;
|
||||
use roc_types::subs::{get_member_lambda_sets_at_region, Content, FlatType, LambdaSet};
|
||||
use roc_types::subs::{ExposedTypesStorageSubs, Subs, Variable};
|
||||
use roc_types::types::Polarity;
|
||||
use roc_unify::unify::MetaCollector;
|
||||
use roc_unify::unify::{Env as UEnv, Mode, Unified};
|
||||
use roc_unify::unify::Unified;
|
||||
use roc_unify::Env as UEnv;
|
||||
|
||||
pub use roc_solve::ability::{ResolveError, Resolved};
|
||||
pub use roc_types::subs::instantiate_rigids;
|
||||
|
@ -360,10 +363,14 @@ pub fn unify(
|
|||
"derived module can only unify its subs in its own context!"
|
||||
);
|
||||
let unified = roc_unify::unify::unify_with_collector::<ChangedVariableCollector>(
|
||||
&mut UEnv::new(subs),
|
||||
// TODO(checkmate): pass checkmate through
|
||||
&mut with_checkmate!({
|
||||
on => UEnv::new(subs, None),
|
||||
off => UEnv::new(subs),
|
||||
}),
|
||||
left,
|
||||
right,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::Pos,
|
||||
);
|
||||
|
||||
|
@ -388,6 +395,9 @@ pub fn unify(
|
|||
derived_env: &derived_env,
|
||||
arena,
|
||||
pools: &mut pools,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: &mut None,
|
||||
};
|
||||
|
||||
compact_lambda_sets_of_vars(&mut env, lambda_sets_to_specialize, &late_phase)
|
||||
|
|
|
@ -10,6 +10,7 @@ version.workspace = true
|
|||
[dependencies]
|
||||
roc_builtins = { path = "../builtins" }
|
||||
roc_can = { path = "../can" }
|
||||
roc_checkmate = { path = "../checkmate" }
|
||||
roc_collections = { path = "../collections" }
|
||||
roc_constrain = { path = "../constrain" }
|
||||
roc_debug_flags = { path = "../debug_flags" }
|
||||
|
|
|
@ -331,6 +331,13 @@ fn start_phase<'a>(
|
|||
|
||||
let derived_module = SharedDerivedModule::clone(&state.derived_module);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let checkmate = if roc_checkmate::is_checkmate_enabled() {
|
||||
Some(roc_checkmate::Collector::new())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
BuildTask::solve_module(
|
||||
module,
|
||||
ident_ids,
|
||||
|
@ -347,6 +354,9 @@ fn start_phase<'a>(
|
|||
declarations,
|
||||
state.cached_types.clone(),
|
||||
derived_module,
|
||||
//
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
)
|
||||
}
|
||||
Phase::FindSpecializations => {
|
||||
|
@ -361,6 +371,9 @@ fn start_phase<'a>(
|
|||
ident_ids,
|
||||
abilities_store,
|
||||
expectations,
|
||||
//
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: _,
|
||||
} = typechecked;
|
||||
|
||||
let mut imported_module_thunks = bumpalo::collections::Vec::new_in(arena);
|
||||
|
@ -567,6 +580,9 @@ enum Msg<'a> {
|
|||
abilities_store: AbilitiesStore,
|
||||
loc_expects: LocExpects,
|
||||
loc_dbgs: LocDbgs,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: Option<roc_checkmate::Collector>,
|
||||
},
|
||||
FinishedAllTypeChecking {
|
||||
solved_subs: Solved<Subs>,
|
||||
|
@ -577,6 +593,9 @@ enum Msg<'a> {
|
|||
dep_idents: IdentIdsByModule,
|
||||
documentation: VecMap<ModuleId, ModuleDocumentation>,
|
||||
abilities_store: AbilitiesStore,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: Option<roc_checkmate::Collector>,
|
||||
},
|
||||
FoundSpecializations {
|
||||
module_id: ModuleId,
|
||||
|
@ -878,6 +897,9 @@ enum BuildTask<'a> {
|
|||
dep_idents: IdentIdsByModule,
|
||||
cached_subs: CachedTypeState,
|
||||
derived_module: SharedDerivedModule,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: Option<roc_checkmate::Collector>,
|
||||
},
|
||||
BuildPendingSpecializations {
|
||||
module_timing: ModuleTiming,
|
||||
|
@ -1393,6 +1415,9 @@ fn state_thread_step<'a>(
|
|||
dep_idents,
|
||||
documentation,
|
||||
abilities_store,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
} => {
|
||||
// We're done! There should be no more messages pending.
|
||||
debug_assert!(msg_rx.is_empty());
|
||||
|
@ -1412,6 +1437,9 @@ fn state_thread_step<'a>(
|
|||
dep_idents,
|
||||
documentation,
|
||||
abilities_store,
|
||||
//
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
);
|
||||
|
||||
Ok(ControlFlow::Break(LoadResult::TypeChecked(typechecked)))
|
||||
|
@ -2387,6 +2415,9 @@ fn update<'a>(
|
|||
abilities_store,
|
||||
loc_expects,
|
||||
loc_dbgs,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
} => {
|
||||
log!("solved types for {:?}", module_id);
|
||||
module_timing.end_time = Instant::now();
|
||||
|
@ -2496,6 +2527,9 @@ fn update<'a>(
|
|||
dep_idents,
|
||||
documentation,
|
||||
abilities_store,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
})
|
||||
.map_err(|_| LoadingProblem::MsgChannelDied)?;
|
||||
|
||||
|
@ -2529,6 +2563,9 @@ fn update<'a>(
|
|||
ident_ids,
|
||||
abilities_store,
|
||||
expectations: opt_expectations,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
};
|
||||
|
||||
state
|
||||
|
@ -3176,6 +3213,8 @@ fn finish(
|
|||
dep_idents: IdentIdsByModule,
|
||||
documentation: VecMap<ModuleId, ModuleDocumentation>,
|
||||
abilities_store: AbilitiesStore,
|
||||
//
|
||||
#[cfg(debug_assertions)] checkmate: Option<roc_checkmate::Collector>,
|
||||
) -> LoadedModule {
|
||||
let module_ids = Arc::try_unwrap(state.arc_modules)
|
||||
.unwrap_or_else(|_| panic!("There were still outstanding Arc references to module_ids"))
|
||||
|
@ -3207,6 +3246,8 @@ fn finish(
|
|||
|
||||
let exposed_values = exposed_vars_by_symbol.iter().map(|x| x.0).collect();
|
||||
|
||||
roc_checkmate::dump_checkmate!(checkmate);
|
||||
|
||||
LoadedModule {
|
||||
module_id: state.root_id,
|
||||
interns,
|
||||
|
@ -4441,6 +4482,8 @@ impl<'a> BuildTask<'a> {
|
|||
declarations: Declarations,
|
||||
cached_subs: CachedTypeState,
|
||||
derived_module: SharedDerivedModule,
|
||||
|
||||
#[cfg(debug_assertions)] checkmate: Option<roc_checkmate::Collector>,
|
||||
) -> Self {
|
||||
let exposed_by_module = exposed_types.retain_modules(imported_modules.keys());
|
||||
|
||||
|
@ -4463,6 +4506,9 @@ impl<'a> BuildTask<'a> {
|
|||
module_timing,
|
||||
cached_subs,
|
||||
derived_module,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4718,6 +4764,9 @@ struct SolveResult {
|
|||
exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
|
||||
problems: Vec<TypeError>,
|
||||
abilities_store: AbilitiesStore,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: Option<roc_checkmate::Collector>,
|
||||
}
|
||||
|
||||
#[allow(clippy::complexity)]
|
||||
|
@ -4731,6 +4780,8 @@ fn run_solve_solve(
|
|||
var_store: VarStore,
|
||||
module: Module,
|
||||
derived_module: SharedDerivedModule,
|
||||
|
||||
#[cfg(debug_assertions)] checkmate: Option<roc_checkmate::Collector>,
|
||||
) -> SolveResult {
|
||||
let Module {
|
||||
exposed_symbols,
|
||||
|
@ -4782,6 +4833,8 @@ fn run_solve_solve(
|
|||
pending_derives,
|
||||
exposed_by_module: &exposed_for_module.exposed_by_module,
|
||||
derived_module,
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
};
|
||||
|
||||
let solve_output = roc_solve::module::run_solve(
|
||||
|
@ -4824,6 +4877,9 @@ fn run_solve_solve(
|
|||
scope: _,
|
||||
errors,
|
||||
resolved_abilities_store,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
} = solve_output;
|
||||
|
||||
SolveResult {
|
||||
|
@ -4832,6 +4888,9 @@ fn run_solve_solve(
|
|||
exposed_vars_by_symbol,
|
||||
problems: errors,
|
||||
abilities_store: resolved_abilities_store,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4850,6 +4909,8 @@ fn run_solve<'a>(
|
|||
dep_idents: IdentIdsByModule,
|
||||
cached_types: CachedTypeState,
|
||||
derived_module: SharedDerivedModule,
|
||||
|
||||
#[cfg(debug_assertions)] checkmate: Option<roc_checkmate::Collector>,
|
||||
) -> Msg<'a> {
|
||||
let solve_start = Instant::now();
|
||||
|
||||
|
@ -4876,6 +4937,9 @@ fn run_solve<'a>(
|
|||
var_store,
|
||||
module,
|
||||
derived_module,
|
||||
//
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
),
|
||||
Some(TypeState {
|
||||
subs,
|
||||
|
@ -4888,6 +4952,9 @@ fn run_solve<'a>(
|
|||
exposed_vars_by_symbol,
|
||||
problems: vec![],
|
||||
abilities_store: abilities,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: None,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
|
@ -4901,6 +4968,9 @@ fn run_solve<'a>(
|
|||
var_store,
|
||||
module,
|
||||
derived_module,
|
||||
//
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
@ -4911,6 +4981,9 @@ fn run_solve<'a>(
|
|||
exposed_vars_by_symbol,
|
||||
problems,
|
||||
abilities_store,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
} = solve_result;
|
||||
|
||||
let exposed_types = roc_solve::module::exposed_types_storage_subs(
|
||||
|
@ -4945,6 +5018,9 @@ fn run_solve<'a>(
|
|||
abilities_store,
|
||||
loc_expects,
|
||||
loc_dbgs,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6160,6 +6236,9 @@ fn run_task<'a>(
|
|||
dep_idents,
|
||||
cached_subs,
|
||||
derived_module,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
} => Ok(run_solve(
|
||||
module,
|
||||
ident_ids,
|
||||
|
@ -6175,6 +6254,9 @@ fn run_task<'a>(
|
|||
dep_idents,
|
||||
cached_subs,
|
||||
derived_module,
|
||||
//
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
)),
|
||||
BuildPendingSpecializations {
|
||||
module_id,
|
||||
|
|
|
@ -125,6 +125,9 @@ pub struct TypeCheckedModule<'a> {
|
|||
pub ident_ids: IdentIds,
|
||||
pub abilities_store: AbilitiesStore,
|
||||
pub expectations: Option<Expectations>,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub checkmate: Option<roc_checkmate::Collector>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -910,7 +910,7 @@ fn get_tag_id_payloads(union_layout: UnionLayout, tag_id: TagIdIntType) -> TagPa
|
|||
nullable_id,
|
||||
other_fields,
|
||||
} => {
|
||||
if tag_id == nullable_id as _ {
|
||||
if tag_id == nullable_id as u16 {
|
||||
TagPayloads::Payloads(&[])
|
||||
} else {
|
||||
check_tag_id_oob!(2);
|
||||
|
|
|
@ -1139,7 +1139,7 @@ fn to_relevant_branch_help<'a>(
|
|||
EnumLiteral { tag_id, .. } => match test {
|
||||
IsByte {
|
||||
tag_id: test_id, ..
|
||||
} if tag_id == *test_id as _ => {
|
||||
} if tag_id == *test_id as u8 => {
|
||||
start.extend(end);
|
||||
Some(Branch {
|
||||
goal: branch.goal,
|
||||
|
|
|
@ -9,6 +9,7 @@ version.workspace = true
|
|||
|
||||
[dependencies]
|
||||
roc_can = { path = "../can" }
|
||||
roc_checkmate = { path = "../checkmate" }
|
||||
roc_collections = { path = "../collections" }
|
||||
roc_debug_flags = { path = "../debug_flags" }
|
||||
roc_derive = { path = "../derive" }
|
||||
|
@ -20,6 +21,7 @@ roc_packaging = { path = "../../packaging" }
|
|||
roc_problem = { path = "../problem" }
|
||||
roc_region = { path = "../region" }
|
||||
roc_solve_problem = { path = "../solve_problem" }
|
||||
roc_solve_schema = { path = "../solve_schema" }
|
||||
roc_types = { path = "../types" }
|
||||
roc_unify = { path = "../unify" }
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use roc_can::abilities::AbilitiesStore;
|
||||
use roc_can::expr::PendingDerives;
|
||||
use roc_checkmate::with_checkmate;
|
||||
use roc_collections::{VecMap, VecSet};
|
||||
use roc_debug_flags::dbg_do;
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -12,14 +13,16 @@ use roc_solve_problem::{
|
|||
NotDerivableContext, NotDerivableDecode, NotDerivableEncode, NotDerivableEq, TypeError,
|
||||
UnderivableReason, Unfulfilled,
|
||||
};
|
||||
use roc_solve_schema::UnificationMode;
|
||||
use roc_types::num::NumericRange;
|
||||
use roc_types::subs::{
|
||||
instantiate_rigids, Content, FlatType, GetSubsSlice, Rank, RecordFields, Subs, SubsSlice,
|
||||
TupleElems, Variable,
|
||||
};
|
||||
use roc_types::types::{AliasKind, Category, MemberImpl, PatternCategory, Polarity, Types};
|
||||
use roc_unify::unify::{Env as UEnv, MustImplementConstraints};
|
||||
use roc_unify::unify::MustImplementConstraints;
|
||||
use roc_unify::unify::{MustImplementAbility, Obligated};
|
||||
use roc_unify::Env as UEnv;
|
||||
|
||||
use crate::env::InferenceEnv;
|
||||
use crate::{aliases::Aliases, to_var::type_to_var};
|
||||
|
@ -1285,16 +1288,19 @@ impl DerivableVisitor for DeriveEq {
|
|||
subs: &mut Subs,
|
||||
content_var: Variable,
|
||||
) -> Result<Descend, NotDerivable> {
|
||||
use roc_unify::unify::{unify, Mode};
|
||||
use roc_unify::unify::unify;
|
||||
|
||||
// Of the floating-point types,
|
||||
// only Dec implements Eq.
|
||||
let mut env = UEnv::new(subs);
|
||||
// TODO(checkmate): pass checkmate through
|
||||
let unified = unify(
|
||||
&mut env,
|
||||
&mut with_checkmate!({
|
||||
on => UEnv::new(subs, None),
|
||||
off => UEnv::new(subs),
|
||||
}),
|
||||
content_var,
|
||||
Variable::DECIMAL,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::Pos,
|
||||
);
|
||||
match unified {
|
||||
|
@ -1412,7 +1418,7 @@ pub fn resolve_ability_specialization<R: AbilityResolver>(
|
|||
ability_member: Symbol,
|
||||
specialization_var: Variable,
|
||||
) -> Result<Resolved, ResolveError> {
|
||||
use roc_unify::unify::{unify, Mode};
|
||||
use roc_unify::unify::unify;
|
||||
|
||||
let (parent_ability, signature_var) = resolver
|
||||
.member_parent_and_signature_var(ability_member, subs)
|
||||
|
@ -1423,10 +1429,14 @@ pub fn resolve_ability_specialization<R: AbilityResolver>(
|
|||
|
||||
instantiate_rigids(subs, signature_var);
|
||||
let (_vars, must_implement_ability, _lambda_sets_to_specialize, _meta) = unify(
|
||||
&mut UEnv::new(subs),
|
||||
// TODO(checkmate): pass checkmate through
|
||||
&mut with_checkmate!({
|
||||
on => UEnv::new(subs, None),
|
||||
off => UEnv::new(subs),
|
||||
}),
|
||||
specialization_var,
|
||||
signature_var,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::Pos,
|
||||
)
|
||||
.expect_success(
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use bumpalo::Bump;
|
||||
use roc_can::{constraint::Constraints, module::ExposedByModule};
|
||||
use roc_checkmate::with_checkmate;
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_types::subs::{Content, Descriptor, Mark, OptVariable, Rank, Subs, Variable};
|
||||
use roc_unify::unify::Env as UEnv;
|
||||
use roc_unify::Env as UEnv;
|
||||
|
||||
use crate::{FunctionKind, Pools};
|
||||
|
||||
|
@ -18,6 +19,8 @@ pub struct SolveEnv<'a> {
|
|||
pub derived_env: &'a DerivedEnv<'a>,
|
||||
pub subs: &'a mut Subs,
|
||||
pub pools: &'a mut Pools,
|
||||
#[cfg(debug_assertions)]
|
||||
pub checkmate: &'a mut Option<roc_checkmate::Collector>,
|
||||
}
|
||||
|
||||
/// Environment necessary for inference.
|
||||
|
@ -28,6 +31,8 @@ pub struct InferenceEnv<'a> {
|
|||
pub derived_env: &'a DerivedEnv<'a>,
|
||||
pub subs: &'a mut Subs,
|
||||
pub pools: &'a mut Pools,
|
||||
#[cfg(debug_assertions)]
|
||||
pub checkmate: Option<roc_checkmate::Collector>,
|
||||
}
|
||||
|
||||
impl<'a> SolveEnv<'a> {
|
||||
|
@ -39,7 +44,10 @@ impl<'a> SolveEnv<'a> {
|
|||
|
||||
/// Retrieves an environment for unification.
|
||||
pub fn uenv(&mut self) -> UEnv {
|
||||
UEnv::new(self.subs)
|
||||
with_checkmate!({
|
||||
on => UEnv::new(self.subs, self.checkmate.as_mut()),
|
||||
off => UEnv::new(self.subs),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +101,10 @@ impl<'a> InferenceEnv<'a> {
|
|||
|
||||
/// Retrieves an environment for unification.
|
||||
pub fn uenv(&mut self) -> UEnv {
|
||||
UEnv::new(self.subs)
|
||||
with_checkmate!({
|
||||
on => UEnv::new(self.subs, self.checkmate.as_mut()),
|
||||
off => UEnv::new(self.subs),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_solve_env(&mut self) -> SolveEnv {
|
||||
|
@ -102,6 +113,8 @@ impl<'a> InferenceEnv<'a> {
|
|||
derived_env: self.derived_env,
|
||||
subs: self.subs,
|
||||
pools: self.pools,
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: &mut self.checkmate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::solve::RunSolveOutput;
|
||||
use crate::FunctionKind;
|
||||
use crate::{aliases::Aliases, solve};
|
||||
use roc_can::abilities::{AbilitiesStore, ResolvedImpl};
|
||||
|
@ -75,6 +76,10 @@ pub struct SolveConfig<'a> {
|
|||
/// Needed during solving to resolve lambda sets from derived implementations that escape into
|
||||
/// the user module.
|
||||
pub derived_module: SharedDerivedModule,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
/// The checkmate collector for this module.
|
||||
pub checkmate: Option<roc_checkmate::Collector>,
|
||||
}
|
||||
|
||||
pub struct SolveOutput {
|
||||
|
@ -82,6 +87,9 @@ pub struct SolveOutput {
|
|||
pub scope: solve::Scope,
|
||||
pub errors: Vec<TypeError>,
|
||||
pub resolved_abilities_store: AbilitiesStore,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub checkmate: Option<roc_checkmate::Collector>,
|
||||
}
|
||||
|
||||
pub fn run_solve(
|
||||
|
@ -108,7 +116,12 @@ pub fn run_solve(
|
|||
let mut problems = Vec::new();
|
||||
|
||||
// Run the solver to populate Subs.
|
||||
let (solved_subs, solved_scope) = solve::run(
|
||||
let RunSolveOutput {
|
||||
solved,
|
||||
scope,
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
} = solve::run(
|
||||
config,
|
||||
&mut problems,
|
||||
subs,
|
||||
|
@ -117,10 +130,12 @@ pub fn run_solve(
|
|||
);
|
||||
|
||||
SolveOutput {
|
||||
subs: solved_subs,
|
||||
scope: solved_scope,
|
||||
subs: solved,
|
||||
scope,
|
||||
errors: problems,
|
||||
resolved_abilities_store: abilities_store,
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,13 +24,14 @@ use roc_module::symbol::Symbol;
|
|||
use roc_problem::can::CycleEntry;
|
||||
use roc_region::all::Loc;
|
||||
use roc_solve_problem::TypeError;
|
||||
use roc_solve_schema::UnificationMode;
|
||||
use roc_types::subs::{
|
||||
self, Content, FlatType, GetSubsSlice, Mark, OptVariable, Rank, Subs, TagExt, UlsOfVar,
|
||||
Variable,
|
||||
};
|
||||
use roc_types::types::{Category, Polarity, Reason, RecordField, Type, TypeExtension, Types, Uls};
|
||||
use roc_unify::unify::{
|
||||
unify, unify_introduced_ability_specialization, Mode, Obligated, SpecializationLsetCollector,
|
||||
unify, unify_introduced_ability_specialization, Obligated, SpecializationLsetCollector,
|
||||
Unified::*,
|
||||
};
|
||||
|
||||
|
@ -93,27 +94,32 @@ struct State {
|
|||
mark: Mark,
|
||||
}
|
||||
|
||||
pub struct RunSolveOutput {
|
||||
pub solved: Solved<Subs>,
|
||||
pub scope: Scope,
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub checkmate: Option<roc_checkmate::Collector>,
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
config: SolveConfig,
|
||||
problems: &mut Vec<TypeError>,
|
||||
mut subs: Subs,
|
||||
subs: Subs,
|
||||
aliases: &mut Aliases,
|
||||
abilities_store: &mut AbilitiesStore,
|
||||
) -> (Solved<Subs>, Scope) {
|
||||
let env = run_in_place(config, problems, &mut subs, aliases, abilities_store);
|
||||
|
||||
(Solved(subs), env)
|
||||
) -> RunSolveOutput {
|
||||
run_help(config, problems, subs, aliases, abilities_store)
|
||||
}
|
||||
|
||||
/// Modify an existing subs in-place instead
|
||||
#[allow(clippy::too_many_arguments)] // TODO: put params in a context/env var
|
||||
fn run_in_place(
|
||||
fn run_help(
|
||||
config: SolveConfig,
|
||||
problems: &mut Vec<TypeError>,
|
||||
subs: &mut Subs,
|
||||
mut owned_subs: Subs,
|
||||
aliases: &mut Aliases,
|
||||
abilities_store: &mut AbilitiesStore,
|
||||
) -> Scope {
|
||||
) -> RunSolveOutput {
|
||||
let subs = &mut owned_subs;
|
||||
let SolveConfig {
|
||||
home: _,
|
||||
constraints,
|
||||
|
@ -123,6 +129,7 @@ fn run_in_place(
|
|||
exposed_by_module,
|
||||
derived_module,
|
||||
function_kind,
|
||||
..
|
||||
} = config;
|
||||
|
||||
let mut pools = Pools::default();
|
||||
|
@ -149,6 +156,8 @@ fn run_in_place(
|
|||
derived_env: &derived_env,
|
||||
subs,
|
||||
pools: &mut pools,
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: config.checkmate,
|
||||
};
|
||||
|
||||
let pending_derives = PendingDerivesTable::new(
|
||||
|
@ -179,7 +188,12 @@ fn run_in_place(
|
|||
&mut awaiting_specializations,
|
||||
);
|
||||
|
||||
state.scope
|
||||
RunSolveOutput {
|
||||
scope: state.scope,
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: env.checkmate,
|
||||
solved: Solved(owned_subs),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -489,7 +503,7 @@ fn solve(
|
|||
&mut env.uenv(),
|
||||
actual,
|
||||
expected,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::OF_VALUE,
|
||||
) {
|
||||
Success {
|
||||
|
@ -600,7 +614,7 @@ fn solve(
|
|||
&mut env.uenv(),
|
||||
actual,
|
||||
expected,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::OF_VALUE,
|
||||
) {
|
||||
Success {
|
||||
|
@ -699,8 +713,8 @@ fn solve(
|
|||
);
|
||||
|
||||
let mode = match constraint {
|
||||
PatternPresence(..) => Mode::PRESENT,
|
||||
_ => Mode::EQ,
|
||||
PatternPresence(..) => UnificationMode::PRESENT,
|
||||
_ => UnificationMode::EQ,
|
||||
};
|
||||
|
||||
match unify(
|
||||
|
@ -919,7 +933,7 @@ fn solve(
|
|||
&mut env.uenv(),
|
||||
actual,
|
||||
includes,
|
||||
Mode::PRESENT,
|
||||
UnificationMode::PRESENT,
|
||||
Polarity::OF_PATTERN,
|
||||
) {
|
||||
Success {
|
||||
|
@ -1053,7 +1067,7 @@ fn solve(
|
|||
&mut env.uenv(),
|
||||
branches_var,
|
||||
real_var,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
cond_polarity,
|
||||
);
|
||||
|
||||
|
@ -1103,7 +1117,7 @@ fn solve(
|
|||
&mut env.uenv(),
|
||||
real_var,
|
||||
branches_var,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
cond_polarity,
|
||||
),
|
||||
Success { .. }
|
||||
|
@ -1121,7 +1135,7 @@ fn solve(
|
|||
&mut env.uenv(),
|
||||
real_var,
|
||||
branches_var,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
cond_polarity,
|
||||
) {
|
||||
Failure(vars, actual_type, expected_type, _bad_impls) => {
|
||||
|
@ -1320,7 +1334,7 @@ fn solve(
|
|||
&mut env.uenv(),
|
||||
actual,
|
||||
Variable::LIST_U8,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::OF_VALUE,
|
||||
) {
|
||||
// List U8 always valid.
|
||||
|
@ -1340,7 +1354,7 @@ fn solve(
|
|||
&mut env.uenv(),
|
||||
actual,
|
||||
Variable::STR,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::OF_VALUE,
|
||||
) {
|
||||
Success {
|
||||
|
@ -1591,7 +1605,7 @@ fn check_ability_specialization(
|
|||
&mut env.uenv(),
|
||||
root_signature_var,
|
||||
symbol_loc_var.value,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
);
|
||||
|
||||
let resolved_mark = match unified {
|
||||
|
|
|
@ -10,6 +10,7 @@ use roc_debug_flags::ROC_TRACE_COMPACTION;
|
|||
use roc_derive_key::{DeriveError, DeriveKey};
|
||||
use roc_error_macros::{internal_error, todo_abilities};
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_solve_schema::UnificationMode;
|
||||
use roc_types::{
|
||||
subs::{
|
||||
get_member_lambda_sets_at_region, Content, Descriptor, GetSubsSlice, LambdaSet, Mark,
|
||||
|
@ -17,7 +18,7 @@ use roc_types::{
|
|||
},
|
||||
types::{AliasKind, MemberImpl, Polarity, Uls},
|
||||
};
|
||||
use roc_unify::unify::{unify, Mode, MustImplementConstraints};
|
||||
use roc_unify::unify::{unify, MustImplementConstraints};
|
||||
|
||||
use crate::{
|
||||
ability::builtin_module_with_unlisted_ability_impl,
|
||||
|
@ -577,7 +578,7 @@ fn compact_lambda_set<P: Phase>(
|
|||
&mut env.uenv(),
|
||||
t_f1,
|
||||
t_f2,
|
||||
Mode::LAMBDA_SET_SPECIALIZATION,
|
||||
UnificationMode::LAMBDA_SET_SPECIALIZATION,
|
||||
Polarity::Pos,
|
||||
)
|
||||
.expect_success("ambient functions don't unify");
|
||||
|
|
|
@ -6,6 +6,7 @@ use roc_error_macros::internal_error;
|
|||
use roc_module::{ident::TagName, symbol::Symbol};
|
||||
use roc_region::all::Loc;
|
||||
use roc_solve_problem::TypeError;
|
||||
use roc_solve_schema::UnificationMode;
|
||||
use roc_types::{
|
||||
subs::{
|
||||
self, AliasVariables, Content, FlatType, GetSubsSlice, LambdaSet, OptVariable, Rank,
|
||||
|
@ -17,7 +18,7 @@ use roc_types::{
|
|||
Category, ExtImplicitOpenness, Polarity, TypeTag, Types,
|
||||
},
|
||||
};
|
||||
use roc_unify::unify::{unify, Mode, Unified};
|
||||
use roc_unify::unify::{unify, Unified};
|
||||
|
||||
use crate::{
|
||||
ability::{AbilityImplError, ObligationCache},
|
||||
|
@ -875,7 +876,7 @@ pub(crate) fn type_to_var_help(
|
|||
&mut env.uenv(),
|
||||
var,
|
||||
flex_ability,
|
||||
Mode::EQ,
|
||||
UnificationMode::EQ,
|
||||
Polarity::OF_VALUE,
|
||||
) {
|
||||
Unified::Success {
|
||||
|
|
11
crates/compiler/solve_schema/Cargo.toml
Normal file
11
crates/compiler/solve_schema/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "roc_solve_schema"
|
||||
description = "Types used in the solver."
|
||||
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bitflags.workspace = true
|
3
crates/compiler/solve_schema/src/lib.rs
Normal file
3
crates/compiler/solve_schema/src/lib.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
mod unify;
|
||||
|
||||
pub use unify::UnificationMode;
|
50
crates/compiler/solve_schema/src/unify.rs
Normal file
50
crates/compiler/solve_schema/src/unify.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use bitflags::bitflags;
|
||||
|
||||
bitflags! {
|
||||
pub struct UnificationMode : u8 {
|
||||
/// Instructs the unifier to solve two types for equality.
|
||||
///
|
||||
/// For example, { n : Str }a ~ { n: Str, m : Str } will solve "a" to "{ m : Str }".
|
||||
const EQ = 1 << 0;
|
||||
/// Instructs the unifier to treat the right-hand-side of a constraint as
|
||||
/// present in the left-hand-side, rather than strictly equal.
|
||||
///
|
||||
/// For example, t1 += [A Str] says we should "add" the tag "A Str" to the type of "t1".
|
||||
const PRESENT = 1 << 1;
|
||||
/// Like [`UnificationMode::EQ`], but also instructs the unifier that the ambient lambda set
|
||||
/// specialization algorithm is running. This has implications for the unification of
|
||||
/// unspecialized lambda sets; see [`unify_unspecialized_lambdas`].
|
||||
const LAMBDA_SET_SPECIALIZATION = UnificationMode::EQ.bits | (1 << 2);
|
||||
}
|
||||
}
|
||||
|
||||
impl UnificationMode {
|
||||
pub fn is_eq(&self) -> bool {
|
||||
debug_assert!(!self.contains(UnificationMode::EQ | UnificationMode::PRESENT));
|
||||
self.contains(UnificationMode::EQ)
|
||||
}
|
||||
|
||||
pub fn is_present(&self) -> bool {
|
||||
debug_assert!(!self.contains(UnificationMode::EQ | UnificationMode::PRESENT));
|
||||
self.contains(UnificationMode::PRESENT)
|
||||
}
|
||||
|
||||
pub fn is_lambda_set_specialization(&self) -> bool {
|
||||
debug_assert!(!self.contains(UnificationMode::EQ | UnificationMode::PRESENT));
|
||||
self.contains(UnificationMode::LAMBDA_SET_SPECIALIZATION)
|
||||
}
|
||||
|
||||
pub fn as_eq(self) -> Self {
|
||||
(self - UnificationMode::PRESENT) | UnificationMode::EQ
|
||||
}
|
||||
|
||||
pub fn pretty_print(&self) -> &str {
|
||||
if self.contains(UnificationMode::EQ) {
|
||||
"~"
|
||||
} else if self.contains(UnificationMode::PRESENT) {
|
||||
"+="
|
||||
} else {
|
||||
unreachable!("Bad mode!")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -433,6 +433,9 @@ fn check_derived_typechecks_and_golden(
|
|||
pending_derives: Default::default(),
|
||||
exposed_by_module: &exposed_for_module.exposed_by_module,
|
||||
derived_module: Default::default(),
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: None,
|
||||
};
|
||||
|
||||
let SolveOutput {
|
||||
|
|
|
@ -38,7 +38,7 @@ impl NumericRange {
|
|||
width.signedness_and_width().1 >= at_least_width.signedness_and_width().1
|
||||
}
|
||||
|
||||
pub(crate) fn width(&self) -> IntLitWidth {
|
||||
pub fn min_width(&self) -> IntLitWidth {
|
||||
use NumericRange::*;
|
||||
match self {
|
||||
IntAtLeastSigned(w)
|
||||
|
@ -52,7 +52,7 @@ impl NumericRange {
|
|||
/// `None` if there is no common lower bound.
|
||||
pub fn intersection(&self, other: &Self) -> Option<Self> {
|
||||
use NumericRange::*;
|
||||
let (left, right) = (self.width(), other.width());
|
||||
let (left, right) = (self.min_width(), other.min_width());
|
||||
let (constructor, is_negative): (fn(IntLitWidth) -> NumericRange, _) = match (self, other) {
|
||||
// Matching against a signed int, the intersection must also be a signed int
|
||||
(IntAtLeastSigned(_), _) | (_, IntAtLeastSigned(_)) => (IntAtLeastSigned, true),
|
||||
|
@ -154,11 +154,17 @@ impl NumericRange {
|
|||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
enum IntSignedness {
|
||||
pub enum IntSignedness {
|
||||
Unsigned,
|
||||
Signed,
|
||||
}
|
||||
|
||||
impl IntSignedness {
|
||||
pub fn is_signed(&self) -> bool {
|
||||
matches!(self, IntSignedness::Signed)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum IntLitWidth {
|
||||
U8,
|
||||
|
@ -184,7 +190,7 @@ pub enum IntLitWidth {
|
|||
|
||||
impl IntLitWidth {
|
||||
/// Returns the `IntSignedness` and bit width of a variant.
|
||||
fn signedness_and_width(&self) -> (IntSignedness, u32) {
|
||||
pub fn signedness_and_width(&self) -> (IntSignedness, u32) {
|
||||
use IntLitWidth::*;
|
||||
use IntSignedness::*;
|
||||
match self {
|
||||
|
@ -207,7 +213,7 @@ impl IntLitWidth {
|
|||
}
|
||||
|
||||
fn is_signed(&self) -> bool {
|
||||
self.signedness_and_width().0 == IntSignedness::Signed
|
||||
self.signedness_and_width().0.is_signed()
|
||||
}
|
||||
|
||||
pub fn type_str(&self) -> &'static str {
|
||||
|
|
|
@ -1609,7 +1609,7 @@ mod debug_types {
|
|||
use crate::num::IntLitWidth::*;
|
||||
use crate::num::NumericRange::*;
|
||||
|
||||
let fmt_width = f.text(match range.width() {
|
||||
let fmt_width = f.text(match range.min_width() {
|
||||
U8 | I8 => "8",
|
||||
U16 | I16 => "16",
|
||||
U32 | I32 => "32",
|
||||
|
|
|
@ -438,7 +438,7 @@ fn write_source_with_answers<W: io::Write>(
|
|||
Some(InferredQuery {
|
||||
source_line_column,
|
||||
..
|
||||
}) if source_line_column.line == i as _
|
||||
}) if source_line_column.line == i as u32
|
||||
) {
|
||||
let inferred = sorted_queries.pop().unwrap();
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ license.workspace = true
|
|||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bitflags.workspace = true
|
||||
|
||||
[dependencies.roc_collections]
|
||||
path = "../collections"
|
||||
|
@ -27,3 +26,9 @@ path = "../debug_flags"
|
|||
|
||||
[dependencies.roc_tracing]
|
||||
path = "../../tracing"
|
||||
|
||||
[dependencies.roc_checkmate]
|
||||
path = "../checkmate"
|
||||
|
||||
[dependencies.roc_solve_schema]
|
||||
path = "../solve_schema"
|
||||
|
|
132
crates/compiler/unify/src/env.rs
Normal file
132
crates/compiler/unify/src/env.rs
Normal file
|
@ -0,0 +1,132 @@
|
|||
#[cfg(debug_assertions)]
|
||||
use roc_checkmate::debug_checkmate;
|
||||
use roc_collections::VecSet;
|
||||
use roc_types::subs::{Descriptor, Subs, Variable};
|
||||
|
||||
pub struct Env<'a> {
|
||||
subs: &'a mut Subs,
|
||||
#[cfg(debug_assertions)]
|
||||
cm: Option<&'a mut roc_checkmate::Collector>,
|
||||
seen_recursion: VecSet<(Variable, Variable)>,
|
||||
fixed_variables: VecSet<Variable>,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Env<'_> {
|
||||
type Target = Subs;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.subs
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for Env<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.subs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Env<'a> {
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn new(subs: &'a mut Subs, cm: Option<&'a mut roc_checkmate::Collector>) -> Self {
|
||||
Self {
|
||||
subs,
|
||||
cm,
|
||||
seen_recursion: Default::default(),
|
||||
fixed_variables: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub fn new(subs: &'a mut Subs) -> Self {
|
||||
Self {
|
||||
subs,
|
||||
seen_recursion: Default::default(),
|
||||
fixed_variables: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_recursion_pair(&mut self, var1: Variable, var2: Variable) {
|
||||
let pair = (
|
||||
self.subs.get_root_key_without_compacting(var1),
|
||||
self.subs.get_root_key_without_compacting(var2),
|
||||
);
|
||||
|
||||
let already_seen = self.seen_recursion.insert(pair);
|
||||
debug_assert!(!already_seen);
|
||||
}
|
||||
|
||||
pub(crate) fn remove_recursion_pair(&mut self, var1: Variable, var2: Variable) {
|
||||
#[cfg(debug_assertions)]
|
||||
let size_before = self.seen_recursion.len();
|
||||
|
||||
self.seen_recursion.retain(|(v1, v2)| {
|
||||
let is_recursion_pair = self.subs.equivalent_without_compacting(*v1, var1)
|
||||
&& self.subs.equivalent_without_compacting(*v2, var2);
|
||||
!is_recursion_pair
|
||||
});
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let size_after = self.seen_recursion.len();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
debug_assert!(size_after < size_before, "nothing was removed");
|
||||
}
|
||||
|
||||
pub(crate) fn seen_recursion_pair(&self, var1: Variable, var2: Variable) -> bool {
|
||||
let (var1, var2) = (
|
||||
self.subs.get_root_key_without_compacting(var1),
|
||||
self.subs.get_root_key_without_compacting(var2),
|
||||
);
|
||||
|
||||
self.seen_recursion.contains(&(var1, var2))
|
||||
}
|
||||
|
||||
pub(crate) fn was_fixed(&self, var: Variable) -> bool {
|
||||
self.fixed_variables
|
||||
.iter()
|
||||
.any(|fixed_var| self.subs.equivalent_without_compacting(*fixed_var, var))
|
||||
}
|
||||
|
||||
pub(crate) fn extend_fixed_variables(&mut self, vars: impl IntoIterator<Item = Variable>) {
|
||||
self.fixed_variables.extend(vars);
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) fn union(&mut self, left: Variable, right: Variable, desc: Descriptor) {
|
||||
let left_root = self.subs.get_root_key_without_compacting(left);
|
||||
let right_root = self.subs.get_root_key_without_compacting(right);
|
||||
|
||||
self.subs.union(left, right, desc);
|
||||
|
||||
debug_checkmate!(self.cm, cm => {
|
||||
let new_root = self.subs.get_root_key_without_compacting(left);
|
||||
cm.set_descriptor(self.subs, new_root, desc);
|
||||
cm.unify(self.subs, left_root, new_root);
|
||||
cm.unify(self.subs, right_root, new_root);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub(crate) fn union(&mut self, left: Variable, right: Variable, desc: Descriptor) {
|
||||
self.subs.union(left, right, desc);
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) fn debug_start_unification(
|
||||
&mut self,
|
||||
left: Variable,
|
||||
right: Variable,
|
||||
mode: roc_solve_schema::UnificationMode,
|
||||
) {
|
||||
debug_checkmate!(self.cm, cm => {
|
||||
cm.start_unification(self.subs, left, right, mode);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) fn debug_end_unification(&mut self, left: Variable, right: Variable, success: bool) {
|
||||
debug_checkmate!(self.cm, cm => {
|
||||
cm.end_unification(self.subs, left, right, success);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -4,5 +4,7 @@
|
|||
// See github.com/roc-lang/roc/issues/800 for discussion of the large_enum_variant check.
|
||||
#![allow(clippy::large_enum_variant)]
|
||||
|
||||
mod env;
|
||||
mod fix;
|
||||
pub mod unify;
|
||||
pub use env::Env;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -16,6 +16,7 @@ use roc_parse::parser::{SourceError, SyntaxError};
|
|||
use roc_problem::can::Problem;
|
||||
use roc_region::all::Loc;
|
||||
use roc_solve::module::SolveConfig;
|
||||
use roc_solve::solve::RunSolveOutput;
|
||||
use roc_solve::{solve, Aliases, FunctionKind};
|
||||
use roc_solve_problem::TypeError;
|
||||
use roc_types::subs::{Content, Subs, VarStore, Variable};
|
||||
|
@ -50,9 +51,12 @@ pub fn infer_expr(
|
|||
exposed_by_module: &Default::default(),
|
||||
derived_module,
|
||||
function_kind: FunctionKind::LambdaSet,
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: None,
|
||||
};
|
||||
|
||||
let (solved, _) = solve::run(config, problems, subs, aliases, abilities_store);
|
||||
let RunSolveOutput { solved, .. } =
|
||||
solve::run(config, problems, subs, aliases, abilities_store);
|
||||
|
||||
let content = *solved.inner().get_content_without_compacting(expr_var);
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[files]
|
||||
extend-exclude = ["crates/vendor/", "examples/static-site-gen/input/", "COPYRIGHT"]
|
||||
extend-exclude = ["crates/vendor/", "examples/static-site-gen/input/", "COPYRIGHT", "crates/compiler/checkmate/www/package-lock.json"]
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue