-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement uniformity check for type recursion #76
Comments
Replacing |
Here is a more minimal example:
I know what the problem is, and this particular example could be fixed (for the price of making type checking more expensive). However, more broadly, this code does something we so far intended to forbid anyway, namely, it uses "non-uniform recursion" in a type definition, that is, there is a recursive use of a type name with different type arguments than its own parameters. Allowing that with equi-recursive types makes type-checking undecidable in general, i.e., the type-checker may not terminate because you are generating infinitely large type derivations. There is a TODO in the type checker somewhere to add a check flagging a type definition like Array as illegal. We could try to relax this restriction somehow, though it is quite difficult to identify weaker but sufficient criteria to prevent bad cases. |
@rossberg thanks for explaining. I'll leave this open as a reminder to make this fail to type check but feel free to close. |
I leave it open as a tracking issue for implementing the check; changed title accordingly. |
I was thinking that an alternative way of achieving the example I provided was to do something like the following, but it's not possible without being able to access Is that something that could be supported? class Array<A>(value_ : A[]) {
value = value_;
bind = func <B>(f : A -> Array<B>) : Array<B> {
array.bind<A, B>(self, f);
};
};
let array = new {
bind = func <A, B>(xs : Array<A>, f : A -> Array<B>) : Array<B> {
var ys : B[] = [];
for (i in xs.value.keys()) {
ys := arrayConcat<B>(ys, f(xs.value[i]).value);
};
Array<B>(ys);
};
}; |
I'm afraid that may run into the same problem, because of a class definition's dual role as a type definition. Currently classes are nominal, which may save this, but I'm not sure we want to keep it that way, so I'd rather be conservative. As for "self" in class definitions, yes this absolutely needs fixing, too. The only blocker is finding a syntax that fits with the rest of the language. I have a local branch where I allow "class C(...) = self { ... }", which is the best I could come up with so far, but requires the "=". |
I gave the changes in #79 a try at some point over the holiday and think I may have encountered the same issue. As expected (based on the diff in #79) I get some errors at first: class Array<A>(value_ : A[]) = self {
value = value_;
bind = func <B>(f : A -> Array<B>) : Array<B> {
array.bind<A, B>(self, f);
};
};
let array = new {
bind = func <A, B>(xs : Array<A>, f : A -> Array<B>) : Array<B> {
var ys : B[] = [];
for (i in xs.value.keys()) {
ys := arrayConcat<B>(ys, f(xs.value[i]).value);
};
Array<B>(ys);
};
};
/* Stub */
let arrayConcat = func <A>(xs : A[], ys : A[]) : A[] {
xs;
};
I added some additional class Array<A>(value_ : A[]) = self {
value = value_;
- bind = func <B>(f : A -> Array<B>) : Array<B> {
+ bind = func <B>(f : A -> Array<B>) : like Array<B> {
array.bind<A, B>(self, f);
};
};
let array = new {
- bind = func <A, B>(xs : Array<A>, f : A -> Array<B>) : Array<B> {
+ bind = func <A, B>(xs : like Array<A>, f : A -> Array<B>) : Array<B> {
var ys : B[] = [];
for (i in xs.value.keys()) {
ys := arrayConcat<B>(ys, f(xs.value[i]).value);
};
Array<B>(ys);
};
};
/* Stub */
let arrayConcat = func <A>(xs : A[], ys : A[]) : A[] {
xs;
}; In this small example I was able to trigger a stack overflow (output below) but at the time it showed no sign of stopping and I eventually killed it.
This works as expected: class Array<A>(value_ : A[]) = self {
value = value_;
bind = func <B>(f : A -> Array<B>) : Array<B> {
array.bind<A, B>(self, f);
};
};
let array = new {
- bind = func <A, B>(xs : Array<A>, f : A -> Array<B>) : Array<B> {
+ bind = func <A, B>(xs : like Array<A>, f : A -> Array<B>) : Array<B> {
var ys : B[] = [];
for (i in xs.value.keys()) {
ys := arrayConcat<B>(ys, f(xs.value[i]).value);
};
Array<B>(ys);
};
};
/* Stub */
let arrayConcat = func <A>(xs : A[], ys : A[]) : A[] {
xs;
}; |
Well, non-termination may or may not manifest itself as a stack overflow, depending on whether it loops in a tail recursion or not. |
@crusso, I think you're right. |
Look what I found: A at least P2 level issue that’s 15 months old, and got dropped on the floor due to the Jira migration :-) |
Just run
in the interpreter to see how it fails. |
Closing in favor of #1279 |
## Changelog for ic-hs: Branch: master Commits: [dfinity/ic-hs@eef711d1...91832636](dfinity/ic-hs@eef711d...9183263) * [`4920ec29`](dfinity/ic-hs@4920ec2) System API for ECDSA signing ([dfinity/ic-hs#79](https://togithub.com/dfinity/ic-hs/issues/79)) * [`47b7f0b6`](dfinity/ic-hs@47b7f0b) Mirror changes of the spec related to the canister HTTP calls ([dfinity/ic-hs#85](https://togithub.com/dfinity/ic-hs/issues/85)) * [`91832636`](dfinity/ic-hs@9183263) upgrade nixpkgs to release-22.05 ([dfinity/ic-hs#76](https://togithub.com/dfinity/ic-hs/issues/76))
## Changelog for ic-hs: Branch: master Commits: [dfinity/ic-hs@eef711d1...91832636](dfinity/ic-hs@eef711d...9183263) * [`4920ec29`](dfinity/ic-hs@4920ec2) System API for ECDSA signing ([dfinity/ic-hs#79](https://togithub.com/dfinity/ic-hs/issues/79)) * [`47b7f0b6`](dfinity/ic-hs@47b7f0b) Mirror changes of the spec related to the canister HTTP calls ([dfinity/ic-hs#85](https://togithub.com/dfinity/ic-hs/issues/85)) * [`91832636`](dfinity/ic-hs@9183263) upgrade nixpkgs to release-22.05 ([dfinity/ic-hs#76](https://togithub.com/dfinity/ic-hs/issues/76))
## Changelog for ic-wasm: Branch: main Commits: [dfinity/ic-wasm@12f4cb76...f3bcbf19](dfinity/ic-wasm@12f4cb7...f3bcbf1) * [`f3bcbf19`](dfinity/ic-wasm@f3bcbf1) use 64bit API for stable memory ([dfinity/ic-wasm#76](https://togithub.com/dfinity/ic-wasm/issues/76))
## Changelog for ic-wasm: Branch: main Commits: [dfinity/ic-wasm@12f4cb76...f3bcbf19](dfinity/ic-wasm@12f4cb7...f3bcbf1) * [`f3bcbf19`](dfinity/ic-wasm@f3bcbf1) use 64bit API for stable memory ([dfinity/ic-wasm#76](https://togithub.com/dfinity/ic-wasm/issues/76))
I'm getting the following error when trying to type check the file below. This is a more relatable and minimal example of an issue I ran into when trying to do something similar.
Tested against 003de63 (the latest on
master
at time of writing)(unknown location): internal error, Stack overflow
The type alone is fine:
In case it's somehow relevant, using a class is fine and behaves as expected:
So the issue seems related to
init
returning anArray
which has abind
field that returns anArray
.The text was updated successfully, but these errors were encountered: