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

Issue with constraint propagation #44

Open
lpw25 opened this issue Dec 30, 2015 · 0 comments
Open

Issue with constraint propagation #44

lpw25 opened this issue Dec 30, 2015 · 0 comments

Comments

@lpw25
Copy link
Member

lpw25 commented Dec 30, 2015

A bug report from @jordwalke:

module type OneSig = sig
  type t
  val oneValue: t -> string
end

module type TwoSig = sig
  type t
  val twoValue: t -> int
end

let hasBothOneAndTwo {OneImpl: OneSig} {TwoImpl: TwoSig with type t = OneImpl.t} o =
  let twoValue = string_of_int (TwoImpl.twoValue o) in
  let oneValue = OneImpl.oneValue o in
    oneValue ^ twoValue

implicit module HasBothForInt = struct
  type t = int
  let create () = 0
  let oneValue t = string_of_int t
  let twoValue t = t
end

implicit module HasBothForFloat = struct
  type t = float
  let create () = 0.0
  let oneValue t = string_of_float t
  let twoValue t = int_of_float t
end

let _ = hasBothOneAndTwo 4

gives the error:

Error: Ambiguous implicit OneImpl: HasBothForFloat and HasBothForInt are both solutions.

This is because functions with types like:

  val hasBothOneAndTwo :
    {OneImpl : OneSig} ->
      {TwoImpl : TwoSig with type t = OneImpl.t} ->
        TwoImpl.t -> string

are not handled correctly. Constraints generated by the TwoImpl.t
parameter are not propogated to the OneImpl implicit parameter. Since
the implicit parameters are currently searched left-to-right (at some
point we will make the search order-independent anyway, and then this
bug will be less noticable) the search for OneImpl fails as ambiguous.

There is a work-around, functions with types like:

  val hasBothOneAndTwo :
    {OneImpl : OneSig} ->
      {TwoImpl : TwoSig with type t = OneImpl.t} ->
        OneImpl.t -> string

do not suffer from this problem, so adding a type annotation fixes the issue:

let hasBothOneAndTwo {OneImpl: OneSig} {TwoImpl: TwoSig with type t = OneImpl.t} (o : OneImpl.t) =
  let twoValue = string_of_int (TwoImpl.twoValue o) in
  let oneValue = OneImpl.oneValue o in
    oneValue ^ twoValue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant