(* TEST flags = " -w +A -strict-sequence "; expect; *) (* Use type information *) module M1 = struct type t = {x: int; y: int} type u = {x: bool; y: bool} end;; [%%expect{| module M1 : sig type t = { x : int; y : int; } type u = { x : bool; y : bool; } end |}] module OK = struct open M1 let f1 (r:t) = r.x (* ok *) let f2 r = ignore (r:t); r.x (* non principal *) let f3 (r: t) = match r with {x; y} -> y + y (* ok *) end;; [%%expect{| Line 3, characters 19-20: 3 | let f1 (r:t) = r.x (* ok *) ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 4, characters 29-30: 4 | let f2 r = ignore (r:t); r.x (* non principal *) ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 7, characters 18-19: 7 | match r with {x; y} -> y + y (* ok *) ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 7, characters 21-22: 7 | match r with {x; y} -> y + y (* ok *) ^ Warning 42 [disambiguated-name]: this use of y relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 7, characters 18-19: 7 | match r with {x; y} -> y + y (* ok *) ^ Warning 27 [unused-var-strict]: unused variable x. module OK : sig val f1 : M1.t -> int val f2 : M1.t -> int val f3 : M1.t -> int end |}, Principal{| Line 3, characters 19-20: 3 | let f1 (r:t) = r.x (* ok *) ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 4, characters 29-30: 4 | let f2 r = ignore (r:t); r.x (* non principal *) ^ Warning 18 [not-principal]: this type-based field disambiguation is not principal. Line 4, characters 29-30: 4 | let f2 r = ignore (r:t); r.x (* non principal *) ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 7, characters 18-19: 7 | match r with {x; y} -> y + y (* ok *) ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 7, characters 21-22: 7 | match r with {x; y} -> y + y (* ok *) ^ Warning 42 [disambiguated-name]: this use of y relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 7, characters 18-19: 7 | match r with {x; y} -> y + y (* ok *) ^ Warning 27 [unused-var-strict]: unused variable x. module OK : sig val f1 : M1.t -> int val f2 : M1.t -> int val f3 : M1.t -> int end |}] module F1 = struct open M1 let f r = match r with {x; y} -> y + y end;; (* fails *) [%%expect{| Line 3, characters 25-31: 3 | let f r = match r with {x; y} -> y + y ^^^^^^ Warning 41 [ambiguous-name]: these field labels belong to several types: M1.u M1.t The first one was selected. Please disambiguate if this is wrong. Line 3, characters 35-36: 3 | let f r = match r with {x; y} -> y + y ^ Error: This expression has type bool but an expression was expected of type int |}] module F2 = struct open M1 let f r = ignore (r: t); match r with {x; y} -> y + y end;; (* fails for -principal *) [%%expect{| Line 6, characters 8-9: 6 | {x; y} -> y + y ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 6, characters 11-12: 6 | {x; y} -> y + y ^ Warning 42 [disambiguated-name]: this use of y relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 6, characters 8-9: 6 | {x; y} -> y + y ^ Warning 27 [unused-var-strict]: unused variable x. module F2 : sig val f : M1.t -> int end |}, Principal{| Line 6, characters 8-9: 6 | {x; y} -> y + y ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 6, characters 11-12: 6 | {x; y} -> y + y ^ Warning 42 [disambiguated-name]: this use of y relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 6, characters 7-13: 6 | {x; y} -> y + y ^^^^^^ Warning 18 [not-principal]: this type-based record disambiguation is not principal. Line 6, characters 8-9: 6 | {x; y} -> y + y ^ Warning 27 [unused-var-strict]: unused variable x. module F2 : sig val f : M1.t -> int end |}] (* Use type information with modules*) module M = struct type t = {x:int} type u = {x:bool} end;; [%%expect{| module M : sig type t = { x : int; } type u = { x : bool; } end |}] let f (r:M.t) = r.M.x;; (* ok *) [%%expect{| Line 1, characters 18-21: 1 | let f (r:M.t) = r.M.x;; (* ok *) ^^^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. val f : M.t -> int = |}] let f (r:M.t) = r.x;; (* warning *) [%%expect{| Line 1, characters 18-19: 1 | let f (r:M.t) = r.x;; (* warning *) ^ Warning 40 [name-out-of-scope]: x was selected from type M.t. It is not visible in the current scope, and will not be selected if the type becomes unknown. Line 1, characters 18-19: 1 | let f (r:M.t) = r.x;; (* warning *) ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. val f : M.t -> int = |}] let f ({x}:M.t) = x;; (* warning *) [%%expect{| Line 1, characters 8-9: 1 | let f ({x}:M.t) = x;; (* warning *) ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 1, characters 7-10: 1 | let f ({x}:M.t) = x;; (* warning *) ^^^ Warning 40 [name-out-of-scope]: this record of type M.t contains fields that are not visible in the current scope: x. They will not be selected if the type becomes unknown. val f : M.t -> int = |}] module M = struct type t = {x: int; y: int} end;; [%%expect{| module M : sig type t = { x : int; y : int; } end |}] module N = struct type u = {x: bool; y: bool} end;; [%%expect{| module N : sig type u = { x : bool; y : bool; } end |}] module OK = struct open M open N let f (r:M.t) = r.x end;; [%%expect{| Line 4, characters 20-21: 4 | let f (r:M.t) = r.x ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 3, characters 2-8: 3 | open N ^^^^^^ Warning 33 [unused-open]: unused open N. module OK : sig val f : M.t -> int end |}] module M = struct type t = {x:int} module N = struct type s = t = {x:int} end type u = {x:bool} end;; [%%expect{| module M : sig type t = { x : int; } module N : sig type s = t = { x : int; } end type u = { x : bool; } end |}] module OK = struct open M.N let f (r:M.t) = r.x end;; [%%expect{| module OK : sig val f : M.t -> int end |}] (* Use field information *) module M = struct type u = {x:bool;y:int;z:char} type t = {x:int;y:bool} end;; [%%expect{| module M : sig type u = { x : bool; y : int; z : char; } type t = { x : int; y : bool; } end |}] module OK = struct open M let f {x;z} = x,z end;; (* ok *) [%%expect{| Line 3, characters 9-10: 3 | let f {x;z} = x,z ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 3, characters 8-13: 3 | let f {x;z} = x,z ^^^^^ Warning 9 [missing-record-field-pattern]: the following labels are not bound in this record pattern: y Either bind these labels explicitly or add '; _' to the pattern. module OK : sig val f : M.u -> bool * char end |}] module F3 = struct open M let r = {x=true;z='z'} end;; (* fail for missing label *) [%%expect{| Line 3, characters 11-12: 3 | let r = {x=true;z='z'} ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 3, characters 10-24: 3 | let r = {x=true;z='z'} ^^^^^^^^^^^^^^ Error: Some record fields are undefined: y |}] module OK = struct type u = {x:int;y:bool} type t = {x:bool;y:int;z:char} let r = {x=3; y=true} end;; (* ok *) [%%expect{| Line 4, characters 11-12: 4 | let r = {x=3; y=true} ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 4, characters 16-17: 4 | let r = {x=3; y=true} ^ Warning 42 [disambiguated-name]: this use of y relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. module OK : sig type u = { x : int; y : bool; } type t = { x : bool; y : int; z : char; } val r : u end |}] (* Corner cases *) module F4 = struct type foo = {x:int; y:int} type bar = {x:int} let b : bar = {x=3; y=4} end;; (* fail but don't warn *) [%%expect{| Line 4, characters 22-23: 4 | let b : bar = {x=3; y=4} ^ Error: This record expression is expected to have type bar There is no field y within type bar |}] module M = struct type foo = {x:int;y:int} end;; [%%expect{| module M : sig type foo = { x : int; y : int; } end |}] module N = struct type bar = {x:int;y:int} end;; [%%expect{| module N : sig type bar = { x : int; y : int; } end |}] let r = { M.x = 3; N.y = 4; };; (* error: different definitions *) [%%expect{| Line 1, characters 19-22: 1 | let r = { M.x = 3; N.y = 4; };; (* error: different definitions *) ^^^ Error: The record field N.y belongs to the type N.bar but is mixed here with fields of type M.foo |}] module MN = struct include M include N end module NM = struct include N include M end;; [%%expect{| module MN : sig type foo = M.foo = { x : int; y : int; } type bar = N.bar = { x : int; y : int; } end module NM : sig type bar = N.bar = { x : int; y : int; } type foo = M.foo = { x : int; y : int; } end |}] let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) [%%expect{| Line 1, characters 8-28: 1 | let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) ^^^^^^^^^^^^^^^^^^^^ Warning 41 [ambiguous-name]: x belongs to several types: MN.bar MN.foo The first one was selected. Please disambiguate if this is wrong. Line 1, characters 8-28: 1 | let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) ^^^^^^^^^^^^^^^^^^^^ Warning 41 [ambiguous-name]: y belongs to several types: NM.foo NM.bar The first one was selected. Please disambiguate if this is wrong. Line 1, characters 19-23: 1 | let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) ^^^^ Error: The record field NM.y belongs to the type NM.foo = M.foo but is mixed here with fields of type MN.bar = N.bar |}] (* Lpw25 *) module M = struct type foo = { x: int; y: int } type bar = { x:int; y: int; z: int} end;; [%%expect{| module M : sig type foo = { x : int; y : int; } type bar = { x : int; y : int; z : int; } end |}] module F5 = struct open M let f r = ignore (r: foo); {r with x = 2; z = 3} end;; [%%expect{| Line 3, characters 37-38: 3 | let f r = ignore (r: foo); {r with x = 2; z = 3} ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 3, characters 44-45: 3 | let f r = ignore (r: foo); {r with x = 2; z = 3} ^ Error: This record expression is expected to have type M.foo There is no field z within type M.foo |}] module M = struct include M type other = { a: int; b: int } end;; [%%expect{| module M : sig type foo = M.foo = { x : int; y : int; } type bar = M.bar = { x : int; y : int; z : int; } type other = { a : int; b : int; } end |}] module F6 = struct open M let f r = ignore (r: foo); { r with x = 3; a = 4 } end;; [%%expect{| Line 3, characters 38-39: 3 | let f r = ignore (r: foo); { r with x = 3; a = 4 } ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 3, characters 45-46: 3 | let f r = ignore (r: foo); { r with x = 3; a = 4 } ^ Error: This record expression is expected to have type M.foo There is no field a within type M.foo |}] module F7 = struct open M let r = {x=1; y=2} let r: other = {x=1; y=2} end;; [%%expect{| Line 3, characters 11-12: 3 | let r = {x=1; y=2} ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 3, characters 16-17: 3 | let r = {x=1; y=2} ^ Warning 42 [disambiguated-name]: this use of y relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 4, characters 18-19: 4 | let r: other = {x=1; y=2} ^ Error: This record expression is expected to have type M.other There is no field x within type M.other |}] module A = struct type t = {x: int} end module B = struct type t = {x: int} end;; [%%expect{| module A : sig type t = { x : int; } end module B : sig type t = { x : int; } end |}] let f (r : B.t) = r.A.x;; (* fail *) [%%expect{| Line 1, characters 20-23: 1 | let f (r : B.t) = r.A.x;; (* fail *) ^^^ Error: The field A.x belongs to the record type A.t but a field was expected belonging to the record type B.t |}] (* Spellchecking *) module F8 = struct type t = {x:int; yyy:int} let a : t = {x=1;yyz=2} end;; [%%expect{| Line 3, characters 19-22: 3 | let a : t = {x=1;yyz=2} ^^^ Error: This record expression is expected to have type t There is no field yyz within type t Hint: Did you mean yyy? |}] (* PR#6004 *) type t = A type s = A class f (_ : t) = object end;; [%%expect{| type t = A type s = A class f : t -> object end |}] class g = f A;; (* ok *) class f (_ : 'a) (_ : 'a) = object end;; [%%expect{| Line 1, characters 12-13: 1 | class g = f A;; (* ok *) ^ Warning 42 [disambiguated-name]: this use of A relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. class g : f class f : 'a -> 'a -> object end |}] class g = f (A : t) A;; (* warn with -principal *) [%%expect{| Line 1, characters 13-14: 1 | class g = f (A : t) A;; (* warn with -principal *) ^ Warning 42 [disambiguated-name]: this use of A relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 1, characters 20-21: 1 | class g = f (A : t) A;; (* warn with -principal *) ^ Warning 42 [disambiguated-name]: this use of A relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. class g : f |}, Principal{| Line 1, characters 13-14: 1 | class g = f (A : t) A;; (* warn with -principal *) ^ Warning 42 [disambiguated-name]: this use of A relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 1, characters 20-21: 1 | class g = f (A : t) A;; (* warn with -principal *) ^ Warning 18 [not-principal]: this type-based constructor disambiguation is not principal. Line 1, characters 20-21: 1 | class g = f (A : t) A;; (* warn with -principal *) ^ Warning 42 [disambiguated-name]: this use of A relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. class g : f |}] (* PR#5980 *) module Shadow1 = struct type t = {x: int} module M = struct type s = {x: string} end open M (* this open is unused, it isn't reported as shadowing 'x' *) let y : t = {x = 0} end;; [%%expect{| Line 7, characters 15-16: 7 | let y : t = {x = 0} ^ Warning 42 [disambiguated-name]: this use of x relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 6, characters 2-8: 6 | open M (* this open is unused, it isn't reported as shadowing 'x' *) ^^^^^^ Warning 33 [unused-open]: unused open M. module Shadow1 : sig type t = { x : int; } module M : sig type s = { x : string; } end val y : t end |}] module Shadow2 = struct type t = {x: int} module M = struct type s = {x: string} end open M (* this open shadows label 'x' *) let y = {x = ""} end;; [%%expect{| Line 6, characters 2-8: 6 | open M (* this open shadows label 'x' *) ^^^^^^ Warning 45 [open-shadow-label-constructor]: this open statement shadows the label x (which is later used) Line 7, characters 10-18: 7 | let y = {x = ""} ^^^^^^^^ Warning 41 [ambiguous-name]: these field labels belong to several types: M.s t The first one was selected. Please disambiguate if this is wrong. module Shadow2 : sig type t = { x : int; } module M : sig type s = { x : string; } end val y : M.s end |}] (* PR#6235 *) module P6235 = struct type t = { loc : string; } type v = { loc : string; x : int; } type u = [ `Key of t ] let f (u : u) = match u with `Key {loc} -> loc end;; [%%expect{| Line 5, characters 37-40: 5 | let f (u : u) = match u with `Key {loc} -> loc ^^^ Warning 42 [disambiguated-name]: this use of loc relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. module P6235 : sig type t = { loc : string; } type v = { loc : string; x : int; } type u = [ `Key of t ] val f : u -> string end |}] (* Remove interaction between branches *) module P6235' = struct type t = { loc : string; } type v = { loc : string; x : int; } type u = [ `Key of t ] let f = function | (_ : u) when false -> "" |`Key {loc} -> loc end;; [%%expect{| Line 7, characters 11-14: 7 | |`Key {loc} -> loc ^^^ Warning 42 [disambiguated-name]: this use of loc relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. module P6235' : sig type t = { loc : string; } type v = { loc : string; x : int; } type u = [ `Key of t ] val f : u -> string end |}, Principal{| Line 7, characters 11-14: 7 | |`Key {loc} -> loc ^^^ Warning 42 [disambiguated-name]: this use of loc relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 7, characters 10-15: 7 | |`Key {loc} -> loc ^^^^^ Warning 18 [not-principal]: this type-based record disambiguation is not principal. module P6235' : sig type t = { loc : string; } type v = { loc : string; x : int; } type u = [ `Key of t ] val f : u -> string end |}] (** no candidates after filtering; This caused a temporary trunk regression identified by Florian Angeletti while reviewing #9196 *) module M = struct type t = { x:int; y:int} end type u = { a:int } let _ = ( { M.x=0 } : u );; [%%expect{| module M : sig type t = { x : int; y : int; } end type u = { a : int; } Line 5, characters 12-15: 5 | let _ = ( { M.x=0 } : u );; ^^^ Error: The field M.x belongs to the record type M.t but a field was expected belonging to the record type u |}] (* PR#8747 *) module M = struct type t = { x : int; y: char } end let f (x : M.t) = { x with y = 'a' } let g (x : M.t) = { x with y = 'a' } :: [] let h (x : M.t) = { x with y = 'a' } :: { x with y = 'b' } :: [];; [%%expect{| module M : sig type t = { x : int; y : char; } end Line 2, characters 27-28: 2 | let f (x : M.t) = { x with y = 'a' } ^ Warning 42 [disambiguated-name]: this use of y relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 2, characters 18-36: 2 | let f (x : M.t) = { x with y = 'a' } ^^^^^^^^^^^^^^^^^^ Warning 40 [name-out-of-scope]: this record of type M.t contains fields that are not visible in the current scope: y. They will not be selected if the type becomes unknown. val f : M.t -> M.t = Line 3, characters 27-28: 3 | let g (x : M.t) = { x with y = 'a' } :: [] ^ Warning 42 [disambiguated-name]: this use of y relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 3, characters 18-36: 3 | let g (x : M.t) = { x with y = 'a' } :: [] ^^^^^^^^^^^^^^^^^^ Warning 40 [name-out-of-scope]: this record of type M.t contains fields that are not visible in the current scope: y. They will not be selected if the type becomes unknown. val g : M.t -> M.t list = Line 4, characters 27-28: 4 | let h (x : M.t) = { x with y = 'a' } :: { x with y = 'b' } :: [];; ^ Warning 42 [disambiguated-name]: this use of y relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 4, characters 18-36: 4 | let h (x : M.t) = { x with y = 'a' } :: { x with y = 'b' } :: [];; ^^^^^^^^^^^^^^^^^^ Warning 40 [name-out-of-scope]: this record of type M.t contains fields that are not visible in the current scope: y. They will not be selected if the type becomes unknown. Line 4, characters 49-50: 4 | let h (x : M.t) = { x with y = 'a' } :: { x with y = 'b' } :: [];; ^ Warning 42 [disambiguated-name]: this use of y relies on type-directed disambiguation, it will not compile with OCaml 4.00 or earlier. Line 4, characters 40-58: 4 | let h (x : M.t) = { x with y = 'a' } :: { x with y = 'b' } :: [];; ^^^^^^^^^^^^^^^^^^ Warning 40 [name-out-of-scope]: this record of type M.t contains fields that are not visible in the current scope: y. They will not be selected if the type becomes unknown. val h : M.t -> M.t list = |}]