diff --git a/src/arr/compiler/type-check.arr b/src/arr/compiler/type-check.arr index 5e57549f7e..67cf8ec430 100644 --- a/src/arr/compiler/type-check.arr +++ b/src/arr/compiler/type-check.arr @@ -1858,8 +1858,8 @@ end fun synthesis-extend(update-loc :: Loc, obj :: Expr, obj-type :: Type, fields :: List, context :: Context) -> TypingResult: collect-members(fields, false, context).typing-bind(lam(new-members, shadow context): - instantiate-object-type(obj-type, context).typing-bind(lam(shadow obj-type, shadow context): - cases(Type) obj-type: + instantiate-object-type(obj-type, context).typing-bind(lam(instantiated-obj-type, shadow context): + cases(Type) instantiated-obj-type: | t-record(t-fields, _, inferred) => final-fields = new-members.fold-keys(lam(key, final-fields): final-fields.set(key, new-members.get-value(key)) @@ -1868,7 +1868,10 @@ fun synthesis-extend(update-loc :: Loc, obj :: Expr, obj-type :: Type, fields :: | t-existential(_, l, _) => typing-error([list: C.unable-to-infer(l)]) | else => - typing-error([list: C.incorrect-type-expression(tostring(obj-type), obj-type.l, "an object type", update-loc, obj)]) + shadow context = new-members.fold-keys(lam(key, shadow context): + context.add-field-constraint(instantiated-obj-type, key, new-members.get-value(key)) + end, context) + typing-result(A.s-extend(update-loc, obj, fields), obj-type, context) end end) end) @@ -1876,13 +1879,13 @@ end fun synthesis-update(update-loc :: Loc, obj :: Expr, obj-type :: Type, fields :: List, context :: Context) -> TypingResult: collect-members(fields, false, context).typing-bind(lam(new-members, shadow context): - instantiate-object-type(obj-type, context).typing-bind(lam(shadow obj-type, shadow context): + instantiate-object-type(obj-type, context).typing-bind(lam(instantiated-obj-type, shadow context): cases(Type) obj-type: | t-record(t-fields, _, inferred) => foldr-fold-result(lam(key, shadow context, final-fields): cases(Option) t-fields.get(key): | none => - fold-errors([list: C.object-missing-field(key, tostring(obj-type), obj-type.l, update-loc)]) + fold-errors([list: C.object-missing-field(key, tostring(instantiated-obj-type), instantiated-obj-type.l, update-loc)]) | some(old-type) => cases(Type) old-type: | t-ref(onto, l, ref-inferred) => @@ -1898,7 +1901,11 @@ fun synthesis-update(update-loc :: Loc, obj :: Expr, obj-type :: Type, fields :: | t-existential(_, l, _) => typing-error([list: C.unable-to-infer(l)]) | else => - typing-error([list: C.incorrect-type-expression(tostring(obj-type), obj-type.l, "an object type", update-loc, obj)]) + shadow context = new-members.fold-keys(lam(key, shadow context): + member-type = new-members.get-value(key) + context.add-field-constraint(instantiated-obj-type, key, t-ref(member-type, member-type.l, false)) + end, context) + typing-result(A.s-update(update-loc, obj, fields), obj-type, context) end end) end) diff --git a/tests/type-check/bad/data-as-object-extend-missing.arr b/tests/type-check/bad/data-as-object-extend-missing.arr new file mode 100644 index 0000000000..bcfcbd4b69 --- /dev/null +++ b/tests/type-check/bad/data-as-object-extend-missing.arr @@ -0,0 +1,6 @@ +data Foo: + | bar(a :: Number, ref b :: String) +end + +# bar(1, "a") does not have a field c +bar(1, "a").{c: "a"} \ No newline at end of file diff --git a/tests/type-check/bad/data-as-object-extend-ref.arr b/tests/type-check/bad/data-as-object-extend-ref.arr new file mode 100644 index 0000000000..d8ac0068ce --- /dev/null +++ b/tests/type-check/bad/data-as-object-extend-ref.arr @@ -0,0 +1,6 @@ +data Foo: + | bar(a :: Number, ref b :: String) +end + +# bar(1, "a").b is a ref String while "a" is a String +bar(1, "a").{b: "a"} \ No newline at end of file diff --git a/tests/type-check/bad/data-as-object-extend-wrong-type.arr b/tests/type-check/bad/data-as-object-extend-wrong-type.arr new file mode 100644 index 0000000000..f7e2610c87 --- /dev/null +++ b/tests/type-check/bad/data-as-object-extend-wrong-type.arr @@ -0,0 +1,6 @@ +data Foo: + | bar(a :: Number, ref b :: String) +end + +# bar(1, "a").a has type Number not String +bar(1, "a").{a: "b"} \ No newline at end of file diff --git a/tests/type-check/bad/data-as-object-update-missing.arr b/tests/type-check/bad/data-as-object-update-missing.arr new file mode 100644 index 0000000000..60e96538b5 --- /dev/null +++ b/tests/type-check/bad/data-as-object-update-missing.arr @@ -0,0 +1,6 @@ +data Foo: + | bar(a :: Number, ref b :: String) +end + +# bar(1, "a") does not have a field c +bar(1, "a")!{c: 3} \ No newline at end of file diff --git a/tests/type-check/bad/data-as-object-update-non-ref.arr b/tests/type-check/bad/data-as-object-update-non-ref.arr new file mode 100644 index 0000000000..d21993beca --- /dev/null +++ b/tests/type-check/bad/data-as-object-update-non-ref.arr @@ -0,0 +1,6 @@ +data Foo: + | bar(a :: Number, ref b :: String) +end + +# bar(1, "a").a is a String but update is for refs +bar(1, "a")!{a: 3} \ No newline at end of file diff --git a/tests/type-check/bad/data-as-object-update-wrong.arr b/tests/type-check/bad/data-as-object-update-wrong.arr new file mode 100644 index 0000000000..d8c6f9eb89 --- /dev/null +++ b/tests/type-check/bad/data-as-object-update-wrong.arr @@ -0,0 +1,6 @@ +data Foo: + | bar(a :: Number, ref b :: String) +end + +# bar(1, "a").b has type String not Number +bar(1, "a")!{b: 3} \ No newline at end of file diff --git a/tests/type-check/good/data-as-object.arr b/tests/type-check/good/data-as-object.arr new file mode 100644 index 0000000000..59c86c67c9 --- /dev/null +++ b/tests/type-check/good/data-as-object.arr @@ -0,0 +1,6 @@ +data Foo: + | bar(a :: Number, ref b :: String) +end + +bar(1, "a").{a: 3} +bar(1, "b")!{b: "a"} \ No newline at end of file