Skip to content
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

[ fix ] Fix interface elaboration when %unbound_implicits is off #3052

Closed
wants to merge 3 commits into from

Conversation

dunhamsteve
Copy link
Contributor

Description

A user on discord reported problems defining interfaces with constraints if unbound_implicits is disabled. The error was undefined names on the type of the Constraint that was being generated. The missing names are always the parameters of the interface (because the interface with parameters is part of the type), so I implicitly pi-bind in all of the parameters. This is also done in the existing code when generating the type for the data.

Prior to the fix the following code:

%unbound_implicits off
interface Foo a where
interface Foo a => Bar (a : Type) where

reports the error

Error: While processing type of Constraint (Foo a). Undefined name a.

tests.idris2.interface030.NoUnbound:3:1--3:40
 1 | %unbound_implicits off
 2 | interface Foo a where
 3 | interface Foo a => Bar (a : Type) where
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

with the patch we get no error.

Should this change go in the CHANGELOG?

  • If this is a fix, user-facing change, a compiler change, or a new paper
    implementation, I have updated CHANGELOG.md (and potentially also
    CONTRIBUTORS.md).

@gallais
Copy link
Member

gallais commented Aug 20, 2023

I don't think that's appropriate: a is indeed unbound here.
You should write something like (I don't have idris on this laptop yet):

%unbound_implicits off
interface {0 a : Type} -> Foo a where
interface {0 a : Type} -> Foo a => Bar a where

@dunhamsteve
Copy link
Contributor Author

I had tried that, and I thouht that would be more consistent with implementation. But the syntax you used does not exist on interface. I added the syntax yesterday and threaded it through to the interface elaboration. The issue that I ran into was that the Constraint types were the only ones relying on unbound implicits (IBindHere, etc). In all the other cases (the data type, etc), the parameters were explicitly added.

Here they are added to the data type:

let dty = bindPs params -- bind parameters
$ bindIFace vdfc ity -- bind interface (?!)
$ substNames vars methNameMap dty

And to the top level methods:

ty_imp <- bindTypeNames EmptyFC [] vars (bindPs params $ bindIFace vfc ity ty_constr)

with a note down here:
-- Bind the type parameters given explicitly - there might be information
-- in there that we can't infer after all
bindPs : List (Name, (RigCount, RawImp)) -> RawImp -> RawImp
bindPs [] ty = ty
bindPs ((n, rig, pty) :: ps) ty
= IPi (getFC pty) rig Implicit (Just n) pty (bindPs ps ty)

Adding those implicits up front, we could have the type of a declared twice:

interface {0 a : Type} -> Foo (a : Type -> Type)  where

So I had figured in for a penny, in for a pound, and have getConstraintHint work like everything else.

Currently params are added to the top level methods (see above) and the data type. Constraints (and only constraints) rely on unbound implicits. And they're added and then removed from the method declaration within the data (presumably because the data already has them up front):

-- Bind the type parameters given explicitly - there might be information
-- in there that we can't infer after all
bindPs : List (Name, (RigCount, RawImp)) -> RawImp -> RawImp
bindPs [] ty = ty
bindPs ((n, rig, pty) :: ps) ty
= IPi (getFC pty) rig Implicit (Just n) pty (bindPs ps ty)

If we want to add that syntax, we need to decide how it interacts with the (a : Type) declarations at the end, whether we want to continue to inject the params when unbound_implicits is off, and how it interacts with the injection of params when unbound_implicits is on (to avoid duplicate binders).

@mattpolzin
Copy link
Collaborator

This PR's changelog entry will likely end up under the v0.7.0 heading unintentionally if git is left to its own devices.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants