brownplt / pyret-lang

The Pyret language.
Other
1.06k stars 106 forks source link

spy ending a block should be ill-formed? #1714

Closed shriram closed 2 months ago

shriram commented 8 months ago

I have a student struggling to figure out why their program is producing nothing, a value they've never heard of before.

The essence of their program is this:

x = 1

fun f():
  block:
    [list: 1]
    spy: x end
  end
end

which passes this:

check:
  f() is nothing
end

spy plus another expression causes a "multiple expressions" error. The error tells them to use block. They add it, and the error goes away. Unfortunately, they seem to have added the spy above the return value expression, rather than below it. So it's easy to see how they end up in a pickle.

One possibility is that spy should not "count" as an expression, so it doesn't trigger a well-formedness error, just like a variable binding does not. (I realize this may be hard after desugaring, but in principle this seems like a sound rule, since spy is "metaprogramming", not at all part of the value-producing code.)

Alternatively and/or additionally, a spy in the return-value position of a block should probably be a well-formedness-error (for the same reason in parens above).

Credit Shu Xu of Brown CSCI 0190 for revealing this behavior.

blerner commented 2 months ago

Well-formedness checking happens before desugaring, so this is feasible. Your diagnosis above is not quite accurate, because the following program already succeeds without requiring a block:

x = 1

fun f():
  spy: x end
  [list: 1]
end

That is, the "ignore spy-blocks as statements" rule is already in effect. The problem is your original example had a non-let-binding, non-spy-block expression followed by something, and that triggers the multiple-expression warning. It's really not worth the hacking to try to avoid this particular issue.

I think the only thing needed here is to prohibit spy blocks in block-final positions, which is pretty easy.
image

@jpolitz once I add this to horizon, we'll need to port this to anchor/you'll need to remind me where to add this to anchor.