diff --git a/samples/hoare.as b/samples/hoare.as index 0b35a5536de..596aa6fff0d 100644 --- a/samples/hoare.as +++ b/samples/hoare.as @@ -1,12 +1,12 @@ /* integer quicksort as top-level functions */ -func swap(a : var Int[], i : Nat, j : Nat) { +func swap(a : [var Int], i : Nat, j : Nat) { let temp = a[i]; a[i] := a[j]; a[j] := temp; }; -func partition(a : var Int[], lo : Nat, hi : Nat) : Nat { +func partition(a : [var Int], lo : Nat, hi : Nat) : Nat { let pivot = a[lo]; var i : Nat = lo; var j : Nat = hi; @@ -19,7 +19,7 @@ func partition(a : var Int[], lo : Nat, hi : Nat) : Nat { }; }; -func quicksort(a : var Int[], lo : Nat, hi : Nat) { +func quicksort(a : [var Int], lo : Nat, hi : Nat) { if (lo < hi) { let p = partition(a, lo, hi); quicksort(a, lo, p); @@ -27,5 +27,5 @@ func quicksort(a : var Int[], lo : Nat, hi : Nat) { }; }; -let a : var Int[] = [8, 3, 9, 5, 2]; +let a : [var Int] = [var 8, 3, 9, 5, 2]; quicksort(a, 0, 4); diff --git a/samples/hoare.txt b/samples/hoare.txt index fe9c5a836a6..8f46d9bff0c 100644 --- a/samples/hoare.txt +++ b/samples/hoare.txt @@ -1,8 +1,8 @@ -- Checking hoare.as: -let a : var Int[] -let partition : (var Int[], Nat, Nat) -> Nat -let quicksort : (var Int[], Nat, Nat) -> () -let swap : (var Int[], Nat, Nat) -> () +let a : [var Int] +let partition : ([var Int], Nat, Nat) -> Nat +let quicksort : ([var Int], Nat, Nat) -> () +let swap : ([var Int], Nat, Nat) -> () -- Interpreting hoare.as: quicksort([8, 3, 9, 5, 2], 0, 4) partition([8, 3, 9, 5, 2], 0, 4) @@ -37,8 +37,8 @@ quicksort([8, 3, 9, 5, 2], 0, 4) <= () <= () -- Finished hoare.as: -let a : var Int[] = [2, 3, 5, 8, 9] -let partition : (var Int[], Nat, Nat) -> Nat = func -let quicksort : (var Int[], Nat, Nat) -> () = func -let swap : (var Int[], Nat, Nat) -> () = func +let a : [var Int] = [2, 3, 5, 8, 9] +let partition : ([var Int], Nat, Nat) -> Nat = func +let quicksort : ([var Int], Nat, Nat) -> () = func +let swap : ([var Int], Nat, Nat) -> () = func diff --git a/samples/quicksort.as b/samples/quicksort.as index 8be08f3a86f..a30245bd90e 100644 --- a/samples/quicksort.as +++ b/samples/quicksort.as @@ -2,7 +2,7 @@ - inplace sorting of mutable arrays of T, for any type T */ -type Array = var T[]; +type Array = [var T]; class QS(cmp : (T, T) -> Int) { quicksort(a : Array, lo : Nat, hi : Nat) { @@ -44,5 +44,5 @@ class QS(cmp : (T, T) -> Int) { func cmpi(i : Int, j : Int) : Int = i - j; let qs = QS(cmpi); -let a : Array = [8, 3, 9, 5, 2]; +let a : Array = [var 8, 3, 9, 5, 2]; qs.quicksort(a, 0, 4); diff --git a/samples/quicksort.txt b/samples/quicksort.txt index e82cb16c9f9..f1fc827ed19 100644 --- a/samples/quicksort.txt +++ b/samples/quicksort.txt @@ -1,5 +1,5 @@ -- Checking quicksort.as: -type Array = var T[] +type Array = [var T] type QS <: {quicksort : (Array, Nat, Nat) -> ()} let QS : class ((T, T) -> Int) -> QS let a : Array diff --git a/src/arrange.ml b/src/arrange.ml index 4ec0a34ae36..59ec4d2561a 100644 --- a/src/arrange.ml +++ b/src/arrange.ml @@ -15,7 +15,7 @@ let rec exp e = match e.it with | ObjE (s, i, efs) -> "ObjE" $$ [obj_sort s; id i] @ List.map exp_field efs | DotE (e, n) -> "DotE" $$ [exp e; name n] | AssignE (e1, e2) -> "AssignE" $$ [exp e1; exp e2] - | ArrayE es -> "ArrayE" $$ List.map exp es + | ArrayE (m, es) -> "ArrayE" $$ [mut m] @ List.map exp es | IdxE (e1, e2) -> "IdxE" $$ [exp e1; exp e2] | CallE (e1, ts, e2) -> "CallE" $$ [exp e1] @ List.map typ ts @ [exp e2] | BlockE ds -> "BlockE" $$ List.map dec ds diff --git a/src/arrange_ir.ml b/src/arrange_ir.ml index 1dd6f78b52c..2927a521eea 100644 --- a/src/arrange_ir.ml +++ b/src/arrange_ir.ml @@ -15,7 +15,7 @@ let rec exp e = match e.it with | ObjE (s, i, efs) -> "ObjE" $$ [Arrange.obj_sort s; id i] @ List.map exp_field efs | DotE (e, n) -> "DotE" $$ [exp e; name n] | AssignE (e1, e2) -> "AssignE" $$ [exp e1; exp e2] - | ArrayE es -> "ArrayE" $$ List.map exp es + | ArrayE (m, es) -> "ArrayE" $$ [Arrange.mut m] @ List.map exp es | IdxE (e1, e2) -> "IdxE" $$ [exp e1; exp e2] | CallE (cc, e1, ts, e2) -> "CallE" $$ [Atom (Value.string_of_call_conv cc); exp e1] @ List.map Arrange.typ ts @ [exp e2] | BlockE ds -> "BlockE" $$ List.map dec ds diff --git a/src/async.ml b/src/async.ml index 9c36c1b038e..720632021d0 100644 --- a/src/async.ml +++ b/src/async.ml @@ -235,8 +235,8 @@ and t_exp' (exp:Syntax.exp) = DotE (t_exp exp1, id) | AssignE (exp1, exp2) -> AssignE (t_exp exp1, t_exp exp2) - | ArrayE exps -> - ArrayE (List.map t_exp exps) + | ArrayE (mut, exps) -> + ArrayE (mut, List.map t_exp exps) | IdxE (exp1, exp2) -> IdxE (t_exp exp1, t_exp exp2) | CallE ({it=PrimE "@await";_}, typs, exp2) -> diff --git a/src/awaitopt.ml b/src/awaitopt.ml index be02d04bbcf..609d9c88cc7 100644 --- a/src/awaitopt.ml +++ b/src/awaitopt.ml @@ -86,8 +86,8 @@ and t_exp' context exp' = DotE (t_exp context exp1, id) | AssignE (exp1, exp2) -> AssignE (t_exp context exp1, t_exp context exp2) - | ArrayE exps -> - ArrayE (List.map (t_exp context) exps) + | ArrayE (mut, exps) -> + ArrayE (mut, List.map (t_exp context) exps) | IdxE (exp1, exp2) -> IdxE (t_exp context exp1, t_exp context exp2) | CallE (exp1, typs, exp2) -> @@ -409,8 +409,8 @@ and c_exp' context exp k = unary context k (fun v1 -> e (DotE (v1, id))) exp1 | AssignE (exp1, exp2) -> binary context k (fun v1 v2 -> e (AssignE (v1, v2))) exp1 exp2 - | ArrayE exps -> - nary context k (fun vs -> e (ArrayE vs)) exps + | ArrayE (mut, exps) -> + nary context k (fun vs -> e (ArrayE (mut, vs))) exps | IdxE (exp1, exp2) -> binary context k (fun v1 v2 -> e (IdxE (v1, v2))) exp1 exp2 | CallE (exp1, typs, exp2) -> diff --git a/src/compile.ml b/src/compile.ml index 6a7b0af10bb..9711a615bec 100644 --- a/src/compile.ml +++ b/src/compile.ml @@ -3076,7 +3076,7 @@ and compile_exp (env : E.t) exp = match exp.it with | ProjE (e1,n) -> compile_exp env e1 ^^ (* offset to tuple (an array) *) Array.load_n (Int32.of_int n) - | ArrayE es -> Array.lit env (List.map (compile_exp env) es) + | ArrayE (m, es) -> Array.lit env (List.map (compile_exp env) es) | ObjE ({ it = Type.Object _ (*sharing*); _}, name, fs) -> (* TBR - really the same for local and shared? *) let fs' = List.map (fun (f : Ir.exp_field) -> diff --git a/src/desugar.ml b/src/desugar.ml index afb752fc97b..61618f031d2 100644 --- a/src/desugar.ml +++ b/src/desugar.ml @@ -37,7 +37,7 @@ let | S.ObjE (s, i, es) -> I.ObjE (s, i, exp_fields es) | S.DotE (e, n) -> I.DotE (exp e, n) | S.AssignE (e1, e2) -> I.AssignE (exp e1, exp e2) - | S.ArrayE es -> I.ArrayE (exps es) + | S.ArrayE (m, es) -> I.ArrayE (m, exps es) | S.IdxE (e1, e2) -> I.IdxE (exp e1, exp e2) | S.CallE (e1, inst, e2) -> let cc = Value.call_conv_of_typ e1.Source.note.S.note_typ in diff --git a/src/effect.ml b/src/effect.ml index c70c8a9b438..e3ecfa202c2 100644 --- a/src/effect.ml +++ b/src/effect.ml @@ -50,7 +50,7 @@ let rec infer_effect_exp (exp:Syntax.exp) : T.eff = let t2 = effect_exp exp2 in max_eff t1 t2 | TupE exps - | ArrayE exps -> + | ArrayE (_, exps) -> let es = List.map effect_exp exps in List.fold_left max_eff Type.Triv es | BlockE decs -> diff --git a/src/freevars.ml b/src/freevars.ml index 83911d680ba..a38f2eace76 100644 --- a/src/freevars.ml +++ b/src/freevars.ml @@ -44,7 +44,7 @@ let rec exp e : f = match e.it with | ObjE (s, i, efs) -> close (exp_fields efs) // i.it | DotE (e, i) -> exp e | AssignE (e1, e2) -> exps [e1; e2] - | ArrayE es -> exps es + | ArrayE (m, es) -> exps es | IdxE (e1, e2) -> exps [e1; e2] | CallE (e1, ts, e2) -> exps [e1; e2] | BlockE ds -> close (decs ds) diff --git a/src/freevars_ir.ml b/src/freevars_ir.ml index 29d813c9d3d..b9228a6be17 100644 --- a/src/freevars_ir.ml +++ b/src/freevars_ir.ml @@ -70,7 +70,7 @@ let rec exp e : f = match e.it with | ObjE (s, i, efs) -> close (exp_fields efs) // i.it | DotE (e, i) -> exp e | AssignE (e1, e2) -> exps [e1; e2] - | ArrayE es -> exps es + | ArrayE (m, es) -> exps es | IdxE (e1, e2) -> exps [e1; e2] | CallE (_, e1, ts, e2) -> exps [e1; e2] | BlockE ds -> close (decs ds) diff --git a/src/interpret.ml b/src/interpret.ml index 25a914bf339..c0e8b96bb97 100644 --- a/src/interpret.ml +++ b/src/interpret.ml @@ -285,13 +285,12 @@ and interpret_exp_mut env exp (k : V.value V.cont) = V.as_mut v1 := v2; k V.unit ) ) - | ArrayE exps -> - let t = exp.note.note_typ in + | ArrayE (mut, exps) -> interpret_exps env exps [] (fun vs -> let vs' = - match t with - | T.Array (T.Mut _) -> List.map (fun v -> V.Mut (ref v)) vs - | _ -> vs + match mut.it with + | Var -> List.map (fun v -> V.Mut (ref v)) vs + | Const -> vs in k (V.Array (Array.of_list vs')) ) | IdxE (exp1, exp2) -> diff --git a/src/ir.ml b/src/ir.ml index 5d770b82768..969faab5bab 100644 --- a/src/ir.ml +++ b/src/ir.ml @@ -25,7 +25,7 @@ and exp' = | ObjE of Syntax.obj_sort * Syntax.id * exp_field list (* object *) | DotE of exp * Syntax.name (* object projection *) | AssignE of exp * exp (* assignment *) - | ArrayE of exp list (* array *) + | ArrayE of Syntax.mut * exp list (* array *) | IdxE of exp * exp (* array indexing *) | CallE of Value. call_conv * exp * Syntax.typ list * exp (* function call *) | BlockE of dec list (* block *) diff --git a/src/parser.mly b/src/parser.mly index 9f5259c89ba..80859f2206f 100644 --- a/src/parser.mly +++ b/src/parser.mly @@ -161,9 +161,6 @@ seplist1(X, SEP) : { fun sort sloc -> ("anon-" ^ sort ^ "-" ^ string_of_pos (at sloc).left) @@ at sloc } -%inline var : - | VAR { Var @@ at $sloc } - %inline var_opt : | (* empty *) { Const @@ no_region } | VAR { Var @@ at $sloc } @@ -200,14 +197,14 @@ typ_nullary : { TupT(ts) @@ at $sloc } | x=id tso=typ_args? { VarT(x, Lib.Option.get tso []) @@ at $sloc } + | LBRACKET m=var_opt t=typ RBRACKET + { ArrayT(m, t) @@ at $sloc } | tfs=typ_obj { ObjT(Type.Object Type.Local @@ at $sloc, tfs) @@ at $sloc } typ_post : | t=typ_nullary { t } - | t=typ_post LBRACKET RBRACKET - { ArrayT(Const @@ no_region, t) @@ at $sloc } | t=typ_post QUEST { OptT(t) @@ at $sloc } @@ -220,8 +217,6 @@ typ_pre : { AsyncT(t) @@ at $sloc } | LIKE t=typ_pre { LikeT(t) @@ at $sloc } - | mut=var t=typ_nullary LBRACKET RBRACKET - { ArrayT(mut, t) @@ at $sloc } | s=obj_sort tfs=typ_obj { let tfs' = if s.it = Type.Object Type.Local @@ -349,12 +344,14 @@ exp_nullary : then efs else List.map share_expfield efs in ObjE(s, xf anon $sloc, efs') @? at $sloc } + | PRIM s=TEXT + { PrimE(s) @? at $sloc } exp_post : | e=exp_nullary { e } - | LBRACKET es=seplist(exp, COMMA) RBRACKET - { ArrayE(es) @? at $sloc } + | LBRACKET m=var_opt es=seplist(exp_nonvar, COMMA) RBRACKET + { ArrayE(m, es) @? at $sloc } | e=exp_post QUEST { OptE(e) @? at $sloc } | e1=exp_post LBRACKET e2=exp RBRACKET @@ -399,8 +396,6 @@ exp_bin : exp_pre : | e=exp_bin { e } - | PRIM s=TEXT - { PrimE(s) @? at $sloc } | RETURN eo=exp_pre? { let e = Lib.Option.get eo (TupE([]) @? at $sloc) in RetE(e) @? at $sloc } @@ -445,10 +440,16 @@ exp_nondec : | FOR LPAR p=pat IN e1=exp RPAR e2=exp { ForE(p, e1, e2) @? at $sloc } -exp : +exp_nonvar : | e=exp_nondec { e } - | d=dec_nonexp + | d=dec_nonvar + { DecE(d) @? at $sloc } + +exp : + | e=exp_nonvar + { e } + | d=dec_var { DecE(d) @? at $sloc } @@ -518,7 +519,7 @@ return_typ_nullary : (* Declarations *) -dec_nonexp : +dec_var : | LET p=pat EQ e=exp { let p', e' = match p.it with @@ -531,6 +532,8 @@ dec_nonexp : | None -> e | Some t -> AnnotE (e, t) @? span t.at e.at in VarD(x, e') @? at $sloc } + +dec_nonvar : | s=shared_opt FUNC xf=id_opt fd=func_dec { (fd s (xf "func" $sloc)).it @? at $sloc } | TYPE x=id tps=typ_params_opt EQ t=typ @@ -544,8 +547,11 @@ dec_nonexp : in let id as tid = xf "class" $sloc in ClassD(xf "class" $sloc, tid, tps, s, p, x, efs') @? at $sloc } + dec : - | d=dec_nonexp + | d=dec_var + { d } + | d=dec_nonvar { d } | e=exp_nondec { ExpD e @? at $sloc } diff --git a/src/prelude.ml b/src/prelude.ml index fc5cc4a4281..c759ed6bbf2 100644 --- a/src/prelude.ml +++ b/src/prelude.ml @@ -18,9 +18,9 @@ type Text = prim "Text"; type Iter = {next : () -> T_?}; -func abs (x : Int) : Nat { ((prim "abs") : Int -> Nat) x }; +func abs(x : Int) : Nat { (prim "abs" : Int -> Nat) x }; -func ignore (_ : Any) {}; +func ignore(_ : Any) {}; class range(x : Nat, y : Nat) { private var i = x; @@ -32,49 +32,48 @@ class revrange(x : Nat, y : Nat) { next() : Nat? { if (i <= y) null else {i -= 1; i?} }; }; -func printInt (x : Int) { ((prim "printInt") : Int -> ()) x }; -func print (x : Text) { ((prim "print") : Text -> ()) x }; +func printInt(x : Int) { (prim "printInt" : Int -> ()) x }; +func print(x : Text) { (prim "print" : Text -> ()) x }; -/* This would be nicer as a objects, but lets do them as functions - until the compiler has a concept of “static objects” */ -func Array_init (len : Nat, x : T) : var T[] { - ((prim "Array.init") : (Nat, T) -> var T[]) (len, x) +// This would be nicer as a objects, but lets do them as functions +// until the compiler has a concept of “static objects” +func Array_init(len : Nat, x : T) : [var T] { + (prim "Array.init" : (Nat, T) -> [var T])(len, x) }; -func Array_tabulate (len : Nat, gen : Nat -> T) : T[] { - ((prim "Array.tabulate") : (Nat, Nat -> T) -> T[]) (len, gen) - +func Array_tabulate(len : Nat, gen : Nat -> T) : [T] { + (prim "Array.tabulate" : (Nat, Nat -> T) -> [T])(len, gen) }; type Cont = T -> () ; type Async = Cont -> (); -func @new_async():(Async,shared T->()) { - let empty = func k (t:T) = (); - var result : T ? = null; - var ks : T -> () = empty; - shared func fullfill(t:T):() { - switch(result) { - case null { - result := t?; - let ks_ = ks; - ks := empty; - ks_(t); - }; - case (t?) (assert(false)); - }; +func @new_async() : (Async, shared T -> ()) { + let empty = func k(t : T) = (); + var result : T? = null; + var ks : T -> () = empty; + shared func fullfill(t : T) { + switch(result) { + case null { + result := t?; + let ks_ = ks; + ks := empty; + ks_(t); + }; + case (t?) { assert(false) }; }; - func enqueue(k:Cont):() { - switch(result) { - case null { - let ks_ = ks; - ks := (func (t:T) {ks_(t);k(t);}); - }; - case (t?) (k(t)); - }; + }; + func enqueue(k : Cont) { + switch(result) { + case null { + let ks_ = ks; + ks := (func(t : T) { ks_(t); k(t) }); + }; + case (t?) { k(t) }; }; - (enqueue,fullfill) + }; + (enqueue, fullfill) }; |} @@ -87,19 +86,21 @@ let prim = function | "print" -> fun v k -> Printf.printf "%s%!" (as_text v); k unit | "printInt" -> fun v k -> Printf.printf "%d%!" (Int.to_int (as_int v)); k unit | "Array.init" -> fun v k -> - (match Value.as_tup v with - | [len; x] -> - k (Array (Array.init (Int.to_int (as_int len)) (fun _ -> Mut (ref x)))) - | _ -> assert false) + (match Value.as_tup v with + | [len; x] -> + k (Array (Array.init (Int.to_int (as_int len)) (fun _ -> Mut (ref x)))) + | _ -> assert false + ) | "Array.tabulate" -> fun v k -> - (match Value.as_tup v with - | [len; g] -> - let len_nat = Int.to_int (as_int len) in - let (_, _, g') = Value.as_func g in - let rec go prefix k i = - if i == len_nat - then k (Array (Array.of_list (prefix []))) - else g' (Int (Int.of_int i)) (fun x -> go (fun tl -> prefix (x::tl)) k (i + 1)) - in go (fun xs -> xs) k 0 - | _ -> assert false) + (match Value.as_tup v with + | [len; g] -> + let len_nat = Int.to_int (as_int len) in + let (_, _, g') = Value.as_func g in + let rec go prefix k i = + if i == len_nat + then k (Array (Array.of_list (prefix []))) + else g' (Int (Int.of_int i)) (fun x -> go (fun tl -> prefix (x::tl)) k (i + 1)) + in go (fun xs -> xs) k 0 + | _ -> assert false + ) | s -> raise (Invalid_argument ("Value.prim: " ^ s)) diff --git a/src/rename.ml b/src/rename.ml index dd912ba4686..2c888be79b0 100644 --- a/src/rename.ml +++ b/src/rename.ml @@ -36,7 +36,7 @@ and exp' rho e = match e with | ObjE (s, i, efs) -> ObjE (s, i, exp_fields rho efs) | DotE (e, i) -> DotE (exp rho e, i) | AssignE (e1, e2) -> AssignE (exp rho e1, exp rho e2) - | ArrayE es -> ArrayE (exps rho es) + | ArrayE (m, es) -> ArrayE (m, exps rho es) | IdxE (e1, e2) -> IdxE (exp rho e1, exp rho e2) | CallE (e1, ts, e2) -> CallE (exp rho e1, ts, exp rho e2) | BlockE ds -> BlockE (decs rho ds) diff --git a/src/syntax.ml b/src/syntax.ml index cb1b6132825..d2e4a68f06e 100644 --- a/src/syntax.ml +++ b/src/syntax.ml @@ -137,7 +137,7 @@ and exp' = | ObjE of obj_sort * id * exp_field list (* object *) | DotE of exp * name (* object projection *) | AssignE of exp * exp (* assignment *) - | ArrayE of exp list (* array *) + | ArrayE of mut * exp list (* array *) | IdxE of exp * exp (* array indexing *) | CallE of exp * typ list * exp (* function call *) | BlockE of dec list (* block *) diff --git a/src/type.ml b/src/type.ml index 1b68053880b..f6c1b1c8934 100644 --- a/src/type.ml +++ b/src/type.ml @@ -611,6 +611,10 @@ let rec string_of_typ_nullary vs = function sprintf "(%s%s)" (String.concat ", " (List.map (string_of_typ' vs) ts)) (if List.length ts = 1 then "," else "") + | Array (Mut t) -> + sprintf "[var %s]" (string_of_typ_nullary vs t) + | Array t -> + sprintf "[%s]" (string_of_typ_nullary vs t) | Obj (Object Local, fs) -> sprintf "{%s}" (String.concat "; " (List.map (string_of_field vs) fs)) | t -> sprintf "(%s)" (string_of_typ' vs t) @@ -636,10 +640,6 @@ and string_of_cod c vs ts = and string_of_typ' vs t = match t with - | Array (Mut t) -> - sprintf "var %s[]" (string_of_typ_nullary vs t) - | Array t -> - sprintf "%s[]" (string_of_typ_nullary vs t) | Func (s, c, [], ts1, ts2) -> sprintf "%s%s -> %s" (string_of_func_sort s) (string_of_dom vs ts1) diff --git a/src/typing.ml b/src/typing.ml index 4de6c4bd2eb..b76e73396a8 100644 --- a/src/typing.ml +++ b/src/typing.ml @@ -426,7 +426,7 @@ and infer_exp' env exp : T.typ = error env exp.at "expected mutable assignment target"; end; T.unit - | ArrayE exps -> + | ArrayE (mut, exps) -> let ts = List.map (infer_exp env) exps in let t1 = List.fold_left (T.lub env.cons) T.Non ts in if @@ -434,7 +434,7 @@ and infer_exp' env exp : T.typ = then warn env exp.at "this array has type %s because elements have inconsistent types" (T.string_of_typ (T.Array t1)); - T.Array t1 + T.Array (match mut.it with Const -> t1 | Var -> T.Mut t1) | IdxE (exp1, exp2) -> let t1 = infer_exp_promote env exp1 in (try @@ -641,7 +641,11 @@ and check_exp' env t exp = | ObjE (sort, id, fields), T.Obj (s, tfs) when s = sort.it -> let env' = if sort.it = T.Actor then { env with async = false } else env in ignore (check_obj env' s tfs id fields exp.at) - | ArrayE exps, T.Array t' -> + | ArrayE (mut, exps), T.Array t' -> + if (mut.it = Var) <> T.is_mut t' then + local_error env exp.at "%smutable array expression cannot produce expected type\n %s" + (if mut.it = Const then "im" else "") + (T.string_of_typ_expand env.cons (T.Array t')); List.iter (check_exp env (T.as_immut t')) exps | AsyncE exp1, T.Async t' -> let env' = {env with labs = T.Env.empty; rets = Some t'; async = true} in @@ -691,6 +695,7 @@ and check_case env t_pat t {it = {pat; exp}; _} = let ve = check_pat env t_pat pat in recover (check_exp (adjoin_vals env ve) t) exp + (* Patterns *) and gather_pat env ve0 pat : val_env = @@ -709,7 +714,7 @@ and gather_pat env ve0 pat : val_env = | OptP pat1 | AnnotP (pat1, _) -> go ve pat1 - in T.Env.adjoin ve0 (go T.Env.empty pat) + in T.Env.adjoin ve0 (go T.Env.empty pat) @@ -864,17 +869,18 @@ and infer_obj env s id fields : T.typ = and check_obj env s tfs id fields at : T.typ = let pre_ve = gather_exp_fields env id.it fields in - let pre_ve' = List.fold_left (fun ve {T.name; typ = t} -> + let pre_ve' = List.fold_left + (fun ve {T.name; typ = t} -> if not (T.Env.mem name ve) then - local_error env at "%s expression without field %s cannot produce expected type\n %s" + error env at "%s expression without field %s cannot produce expected type\n %s" (if s = T.Actor then "actor" else "object") name (T.string_of_typ_expand env.cons t); T.Env.add name t ve ) pre_ve tfs in let pre_env = adjoin_vals {env with pre = true} pre_ve' in - let tfs, ve = infer_exp_fields pre_env s id.it T.Pre fields in - let t = T.Obj (s, tfs) in + let tfs', ve = infer_exp_fields pre_env s id.it T.Pre fields in + let t = T.Obj (s, tfs') in let env' = adjoin_vals (add_val env id.it t) ve in ignore (infer_exp_fields env' s id.it t fields); t @@ -916,8 +922,15 @@ and infer_exp_field env s (tfs, ve) field : T.field list * val_env = infer_mut mut (infer_exp (adjoin_vals env ve) exp) | t -> (* When checking object in analysis mode *) - if not env.pre then + if not env.pre then begin check_exp (adjoin_vals env ve) (T.as_immut t) exp; + if (mut.it = Var) <> T.is_mut t then + local_error env field.at + "%smutable field %s cannot produce expected %smutable field of type\n %s" + (if mut.it = Var then "" else "im") id.it + (if T.is_mut t then "" else "im") + (T.string_of_typ_expand env.cons (T.as_immut t)) + end; t in if not env.pre then begin diff --git a/test/fail/const-var-array.as b/test/fail/const-var-array.as new file mode 100644 index 00000000000..d8f2705e2ad --- /dev/null +++ b/test/fail/const-var-array.as @@ -0,0 +1 @@ +let a : [Nat] = [var]; diff --git a/test/fail/const-var-field.as b/test/fail/const-var-field.as new file mode 100644 index 00000000000..f6db662c711 --- /dev/null +++ b/test/fail/const-var-field.as @@ -0,0 +1 @@ +let o : {x : Nat} = new {var x = 0}; diff --git a/test/fail/ok/const-var-array.tc.ok b/test/fail/ok/const-var-array.tc.ok new file mode 100644 index 00000000000..74f605301e2 --- /dev/null +++ b/test/fail/ok/const-var-array.tc.ok @@ -0,0 +1,2 @@ +const-var-array.as:1.17-1.22: type error, mutable array expression cannot produce expected type + [Nat] diff --git a/test/fail/ok/const-var-field.tc.ok b/test/fail/ok/const-var-field.tc.ok new file mode 100644 index 00000000000..7741ec54473 --- /dev/null +++ b/test/fail/ok/const-var-field.tc.ok @@ -0,0 +1,2 @@ +const-var-field.as:1.26-1.35: type error, mutable field x cannot produce expected immutable field of type + Nat diff --git a/test/fail/ok/var-const-array.tc.ok b/test/fail/ok/var-const-array.tc.ok new file mode 100644 index 00000000000..79453817fc9 --- /dev/null +++ b/test/fail/ok/var-const-array.tc.ok @@ -0,0 +1,2 @@ +var-const-array.as:1.21-1.23: type error, immutable array expression cannot produce expected type + [var Nat] diff --git a/test/fail/ok/var-const-field.tc.ok b/test/fail/ok/var-const-field.tc.ok new file mode 100644 index 00000000000..733fbc9d525 --- /dev/null +++ b/test/fail/ok/var-const-field.tc.ok @@ -0,0 +1,2 @@ +var-const-field.as:1.30-1.35: type error, immutable field x cannot produce expected mutable field of type + Nat diff --git a/test/fail/var-const-array.as b/test/fail/var-const-array.as new file mode 100644 index 00000000000..09ac29fbcd5 --- /dev/null +++ b/test/fail/var-const-array.as @@ -0,0 +1 @@ +let a : [var Nat] = []; diff --git a/test/fail/var-const-field.as b/test/fail/var-const-field.as new file mode 100644 index 00000000000..69c9fa88b49 --- /dev/null +++ b/test/fail/var-const-field.as @@ -0,0 +1 @@ +let o : {var x : Nat} = new {x = 0}; diff --git a/test/run-dfinity/data-params.as b/test/run-dfinity/data-params.as index 1501674955e..bb67f2c5723 100644 --- a/test/run-dfinity/data-params.as +++ b/test/run-dfinity/data-params.as @@ -15,7 +15,7 @@ let a = actor { printInt(c); print("\n"); }; - incarray(a : Nat[]) : () { + incarray(a : [Nat]) : () { for (i in a.vals()) { c += i }; printInt(c); print("\n"); diff --git a/test/run/array.as b/test/run/array.as index a794401aed8..aa90d834a8e 100644 --- a/test/run/array.as +++ b/test/run/array.as @@ -1,4 +1,5 @@ -let a : Nat[] = [1, 2, 42]; +let a = [1, 2, 42]; +let aa = a : [Nat]; assert(a.len() == 3); @@ -10,7 +11,8 @@ assert(a.get(0) == 1); assert(a.get(1) == 2); assert(a.get(2) == 42); -let b : var Nat[] = [2, 3, 23]; +let b = [var 2, 3, 23]; +let bb = b : [var Nat]; assert(b.len() == 3); @@ -38,7 +40,7 @@ func opt_eq(x : Nat?, y : Nat) : Bool { case (i?) { i == y } } }; -var emptyit = ([]: Nat[]).keys(); +var emptyit = ([] : [Nat]).keys(); switch (emptyit.next()) { case null {}; case _ {assert false} }; var it = a.keys(); diff --git a/test/run/coverage.as b/test/run/coverage.as index b96682d84df..06bca143ce7 100644 --- a/test/run/coverage.as +++ b/test/run/coverage.as @@ -6,9 +6,9 @@ func f() { let (5 or _) = 0; let (_ or 6) = 0; let (_ or _) = 0; - let b? = 0; - let _? = 0; - let 9? = 0; + let b? = 0?; + let _? = 0?; + let 9? = 0?; func(_ : Nat) {}; func(x : Nat) {}; @@ -21,17 +21,17 @@ func f() { switch 0 { case _ {} }; switch 0 { case x {} }; switch 0 { case 5 {} }; - switch 0 { case 5 {} case 5 {} }; - switch 0 { case 5 {} case _ {} }; - switch 0 { case 5 {} case x {} }; - switch 0 { case _ {} case 6 {} }; - switch 0 { case _ {} case x {} }; - switch 0 { case x {} case _ {} }; - switch 0 { case x {} case x {} }; - switch 0 { case _ {} case _ {} }; - switch 0 { case (5 or 6) {} case (7 or 6) {} }; - switch (0, 0) { case (_, _) {} case (_, 6) {} }; - switch (0, 0) { case (_, (6 or _)) {} case _ {} }; - switch (0, 0) { case (0, _) {} case (_, 0) {} }; - switch (0, 0) { case (0, _) {} case (_, 0) {} case _ {} }; + switch 0 { case 5 {}; case 5 {} }; + switch 0 { case 5 {}; case _ {} }; + switch 0 { case 5 {}; case x {} }; + switch 0 { case _ {}; case 6 {} }; + switch 0 { case _ {}; case x {} }; + switch 0 { case x {}; case _ {} }; + switch 0 { case x {}; case x {} }; + switch 0 { case _ {}; case _ {} }; + switch 0 { case (5 or 6) {}; case (7 or 6) {} }; + switch (0, 0) { case (_, _) {}; case (_, 6) {} }; + switch (0, 0) { case (_, (6 or _)) {}; case _ {} }; + switch (0, 0) { case (0, _) {}; case (_, 0) {} }; + switch (0, 0) { case (0, _) {}; case (_, 0) {}; case _ {} }; }; diff --git a/test/run/fib.as b/test/run/fib.as index 52d1aab4447..44c98a9cb57 100644 --- a/test/run/fib.as +++ b/test/run/fib.as @@ -1,6 +1,6 @@ -let a : var Nat[] = [0,1,0,0,0,0,0,0,0,0,0]; +let a = [var 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]; -var i : Nat = 1; +var i = 1; while (i < 10) { i += 1; a[i] := a[i-1] + a[i-2]; @@ -18,4 +18,3 @@ assert (a[7] == 13); assert (a[8] == 21); assert (a[9] == 34); assert (a[10] == 55); - diff --git a/test/run/hoare.as b/test/run/hoare.as index c97c019c5a3..b8e5347716e 100644 --- a/test/run/hoare.as +++ b/test/run/hoare.as @@ -1,11 +1,11 @@ -func swap(a : var Int[], i : Nat, j : Nat) { +func swap(a : [var Int], i : Nat, j : Nat) { let temp = a[i]; a[i] := a[j]; a[j] := temp; }; -func partition(a : var Int[], lo : Nat, hi : Nat) : Nat { +func partition(a : [var Int], lo : Nat, hi : Nat) : Nat { let pivot = a[lo]; var i : Nat = lo; var j : Nat = hi; @@ -18,7 +18,7 @@ func partition(a : var Int[], lo : Nat, hi : Nat) : Nat { }; }; -func quicksort(a : var Int[], lo : Nat, hi : Nat) { +func quicksort(a : [var Int], lo : Nat, hi : Nat) { if (lo < hi) { let p = partition(a, lo, hi); quicksort(a, lo, p); @@ -26,7 +26,7 @@ func quicksort(a : var Int[], lo : Nat, hi : Nat) { }; }; -let a : var Int[] = [8, 3, 9, 5, 2]; +let a : [var Int] = [var 8, 3, 9, 5, 2]; quicksort(a, 0, 4); diff --git a/test/run/issue83.as b/test/run/issue83.as index 3044025965b..7762dbb951b 100644 --- a/test/run/issue83.as +++ b/test/run/issue83.as @@ -1,24 +1,24 @@ -let Array_thaw = func (xs : A[]) : var A[] { +func Array_thaw(xs : [A]) : [var A] { let xsLen = xs.len(); if (xsLen == 0) { - return []; + return [var]; }; let ys = Array_init(xsLen, xs[0]); for (i in ys.keys()) { - ys[i] := xs[i]; // Comment out this line to prevent the error + ys[i] := xs[i]; }; ys; }; -(func () { - let xs : Int[] = [ 1, 2, 3 ]; +{ + let xs : [Int] = [1, 2, 3]; let actual = Array_thaw(xs); - let expected : var Int[] = [ 1, 2, 3 ]; + let expected : [var Int] = [var 1, 2, 3]; assert(actual.len() == expected.len()); for (i in actual.keys()) { assert(actual[i] == expected[i]); }; -})(); +}; diff --git a/test/run/iter-null.as b/test/run/iter-null.as index dda62c6a2d2..f4aed3e3012 100644 --- a/test/run/iter-null.as +++ b/test/run/iter-null.as @@ -1,9 +1,9 @@ -let a : Nat?[] = [null, 1?]; +let a : [Nat?] = [null, 1?]; var x : Nat? = 0?; for (i in a.vals()) { x := i }; -/* This tests that the iterator does proceed past the null element */ + +// This tests that the iterator does proceed past the null element switch x { case null (); case (y?) {assert (y == 1) }; }; - diff --git a/test/run/nested-lexpr.as b/test/run/nested-lexpr.as index 8092498d7fd..d7e588733fd 100644 --- a/test/run/nested-lexpr.as +++ b/test/run/nested-lexpr.as @@ -1,9 +1,9 @@ -let a : (var Int[])[] = [[1]]; +let a : [[var Int]] = [[var 1]]; assert (a[0][0] == 1); a[0][0] := 2; assert (a[0][0] == 2); -let b : ({var x : Int})[] = [new {x = 1}]; +let b : [{var x : Int}] = [new {var x = 1}]; assert (b[0].x == 1); b[0].x := 2; assert (b[0].x == 2); diff --git a/test/run/ok/coverage.run-low.ok b/test/run/ok/coverage.run-low.ok new file mode 100644 index 00000000000..2d5667ab33d --- /dev/null +++ b/test/run/ok/coverage.run-low.ok @@ -0,0 +1,26 @@ +coverage.as:5.13-5.14: warning, this pattern is never matched +coverage.as:7.13-7.14: warning, this pattern is never matched +coverage.as:8.13-8.14: warning, this pattern is never matched +coverage.as:16.13-16.14: warning, this pattern is never matched +coverage.as:18.13-18.14: warning, this pattern is never matched +coverage.as:19.14-19.15: warning, this pattern is never matched +coverage.as:24.25-24.34: warning, this case is never reached +coverage.as:27.25-27.34: warning, this case is never reached +coverage.as:28.25-28.34: warning, this case is never reached +coverage.as:29.25-29.34: warning, this case is never reached +coverage.as:30.25-30.34: warning, this case is never reached +coverage.as:31.25-31.34: warning, this case is never reached +coverage.as:32.43-32.44: warning, this pattern is never matched +coverage.as:33.35-33.49: warning, this case is never reached +coverage.as:34.42-34.51: warning, this case is never reached +coverage.as:4.7-4.8: warning, this pattern does not cover all possible values +coverage.as:5.8-5.14: warning, this pattern does not cover all possible values +coverage.as:9.7-9.9: warning, this pattern does not cover all possible values +coverage.as:10.7-10.9: warning, this pattern does not cover all possible values +coverage.as:11.7-11.9: warning, this pattern does not cover all possible values +coverage.as:15.8-15.9: warning, this pattern does not cover all possible values +coverage.as:16.8-16.14: warning, this pattern does not cover all possible values +coverage.as:23.3-23.25: warning, the cases in this switch do not cover all possible values +coverage.as:24.3-24.36: warning, the cases in this switch do not cover all possible values +coverage.as:32.3-32.50: warning, the cases in this switch do not cover all possible values +coverage.as:35.3-35.51: warning, the cases in this switch do not cover all possible values diff --git a/test/run/ok/coverage.run.ok b/test/run/ok/coverage.run.ok new file mode 100644 index 00000000000..2d5667ab33d --- /dev/null +++ b/test/run/ok/coverage.run.ok @@ -0,0 +1,26 @@ +coverage.as:5.13-5.14: warning, this pattern is never matched +coverage.as:7.13-7.14: warning, this pattern is never matched +coverage.as:8.13-8.14: warning, this pattern is never matched +coverage.as:16.13-16.14: warning, this pattern is never matched +coverage.as:18.13-18.14: warning, this pattern is never matched +coverage.as:19.14-19.15: warning, this pattern is never matched +coverage.as:24.25-24.34: warning, this case is never reached +coverage.as:27.25-27.34: warning, this case is never reached +coverage.as:28.25-28.34: warning, this case is never reached +coverage.as:29.25-29.34: warning, this case is never reached +coverage.as:30.25-30.34: warning, this case is never reached +coverage.as:31.25-31.34: warning, this case is never reached +coverage.as:32.43-32.44: warning, this pattern is never matched +coverage.as:33.35-33.49: warning, this case is never reached +coverage.as:34.42-34.51: warning, this case is never reached +coverage.as:4.7-4.8: warning, this pattern does not cover all possible values +coverage.as:5.8-5.14: warning, this pattern does not cover all possible values +coverage.as:9.7-9.9: warning, this pattern does not cover all possible values +coverage.as:10.7-10.9: warning, this pattern does not cover all possible values +coverage.as:11.7-11.9: warning, this pattern does not cover all possible values +coverage.as:15.8-15.9: warning, this pattern does not cover all possible values +coverage.as:16.8-16.14: warning, this pattern does not cover all possible values +coverage.as:23.3-23.25: warning, the cases in this switch do not cover all possible values +coverage.as:24.3-24.36: warning, the cases in this switch do not cover all possible values +coverage.as:32.3-32.50: warning, the cases in this switch do not cover all possible values +coverage.as:35.3-35.51: warning, the cases in this switch do not cover all possible values diff --git a/test/run/ok/coverage.tc.ok b/test/run/ok/coverage.tc.ok index d4a2a2eae87..2d5667ab33d 100644 --- a/test/run/ok/coverage.tc.ok +++ b/test/run/ok/coverage.tc.ok @@ -1 +1,26 @@ -coverage.as:24.24-24.28: syntax error, unexpected token +coverage.as:5.13-5.14: warning, this pattern is never matched +coverage.as:7.13-7.14: warning, this pattern is never matched +coverage.as:8.13-8.14: warning, this pattern is never matched +coverage.as:16.13-16.14: warning, this pattern is never matched +coverage.as:18.13-18.14: warning, this pattern is never matched +coverage.as:19.14-19.15: warning, this pattern is never matched +coverage.as:24.25-24.34: warning, this case is never reached +coverage.as:27.25-27.34: warning, this case is never reached +coverage.as:28.25-28.34: warning, this case is never reached +coverage.as:29.25-29.34: warning, this case is never reached +coverage.as:30.25-30.34: warning, this case is never reached +coverage.as:31.25-31.34: warning, this case is never reached +coverage.as:32.43-32.44: warning, this pattern is never matched +coverage.as:33.35-33.49: warning, this case is never reached +coverage.as:34.42-34.51: warning, this case is never reached +coverage.as:4.7-4.8: warning, this pattern does not cover all possible values +coverage.as:5.8-5.14: warning, this pattern does not cover all possible values +coverage.as:9.7-9.9: warning, this pattern does not cover all possible values +coverage.as:10.7-10.9: warning, this pattern does not cover all possible values +coverage.as:11.7-11.9: warning, this pattern does not cover all possible values +coverage.as:15.8-15.9: warning, this pattern does not cover all possible values +coverage.as:16.8-16.14: warning, this pattern does not cover all possible values +coverage.as:23.3-23.25: warning, the cases in this switch do not cover all possible values +coverage.as:24.3-24.36: warning, the cases in this switch do not cover all possible values +coverage.as:32.3-32.50: warning, the cases in this switch do not cover all possible values +coverage.as:35.3-35.51: warning, the cases in this switch do not cover all possible values diff --git a/test/run/ok/coverage.wasm.stderr.ok b/test/run/ok/coverage.wasm.stderr.ok new file mode 100644 index 00000000000..2d5667ab33d --- /dev/null +++ b/test/run/ok/coverage.wasm.stderr.ok @@ -0,0 +1,26 @@ +coverage.as:5.13-5.14: warning, this pattern is never matched +coverage.as:7.13-7.14: warning, this pattern is never matched +coverage.as:8.13-8.14: warning, this pattern is never matched +coverage.as:16.13-16.14: warning, this pattern is never matched +coverage.as:18.13-18.14: warning, this pattern is never matched +coverage.as:19.14-19.15: warning, this pattern is never matched +coverage.as:24.25-24.34: warning, this case is never reached +coverage.as:27.25-27.34: warning, this case is never reached +coverage.as:28.25-28.34: warning, this case is never reached +coverage.as:29.25-29.34: warning, this case is never reached +coverage.as:30.25-30.34: warning, this case is never reached +coverage.as:31.25-31.34: warning, this case is never reached +coverage.as:32.43-32.44: warning, this pattern is never matched +coverage.as:33.35-33.49: warning, this case is never reached +coverage.as:34.42-34.51: warning, this case is never reached +coverage.as:4.7-4.8: warning, this pattern does not cover all possible values +coverage.as:5.8-5.14: warning, this pattern does not cover all possible values +coverage.as:9.7-9.9: warning, this pattern does not cover all possible values +coverage.as:10.7-10.9: warning, this pattern does not cover all possible values +coverage.as:11.7-11.9: warning, this pattern does not cover all possible values +coverage.as:15.8-15.9: warning, this pattern does not cover all possible values +coverage.as:16.8-16.14: warning, this pattern does not cover all possible values +coverage.as:23.3-23.25: warning, the cases in this switch do not cover all possible values +coverage.as:24.3-24.36: warning, the cases in this switch do not cover all possible values +coverage.as:32.3-32.50: warning, the cases in this switch do not cover all possible values +coverage.as:35.3-35.51: warning, the cases in this switch do not cover all possible values diff --git a/test/run/ok/nested-lexpr.run-low.ok b/test/run/ok/nested-lexpr.run-low.ok deleted file mode 100644 index 40abfea241f..00000000000 --- a/test/run/ok/nested-lexpr.run-low.ok +++ /dev/null @@ -1,15 +0,0 @@ -nested-lexpr.as:8.11-8.12: fatal error, Invalid_argument("Value.as_mut") - -Last environment: -@new_async = func -Array_init = func -Array_tabulate = func -a = [[2]] -abs = func -b = [{x = 1}] -ignore = func -print = func -printInt = func -range = class -revrange = class - diff --git a/test/run/ok/nested-lexpr.run.ok b/test/run/ok/nested-lexpr.run.ok deleted file mode 100644 index 40abfea241f..00000000000 --- a/test/run/ok/nested-lexpr.run.ok +++ /dev/null @@ -1,15 +0,0 @@ -nested-lexpr.as:8.11-8.12: fatal error, Invalid_argument("Value.as_mut") - -Last environment: -@new_async = func -Array_init = func -Array_tabulate = func -a = [[2]] -abs = func -b = [{x = 1}] -ignore = func -print = func -printInt = func -range = class -revrange = class - diff --git a/test/run/quicksort.as b/test/run/quicksort.as index 6843058aa00..96412a19a3d 100644 --- a/test/run/quicksort.as +++ b/test/run/quicksort.as @@ -1,5 +1,5 @@ class QS(cmp : (T, T) -> Int) { - quicksort(a : var T[], lo : Nat, hi : Nat) { + quicksort(a : [var T], lo : Nat, hi : Nat) { if (lo < hi) { let p = partition(a, lo, hi); quicksort(a, lo, p); @@ -7,7 +7,7 @@ class QS(cmp : (T, T) -> Int) { } }; - private swap(a : var T[], i : Nat, j : Nat) { + private swap(a : [var T], i : Nat, j : Nat) { let temp = a[i]; a[i] := a[j]; a[j] := temp; @@ -15,8 +15,8 @@ class QS(cmp : (T, T) -> Int) { private trace(v : T) {}; - private partition(a : var T[], lo : Nat, hi : Nat) : Nat { - trace(a); + private partition(a : [var T], lo : Nat, hi : Nat) : Nat { + trace<[var T]>(a); let pivot = a[lo]; var i = lo; var j = hi; @@ -41,7 +41,7 @@ func cmpi(i : Int, j : Int) : Int = i - j; let qs = QS(cmpi); -let a : var Int[] = [8, 3, 9, 5, 2]; +let a : [var Int] = [var 8, 3, 9, 5, 2]; qs.quicksort(a, 0, 4);