diff --git a/lib/check.ml b/lib/check.ml index 92421222..dbce1116 100644 --- a/lib/check.ml +++ b/lib/check.ml @@ -2419,12 +2419,11 @@ and const_steps ro (ty : Types.t) n = | _ -> ro (* A copy of a read-only slice's elements that can be written, spelled so it - compiles. Only for elements that own nothing: an element holding a Vec or - a Map — directly or inside a struct — would copy only its header, and the - copy would share the original's block. *) + compiles: [clone], for exactly the element types clone copies. It refuses + elements that own storage — a copy would share their blocks — and + elements that hold a dyn, which its allocator storage cannot root. *) let const_copy env (e : Types.t) = - if owning env e then None - else Some (Printf.sprintf "(slice (into v (vec-new %s)))" (Types.to_string e)) + if owning env e || holds_dyn env e then None else Some "(clone v)" (* A store through a read-only view: a [[const T]] or a (Ptr const T). *) let refuse_const_place env loc (view : Types.t) = @@ -3348,19 +3347,12 @@ let numeric_note ~(want : Types.t) ~(got : Types.t) = (%s x)" (Types.to_string want) -(* The rest of the sentence when a read-only slice meets a writable one. Both - copies it names compile today: [string] reads any byte slice and [bytes] - copies a string, and [into] pushes any slice's elements into a Vec that - [slice] then views. *) +(* The rest of the sentence when a read-only slice meets a writable one. *) let const_note env ~(want : Types.t) ~(got : Types.t) = match want, got with | Types.Slice (Types.Mut, e), Types.Slice (Types.Const, e') when Types.equal e e' -> - let copy = - match e with - | Types.Int Types.U8 -> Some "(bytes (string v))" - | _ -> const_copy env e - in + let copy = const_copy env e in Printf.sprintf " — a %s can only be read, and never becomes a %s that can be written \ through. %sWhere nothing writes through it, the %s can be declared %s \ @@ -3989,8 +3981,8 @@ and refuse_owned_copy ctx (r : Tast.expr) = match r.Tast.ty with | (Types.Vec _ | Types.Map _) when not (region_only ctx.env r.Tast.ty) -> Printf.sprintf "(clone v) copies it into a %s of its own" t - (* TODO.org, "(clone slice)": once clone copies any value that owns - storage, this should say (clone v) too. *) + (* Nothing copies an array, an Option or a struct that owns storage, + nor a container whose elements do: its address is the way to it. *) | _ -> Printf.sprintf "(addr v) gives a (Ptr const %s) to read it through" t in Loc.failk "check/const-owned-copy" r.Tast.loc diff --git a/test/test_flan.ml b/test/test_flan.ml index fba88422..583d6bf1 100644 --- a/test/test_flan.ml +++ b/test/test_flan.ml @@ -2283,7 +2283,18 @@ let () = ~needle:"expected [u8], found [const u8]"; rejects_check "and the refusal names the copy" "(defn g [b [u8]] () (set (at b 0) 1)) (defn f [s [const u8]] () (g s))" - ~needle:"(bytes (string v)) copies v"; + ~needle:"(clone v) copies v into a [u8] of its own"; + accepts "and the copy it names compiles" + "(defn g [b [u8]] () (set (at b 0) 1)) (defn f [s [const u8]] () (g (clone s)))"; + rejects_check "a store through a const slice names clone" + "(defstruct P [x i32]) (defn f [v [const P]] () (set (.x (at v 0)) 1))" + ~needle:"(clone v) copies v's elements into one"; + accepts "and that clone compiles" + "(defstruct P [x i32]) \ + (defn f [v [const P]] () (let [w (clone v)] (set (.x (at w 0)) 1)))"; + rejects_check "no clone named for elements clone refuses" + "(defn f [v [const dyn]] () (set (at v 0) 1))" + ~needle:"take it as a [dyn] instead"; rejects_check "a generic writer does not take a const slice" "(defn f [s [const i32]] () (sort s))" ~needle:"sort takes a slice it may write through";