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

Typechecking infers incorrect types #2517

Closed
lukaszcz opened this issue Nov 16, 2023 · 9 comments
Closed

Typechecking infers incorrect types #2517

lukaszcz opened this issue Nov 16, 2023 · 9 comments
Assignees
Milestone

Comments

@lukaszcz
Copy link
Collaborator

Input:

module ty1;

import Stdlib.Prelude open;

trait
type Functor (f : Type -> Type) :=
  mkFunctor {
    fmap : {A B : Type} -> (A -> B) -> f A -> f B
  };

instance
listFunctorI : Functor List :=
  mkFunctor@{
    fmap := map;
  };

Output after running uvix dev internal typecheck ty1.juvix --print-result --new-typechecker:

import Stdlib.Prelude

mutual {
  listFunctorI : Functor List
    := let 
      not-mutual fmap : (f : A → B) → List A → List B
        := map {A} {B}
     in let 
      not-mutual f : Type → Type := List
      not-mutual fmap : {A : Type} → {B : Type} → (A → B) → f A → f B
        := λ {| {_ω1276} {_ω1277} := fmap}
     in mkFunctor {f} fmap

  type Functor (f : Type → Type) =
    mkFunctor : (fmap : {A : Type} → {B : Type} → (A → B) → f A → f B) → Functor f
}

mutual fmap : {f : Type → Type} → {{Functor f}} → {A : Type} → {B : Type} → (A → B) → f A → f B
  := λ : {f : Type → Type} → {{Functor f}} → {A : Type} → {B : Type} → (A → B) → f A → f B {| {_ω1282} ({{(mkFunctor a : Functor _ω1282)}}) {_ω1283} {_ω1284} := a {A} {B}}

In the fist fmap, the type variables A and B are not bound, which later makes the translation from Internal to Core fail.

@lukaszcz lukaszcz added this to the 0.5.4 milestone Nov 16, 2023
@lukaszcz lukaszcz changed the title The new typechecking algorithm infers incorrect types Record creation syntax causes typechecking to infer incorrect types Nov 16, 2023
@lukaszcz lukaszcz changed the title Record creation syntax causes typechecking to infer incorrect types New named arguments syntax causes typechecking to infer incorrect types Nov 16, 2023
@lukaszcz
Copy link
Collaborator Author

This is actually a bug with the new named arguments syntax. Just before having type constructor parameters for inductive types we never used type variables in constructors.

@lukaszcz lukaszcz self-assigned this Nov 16, 2023
@lukaszcz
Copy link
Collaborator Author

lukaszcz commented Nov 16, 2023

Well, the bug is in the typechecker, both the new and old one, the named arguments syntax only exposes it.

Running juvix dev internal pretty ty1.juvix --new-typechecker results in:

mutual {
  listFunctorI : Functor List
    := let 
      not-mutual fmap : _ := map
     in let 
      not-mutual f : Type → Type := _
      not-mutual fmap : {A : Type} → {B : Type} → (A → B) → f A → f B
        := fmap
     in mkFunctor {f} fmap

  type Functor (f : Type → Type) =
    mkFunctor : (fmap : {A : Type} → {B : Type} → (A → B) → f A → f B) → Functor f
}

This is still correct. The holes are incorrectly inferred, without taking scope into account.

@lukaszcz
Copy link
Collaborator Author

lukaszcz commented Nov 16, 2023

For the old typechecker, the following input exposes the bug:

module ty2;

import Stdlib.Prelude open;

trait
type Functor (F : Type) :=
  mkFunctor {
    fmap : {A : Type} -> (A -> A) -> F -> F
  };

fmapLst {A} (f : A -> A) (l : List Nat) : List Nat := l;

instance
listFunctorI : Functor (List Nat) :=
  mkFunctor@{
    fmap := fmapLst;
  };

@lukaszcz
Copy link
Collaborator Author

@janmasrovira can you look at this? Is there some easy fix or this exposes a bigger issue with holes having no context?

@lukaszcz lukaszcz changed the title New named arguments syntax causes typechecking to infer incorrect types Typechecking infers incorrect types Nov 16, 2023
@lukaszcz
Copy link
Collaborator Author

lukaszcz commented Nov 16, 2023

A simpler example without traits:

module ty3;

id0 : {A : Type} -> A -> A :=
  let id : _ := λ{x := x};
      id' : {A : Type} -> A -> A := id
  in id';

Running juvix dev internal typecheck ty3.juvix --print-result gives:

mutual id0 : {A : Type} → A → A
  := let 
    not-mutual id : _ω8 → _ω8 := λ : _ω8 → _ω8 {| x := x}
    not-mutual id' : {A : Type} → A → A
      := λ : {A : Type} → A → A {| {_ω8} := id}
   in id'

Running juvix typecheck ty3.juvix results in:

juvix: impossible
CallStack (from HasCallStack):
  error, called at src/Juvix/Prelude/Base.hs:392:14 in juvix-0.5.3-6xl5bc4fEBjCQTOL6knJUZ:Juvix.Prelude.Base
  impossible, called at src/Juvix/Compiler/Core/Translation/FromInternal.hs:859:34 in juvix-0.5.3-6xl5bc4fEBjCQTOL6knJUZ:Juvix.Compiler.Core.Translation.FromInternal

@lukaszcz
Copy link
Collaborator Author

It seems like the problem is with not remembering the hole context.

@janmasrovira
Copy link
Collaborator

this could be related or the exact same problem as #2247

@lukaszcz
Copy link
Collaborator Author

lukaszcz commented Nov 16, 2023

I guess we need to fix this before making use of type constructor inductive parameters. This bug gets exposed whenever there are record fields with implicit type arguments, which happens with Functor and so on. A workaround is to explicitly annotate the types of all such fields in record construction or don't use the named arguments syntax in such cases, but this is not acceptable. The translation from Internal to Core seems to work with the new typechecker with these workarounds.

@jonaprieto jonaprieto modified the milestones: 0.5.4, 0.5.5 Nov 17, 2023
janmasrovira added a commit that referenced this issue Nov 28, 2023
This pr applies a number of fixes to the new typechecker.
The fixes implemented are:
1. When guessing the arity of the body, we properly use the type
information of the variables in the patterns.
2. When generating wildcards, we name them properly so that they align
with the name in the type signature.
3. When compiling named applications, we inline all clauses of the form
`fun : _ := body`. This is a workaround to
#2247 and
#2517
4. I've had to ignore test027 (Church numerals). While the typechecker
passes and one can see that the types are correct, there is a lambda
where its clauses have different number of patterns. Our goal is to
support that in the near future
(#1706). This is the conflicting
lambda:
    ```
    mutual num : Nat → Num
      := λ : Nat → Num {| (zero : Nat) := czero
      | ((suc n : Nat)) {A} := csuc (num n) {A}}
    ```
5. I've added non-trivial a compilation test involving monad
transformers.
@jonaprieto jonaprieto modified the milestones: 0.5.5, 0.5.6 Dec 1, 2023
@janmasrovira
Copy link
Collaborator

The original problem reported in this issue has been solved in #2524.

The #2247 problem still remains but I'm closing this to avoid duplicates.

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

When branches are created from issues, their pull requests are automatically linked.

3 participants