o1-labs / o1js

TypeScript framework for zk-SNARKs and zkApps
https://docs.minaprotocol.com/en/zkapps/how-to-write-a-zkapp
Apache License 2.0
494 stars 108 forks source link

seemingly-innocuous code producing checker depth error (2589) #1537

Open harrysolovay opened 5 months ago

harrysolovay commented 5 months ago

I see no circular type reference in the following.

import { Struct, UInt64, MerkleList } from "o1js"

export class ApprovalId extends UInt64 {}
export class Approvals extends MerkleList<ApprovalId> {}

export class TokenAccount extends Struct({
  balance: UInt64,
  approvals: Approvals,
}) {}

Any idea why this is producing a type instantiation depth error?

TS playground here.

mitschabaude commented 5 months ago
import { Struct, UInt64, MerkleList } from "o1js"

export class ApprovalId extends UInt64 {}
-export class Approvals extends MerkleList<ApprovalId> {}
+export class Approvals extends MerkleList.create(ApprovalId) {}

export class TokenAccount extends Struct({
  balance: UInt64,
- approvals: Approvals,
+ approvals: Approvals.provable,
}) {}
mitschabaude commented 5 months ago

we still need to make the change to handle .provable https://github.com/o1-labs/o1js/issues/1248

mitschabaude commented 5 months ago

Also I think we should add a recursive base type for inputs to Struct, which would be a clearer error

harrysolovay commented 5 months ago

Thank you for the quick reply and (temporary (?)) fix. I can confirm that resolved the depth error. Why is MerkleList a class and not a class factory like Struct?

mitschabaude commented 5 months ago

We need base classes for generic classes because if we return them directly from a function, the type gets butchered by TS in the exported d.ts file. For example, method arguments that are instances of the class become any.

For Struct it's different because we're explicitly defining the interface that the function returns.