Version française
Home     About     Download     Resources     Contact us    
Browse thread
RE: [Caml-list] Pattern matcher no more supposed to warn on non exhaustive patterns ?
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Jacques Garrigue <garrigue@k...>
Subject: RE: [Caml-list] Pattern matcher no more supposed to warn on non exhaustive patterns ?
> The issue with threads is a bit more troublesome.  Consider:
> 
>   let x : (int->int) option ref = ref (Some (fun x -> x));;
> 
>   let foo z =
>       match z with
>         {contents=None} -> 0
>       | {contents=Some(f)} -> f(0);
> 
> Now suppose I fork two threads:
> 
> Thread 1:  foo x
> Thread 2:  x := None

Wouldn't the straightforward idea be to take a snapshot of the mutable
parts in the pattern before starting the matching ?
That is, convert the above to:
  let foo z =
    let z' = {contents=z.contents} in
    match z' with
      {contents=None} -> 0
    | {contents=Some f} -> f 0

The funny part is if you also have aliases in the pattern
  let foo z =
     match z with
       {contents=None} as x -> x.contents <- Some 0; 0
     | {contents=Some(f)} -> f(0);

Then you would have to make sure you return a pointer to the original
structure:
  let foo z =
    let x = z in
    let z' = {contents=z.contents} in
    match z' with
      {contents=None} -> x.contents <- Some 0; 0
    | {contents=Some f} -> f 0

It's even more complex than that, if you think of
  let foo z =
     match z with
       {contents=None} as x when (x.contents <- Some 1; false) -> 0
     | {contents=Some ({contents=None} as y)}
       when (y <- Some 1; false) -> 1
     | {contents=Some {contents=Some f}} -> f 0
     | _ -> 2

The idea is that you have to take snapshots of the type as you visit
it, so that every time you come back somewhere it has not changed.
So you build a shodow structure with both actual and copied nodes
(types are not correct):

type 'a shadow_ref = {real = 'a ref; copy = 'a ref}

let shadow_ref z = {real = z; copy = {contents = z.contents}}

let foo z =
  let zs = shadow_ref z in
  match zs.copy with
    {contents=None} ->
      zs.real.contents <- Some 1; if false then 0 else continue
  | {contents=Some z1} ->
      let z1s = shadow_ref z1 in
      zs.copy.contents <- Some z1s; (* update with a different type! *)
      begin match z1s.copy with
        {contents = None} ->
          z1s.real.contents <- Some 1; if false then 1 else continue
      | _ -> continue
      end
  | {contents=Some z1s} ->
      begin match z1s.copy with
        {contents = Some f} -> f 0
      | _ -> continue
      end
  | _ ->  2

Looks possible, but the algorithm might get heavy...

Jacques Garrigue
-------------------
Bug reports: http://caml.inria.fr/bin/caml-bugs  FAQ: http://caml.inria.fr/FAQ/
To unsubscribe, mail caml-list-request@inria.fr  Archives: http://caml.inria.fr