Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ lcov.info
AGENTS.md
CLAUDE.md
/.claude/
/.agents/
/LOCAL/


# Documentation
function_type_checking.md
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ typr test # run testthat suites
typr document # generate .Rd documentation
typr pkgdown # build a documentation website
typr repl # interactive session
typr tutor # learn TypR step by step, like vimtutor
typr lsp # language server (used by the editor extensions)
typr mcp # MCP server (exposes the compiler to AI agents)
```
Expand All @@ -99,6 +100,12 @@ Tools exposed today (see `crates/typr-mcp`):
|---|---|
| `check` | Type-checks TypR source, returns `{ok, diagnostics[{code, message}]}` with stable `T0xx`/`S0xx` codes |
| `build` | Same as `check`, plus the transpiled R code (`r_code`) — produced even when there are type errors |
| `tutor_lessons` / `tutor_lesson` / `tutor_check` / `tutor_hint` | The TypR tutor's lessons, graded by the compiler — the same course as `typr tutor` |

The server also offers a `tutor` **prompt**: pick it in your client (in Claude Code,
`/mcp__typr__tutor`) and the assistant becomes a tutor that walks you through the lessons,
grades your attempts without writing them for you, and points you to the documentation
pages each lesson opens onto.

Point a client at the `typr` binary with the `mcp` argument. After `cargo install typr`,
`typr` is on `PATH`, so a client config (e.g. Claude Desktop's/Claude Code's `mcpServers`
Expand All @@ -118,6 +125,15 @@ block) just needs:
Building from a local checkout instead of installing? Point `command` at
`target/debug/typr` (or `target/release/typr`) directly.

## Learning TypR: `typr tutor`

Like `vimtutor`, `typr tutor` teaches by doing: it creates a `typr-tutor/` folder holding
thirteen short lessons, each a TypR file whose comments explain and whose code you complete.
`typr tutor check` grades your answer with the compiler and, once it passes, lists the
documentation pages to read next. `typr tutor hint`, `list`, `reset N` and `solution N`
do what they say. No AI needed — and if you want one, the MCP server's `tutor` prompt runs
the same lessons. Lessons live in `crates/typr-mcp/data/tutor/`.

## Repository layout

```
Expand Down
7 changes: 7 additions & 0 deletions cases/0089-inferred-dataframe-vs-annotation/case.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
title = "data.frame(...) inferred type does not match a dataframe[N]{...} annotation"
cmd = "build"
layer = "type"
status = "open"
created = "2026-10-01"
origin = "perso"
checked = false
9 changes: 9 additions & 0 deletions cases/0089-inferred-dataframe-vs-annotation/expect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
`data.frame(units = c(...), price = c(...))` is inferred as `DataFrame[3, {price: num, units: num}]`,
which is rejected where `dataframe[3]{ units: num, price: num }` is expected
("No signature of function 'total' matches this call"). Row count and column names agree; the
mismatch comes from the column types: the inferred side stores `Vec[3, num]` per column, the
annotation `num`. The inferred form should be accepted (a `data.frame(...)` call is the natural
way to build one for R users).

Code: `type_checking/mod.rs`, `Lang::DataFrame` arm.
Found while checking the landing-page examples (typr.github.io, "What R lets through").
4 changes: 4 additions & 0 deletions cases/0089-inferred-dataframe-vs-annotation/expect.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# the call type-checks, so the R file is produced and the call is emitted
[[rule]]
file = "R/main.R"
must_contain = "total(sales)"
Loading
Loading