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

Type errors at the module level are puzzling #7336

Closed
vicuna opened this issue Aug 29, 2016 · 10 comments
Closed

Type errors at the module level are puzzling #7336

vicuna opened this issue Aug 29, 2016 · 10 comments

Comments

@vicuna
Copy link

vicuna commented Aug 29, 2016

Original bug ID: 7336
Reporter: @sliquister
Status: acknowledged (set by @xavierleroy on 2017-02-18T17:24:17Z)
Resolution: open
Priority: normal
Severity: feature
Version: 4.03.0
Target version: 4.07.0+dev/beta2/rc1/rc2
Category: typing
Child of: #7338
Monitored by: @gasche

Bug description

I got the following (legitimate) type error today:

$ ocamlopt -short-paths a.ml
File "a.ml", line 27, characters 11-12:
Error: Signature mismatch:
       ...
       Values do not match:
         val fold :
           ('a, 'b) hashtbl ->
           init:'c -> f:(key:'a -> data:'b -> 'c -> 'c) -> 'c
       is not included in
         val fold :
           ('a, 'b) t1 ->
           init:'c -> f:(key:Key.t -> data:'b -> 'c -> 'c) -> 'c
       File "a.ml", line 4, characters 2-85: Expected declaration
       File "a.ml", line 4, characters 2-85: Actual declaration

while building something I reduced to [1]. The details of the code or the error are not very important, the point is I was not able to figure out what the problem is until someone helped me, because the types printed are what I expect. It turns out the bug was in the definition of t1.

I think the type error reporting is not as good at the module level. I don't think I'm ever confused like that by errors that don't involve modules. Contrast with an error involving the same types, but when there is no module in sight:

$ ocamlopt -short-paths a.ml
File "a.ml", line 26, characters 32-33:
Error: This expression has type
         (a, b) t1 -> init:c -> f:(key:key -> data:b -> c -> c) -> c
       but an expression was expected of type
         (a, b) hashtbl -> init:c -> f:(key:a -> data:b -> c -> c) -> c
       Type (a, b) t1 = (key, a) hashtbl is not compatible with type
         (a, b) hashtbl
       Type key is not compatible with type a

I'd like the typer to give this kind of error at the module level too. If this error had been given, I would have probably found the problem right away.

(Here, it probably didn't help that we are forced to create useless types, t1 and key1, to use destructive substitutions, because now they show up in type errors. I'm trying to lift that restriction.)

[1]

module type S = sig
  type ('a, 'b) t
  type 'a key
  val fold :
    ('a, 'b) t -> init:'c -> f:(key:'a key -> data:'b -> 'c -> 'c) -> 'c
end

module M : S with type 'a key = 'a = struct
  type ('a, 'b) t
  type 'a key = 'a
  let fold = assert false
end

