pyret-lang icon indicating copy to clipboard operation
pyret-lang copied to clipboard

type-checker internal error?

Open shriram opened this issue 4 years ago • 4 comments


data NeLoN:
  | one(n :: Number)
  | more(n :: Number, r :: NeLoN)
end

fun ra-to-nelon(r :: RawArray<Number>) -> NeLoN:
  len = raw-array-length(r)
  fun make-from-index(n :: Number):
    v = raw-array-get(r, n)
    if n == (len - 1):
      one(v)
    else:
      more(v, make-from-index(n + 1))
    end
  end
  make-from-index(0)
end

nelon = {
  make0: {(): raise("can't make an empty NeLoN")},
  make1: {(a1 :: Number): one(a1)},
  make2: {(a1 :: Number, a2 :: Number): more(a1, one(a2))},
  make3: {(a1 :: Number, a2 :: Number, a3 :: Number): more(a1, more(a2, one(a3)))},
  make4: {(a1 :: Number, a2 :: Number, a3 :: Number, a4 :: Number): more(a1, more(a2, more(a3, one(a4))))},
  make5: {(a1 :: Number, a2 :: Number, a3 :: Number, a4 :: Number, a5 :: Number): more(a1, more(a2, more(a3, more(a4, one(a5)))))},
  make: {(args :: RawArray<Number>): ra-to-nelon(args)} }

image

Given that there's no cases anywhere in my code, I have to assume this is something internal… (or a desugaring that I can't identify).

shriram avatar Sep 23 '21 00:09 shriram

Definitely a bug as you say. This is hitting a bad case in object inference somewhere. Dumb workaround so you can make progress if you want:

data NeLoN:
  | one(n :: Number)
  | more(n :: Number, r :: NeLoN)
end




fun ra-to-nelon(r :: RawArray<Number>) -> NeLoN:
  len = raw-array-length(r)
  fun make-from-index(n :: Number):
    v = raw-array-get(r, n)
    if n == (len - 1):
      one(v)
    else:
      more(v, make-from-index(n + 1))
    end
  end
  make-from-index(0)
end

type Maker<A, B> = {
  make0 :: ( -> B),
  make1 :: (A -> B),
  make2 :: (A, A -> B),
  make3 :: (A, A, A -> B),
  make4 :: (A, A, A, A -> B),
  make5 :: (A, A, A, A, A -> B),
  make  :: (RawArray<A> -> B)
}

nelon :: Maker<Number, NeLoN> = {
  make0: {(): raise("can't make an empty NeLoN")},
  make1: {(a1 :: Number): one(a1)},
  make2: {(a1 :: Number, a2 :: Number): more(a1, one(a2))},
  make3: {(a1 :: Number, a2 :: Number, a3 :: Number): more(a1, more(a2, one(a3)))},
  make4: {(a1 :: Number, a2 :: Number, a3 :: Number, a4 :: Number): more(a1, more(a2, more(a3, one(a4))))},
  make5: {(a1 :: Number, a2 :: Number, a3 :: Number, a4 :: Number, a5 :: Number): more(a1, more(a2, more(a3, more(a4, one(a5)))))},
  make: {(args :: RawArray<Number>): ra-to-nelon(args)}
}

(Note that it's hard to make Maker as polymorphic as one might want if you had a polymorphic list, but this is an accurate type here)

I also reduced the test to:

o = { m: {(): raise("something") } }

(Which is context-independent)

So this is probably a bad use of bot in constraint solving for fields to track down.

jpolitz avatar Sep 23 '21 04:09 jpolitz

Also, in case @blerner or someone else picks this up, I can't make this fail at the CLI, it builds fine across several different choices of context.

jpolitz avatar Sep 23 '21 04:09 jpolitz

Actually, it wasn't that. We had never written a test with an inferred t-bot that got provided out of a module in typed mode. (Using CPO had an implicit provide * that triggered that path)

Interestingly, it's not necessarily great for make0 to have that inferred type.

Regression test added and fixed by 4844404d4 on horizon, will go out in next deploy with some other fixes, soon.

jpolitz avatar Sep 23 '21 04:09 jpolitz

Also, someone should probably make it so we can type-check the compiler.

jpolitz avatar Sep 23 '21 04:09 jpolitz