type ('a, 'b) t = ('a, 'b) M.t
module Make(Key : sig type t end) = struct
  type key = Key.t
  type ('a, 'b) hashtbl = ('a, 'b) t
  type 'a t = (key, 'a) hashtbl
  type ('a, 'b) t1 = (key, 'a) hashtbl
  type 'a key1 = key

  (* roughly equivalent type error at the value level:
    type a type b type c
    let x : (a, b) hashtbl -> init:c -> f:(key:a M.key -> data:b -> c -> c) -> c = assert false
    let y : (a, b) t1 -> init:c -> f:(key:Key.t -> data:b -> c -> c) -> c = assert false
    let _ = if true then x else y
  *)
  include (M : S
           with type ('a, 'b) t := ('a, 'b) t1
           with type 'a key := 'a key1)
end
@vicuna
Copy link
Author

vicuna commented Aug 30, 2016

Comment author: @sliquister

I think the problem is Includemod calls Includecore.value_descriptions, which calls Ctype.more_general, which drops the Unify exception and returns a boolean instead.

@vicuna
Copy link
Author

vicuna commented Apr 24, 2018

Comment author: @trefis

Follow-up: since #792 was merged (in 4.06) I believe the example can be reduced to:

module type S = sig
  type ('a, 'b) t
  type 'a key
  val fold :
    ('a, 'b) t -> init:'c -> f:(key:'a key -> data:'b -> 'c -> 'c) -> 'c
end

module M : S with type 'a key = 'a = struct
  type ('a, 'b) t
  type 'a key = 'a
  let fold = assert false
end

type ('a, 'b) t = ('a, 'b) M.t

module Make(Key : sig type t end) = struct
  type nonrec 'a t = (Key.t, 'a) t

  (* roughly equivalent type error at the value level:
    type a type b type c
    let x : (a, b) hashtbl -> init:c -> f:(key:a M.key -> data:b -> c -> c) -> c = assert false
    let y : (a, b) t1 -> init:c -> f:(key:Key.t -> data:b -> c -> c) -> c = assert false
    let _ = if true then x else y
  *)
  include (M : S
           with type ('a, 'b) t := 'a t
           with type 'a key := Key.t)
end

Which gives the following error messages (when running without -short-paths):

File "./a.ml", line 25, characters 11-12:
Error: Signature mismatch:
       ...
       Values do not match:
         val fold :
           ('a, 'b) t ->
           init:'c -> f:(key:'a key -> data:'b -> 'c -> 'c) -> 'c
       is not included in
         val fold :
           'a t -> init:'c -> f:(key:Key.t -> data:'b -> 'c -> 'c) -> 'c
       File "./a.ml", line 4, characters 2-85: Expected declaration
       File "./a.ml", line 4, characters 2-85: Actual declaration

When trying it with #1737 the last two lines become:

       File "./a.ml", line 25, characters 15-93: Expected declaration
       File "./a.ml", line 4, characters 2-85: Actual declaration

While this is very slightly better, it's indeed still fairly confusing.
I agree with sliquister previous message: reusing the trace we get from [moregen] instead of discarding it would probably help matters a lot.

@github-actions
Copy link

github-actions bot commented May 9, 2020

This issue has been open one year with no activity. Consequently, it is being marked with the "stale" label. What this means is that the issue will be automatically closed in 30 days unless more comments are added or the "stale" label is removed. Comments that provide new information on the issue are especially welcome: is it still reproducible? did it appear in other contexts? how critical is it? etc.

@github-actions github-actions bot added the Stale label May 9, 2020
@Drup
Copy link
Contributor

Drup commented May 9, 2020

I think the bug is still valid: we should expose the unification trace in case of signature item mismatch. IIRC, the additional information exposed by #9331 should make that easier to achieve.

@gasche
Copy link
Member

gasche commented May 9, 2020

@Drup could you submit a testsuite PR that contains the current behavior, in a known-misbehavior category or with otherwise a clear indication that this is something we want to improve?

@gasche gasche removed the Stale label May 9, 2020
@github-actions
Copy link

This issue has been open one year with no activity. Consequently, it is being marked with the "stale" label. What this means is that the issue will be automatically closed in 30 days unless more comments are added or the "stale" label is removed. Comments that provide new information on the issue are especially welcome: is it still reproducible? did it appear in other contexts? how critical is it? etc.

@github-actions github-actions bot added the Stale label May 12, 2021
@Octachron
Copy link
Member

See #10407 for a possible solution to this issue.

@github-actions github-actions bot removed the Stale label May 14, 2021
@XVilka
Copy link
Contributor

XVilka commented Sep 18, 2021

There is a label "error-messages", I suggest to assign it to this issue, it will finding all these error message improvements easier:
error-messages

@github-actions
Copy link

github-actions bot commented Oct 5, 2022

This issue has been open one year with no activity. Consequently, it is being marked with the "stale" label. What this means is that the issue will be automatically closed in 30 days unless more comments are added or the "stale" label is removed. Comments that provide new information on the issue are especially welcome: is it still reproducible? did it appear in other contexts? how critical is it? etc.

@github-actions github-actions bot added the Stale label Oct 5, 2022
@Octachron
Copy link
Member

The current error message has been extended to include the error trace:

         val fold :
           ('a, 'b) t/1 ->
           init:'c -> f:(key:'a key -> data:'b -> 'c -> 'c) -> 'c
       is not included in
         val fold :
           'a t/2 -> init:'c -> f:(key:Key.t -> data:'b -> 'c -> 'c) -> 'c
       The type
         (Key.t, 'a) t/1 ->
         init:'b -> f:(key:Key.t key -> data:'a -> 'b -> 'b) -> 'b
       is not compatible with the type
         'a t/2 -> init:'b -> f:(key:Key.t -> data:'c -> 'b -> 'b) -> 'b
       Type 'a is not compatible with type 'c 

which does point to incompatibility for the type of data. Let's thus close this issue.

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

No branches or pull requests

6 participants