From 4db20fbbee6aaafaa7ab7c1664bfd52deec771b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 24 Jan 2025 14:06:48 +0100 Subject: [PATCH 01/13] Adding tests of intersection types hiding and unhiding --- test/Base_Tests/src/Main.enso | 2 + .../Multi_Value_As_Type_Refinement_Spec.enso | 45 +++++++++++++++++++ .../src/Semantic/Multi_Value_Spec.enso | 1 - .../Type_Refinement/Hidden_Conversions.enso | 7 +++ .../src/Semantic/Type_Refinement/Types.enso | 12 +++++ 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso create mode 100644 test/Base_Tests/src/Semantic/Type_Refinement/Hidden_Conversions.enso create mode 100644 test/Base_Tests/src/Semantic/Type_Refinement/Types.enso diff --git a/test/Base_Tests/src/Main.enso b/test/Base_Tests/src/Main.enso index e22426567929..f356e1f86c56 100644 --- a/test/Base_Tests/src/Main.enso +++ b/test/Base_Tests/src/Main.enso @@ -10,6 +10,7 @@ import project.Semantic.Error_Spec import project.Semantic.Import_Loop.Spec as Import_Loop_Spec import project.Semantic.Meta_Spec import project.Semantic.Meta_Location_Spec +import project.Semantic.Multi_Value_As_Type_Refinement_Spec import project.Semantic.Multi_Value_Convert_Spec import project.Semantic.Multi_Value_Spec import project.Semantic.Names_Spec @@ -132,6 +133,7 @@ main filter=Nothing = Maybe_Spec.add_specs suite_builder Meta_Spec.add_specs suite_builder Meta_Location_Spec.add_specs suite_builder + Multi_Value_As_Type_Refinement_Spec.add_specs suite_builder Multi_Value_Convert_Spec.add_specs suite_builder Multi_Value_Spec.add_specs suite_builder Names_Spec.add_specs suite_builder diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso new file mode 100644 index 000000000000..02e7ae48933f --- /dev/null +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -0,0 +1,45 @@ +from Standard.Base import all +from Standard.Test import all +import Standard.Base.Errors.Common.Type_Error +import Standard.Base.Errors.Common.No_Such_Conversion +import Standard.Base.Errors.Common.No_Such_Method + +from project.Semantic.Type_Refinement.Types import A, B, make_a_and_b + +id_a (x : A) -> A = x +id_b (x : B) -> B = x + +add_specs suite_builder = + suite_builder.group "Multi Value as type refinement" group_builder-> + group_builder.specify "conversion A -> B should not be available" <| + just_a = A.A_Ctor 1 + Test.expect_panic Type_Error (just_a:B) + Test.expect_panic No_Such_Conversion (B.from just_a) + Test.expect_panic Type_Error (id_b just_a) + + group_builder.specify "make_a_and_b->A&B presents as both A and B" <| + ab = make_a_and_b + ab.is_a A . should_be_true + ab.is_a B . should_be_true + (ab:A).to_text . should_equal "(A_Ctor 1)" + (ab:B).to_text . should_equal "(B_Ctor (A_Ctor 1))" + (id_a ab).to_text . should_equal "(A_Ctor 1)" + (id_b ab).to_text . should_equal "(B_Ctor (A_Ctor 1))" + + group_builder.specify "after passing A&B value to a function expecting A argument, B becomes hidden" <| + ab = make_a_and_b + a2 = id_a ab + a2.is_a A . should_be_true + a2.is_a B . should_be_false + + # Passing a2 to a function expecting B fails because B part was hidden + Test.expect_panic Type_Error (id_b a2) + + # But it can be uncovered via explicit cast + (a2:B).to_text . should_equal "(B_Ctor (A_Ctor 1))" + (id_b (a2:B)).to_text . should_equal "(B_Ctor (A_Ctor 1))" + +main filter=Nothing = + suite = Test.build suite_builder-> + add_specs suite_builder + suite.run_with_filter filter diff --git a/test/Base_Tests/src/Semantic/Multi_Value_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_Spec.enso index 4cee0a32e6b2..b78a1be127f6 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_Spec.enso @@ -163,7 +163,6 @@ add_specs suite_builder = Test.expect_panic Type_Error <| _ = a_or_b : (A&B) - # This test is failing group_builder.specify "B --> (A|C) is possible" <| b = B.B 42 a_or_c = b : (A|C) diff --git a/test/Base_Tests/src/Semantic/Type_Refinement/Hidden_Conversions.enso b/test/Base_Tests/src/Semantic/Type_Refinement/Hidden_Conversions.enso new file mode 100644 index 000000000000..b4ea007353f6 --- /dev/null +++ b/test/Base_Tests/src/Semantic/Type_Refinement/Hidden_Conversions.enso @@ -0,0 +1,7 @@ +private + +from project.Semantic.Type_Refinement.Types import A, B + +## This conversion should only be imported in `Type_Refinement.Types` and nowhere else. +B.from (that : A) -> B = + B.B_Ctor that diff --git a/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso b/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso new file mode 100644 index 000000000000..0bb0c27187b6 --- /dev/null +++ b/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso @@ -0,0 +1,12 @@ +from project.Semantic.Type_Refinement.Hidden_Conversions import all + +type A + A_Ctor x + +type B + B_Ctor x + +make_a_and_b -> A & B = + a = A.A_Ctor 1 + # Relies on the hidden conversion + (a : A & B) From 07291e80d7691c997f3dbe7f43cb006faabcbe4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 24 Jan 2025 20:00:47 +0100 Subject: [PATCH 02/13] adding remaining tests from https://github.com/enso-org/enso/pull/11600#discussion_r1902112540, and some additions --- .../Multi_Value_As_Type_Refinement_Spec.enso | 116 ++++++++++++++++++ .../src/Semantic/Type_Refinement/Types.enso | 4 + 2 files changed, 120 insertions(+) diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso index 02e7ae48933f..15b23430a92b 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -1,3 +1,8 @@ +## This tests the usage of intersection types as refinement of a value's type. + These tests rely on a conversion A -> B that is not available in the scope, + so a type is A & B only if it was 'refined' somewhere else. Then we are + testing what happens to such instances after various casts, type checks etc. + from Standard.Base import all from Standard.Test import all import Standard.Base.Errors.Common.Type_Error @@ -9,6 +14,13 @@ from project.Semantic.Type_Refinement.Types import A, B, make_a_and_b id_a (x : A) -> A = x id_b (x : B) -> B = x +type C + C_Ctor x + + c_method self = "C method" + +C.from (that:B) = C.C_Ctor that + add_specs suite_builder = suite_builder.group "Multi Value as type refinement" group_builder-> group_builder.specify "conversion A -> B should not be available" <| @@ -21,6 +33,10 @@ add_specs suite_builder = ab = make_a_and_b ab.is_a A . should_be_true ab.is_a B . should_be_true + + ab.a_method . should_equal "A method" + ab.b_method . should_equal "B method" + (ab:A).to_text . should_equal "(A_Ctor 1)" (ab:B).to_text . should_equal "(B_Ctor (A_Ctor 1))" (id_a ab).to_text . should_equal "(A_Ctor 1)" @@ -32,6 +48,20 @@ add_specs suite_builder = a2.is_a A . should_be_true a2.is_a B . should_be_false + # Passing a2 to a function expecting B fails because B part was hidden + Test.expect_panic Type_Error (id_b a2) + Test.expect_panic No_Such_Method (a2.b_method) + + # But it can be uncovered via explicit cast + (a2:B).b_method . should_equal "B method" + (id_b (a2:B)).to_text . should_equal "(B_Ctor (A_Ctor 1))" + + group_builder.specify "after casting A&B to A, B part is again hidden" <| + ab = make_a_and_b + a2 = ab:A + a2.is_a A . should_be_true + a2.is_a B . should_be_false + # Passing a2 to a function expecting B fails because B part was hidden Test.expect_panic Type_Error (id_b a2) @@ -39,6 +69,92 @@ add_specs suite_builder = (a2:B).to_text . should_equal "(B_Ctor (A_Ctor 1))" (id_b (a2:B)).to_text . should_equal "(B_Ctor (A_Ctor 1))" + group_builder.specify "passing A&B to function expecting B, then re-casting to A" <| + ab = make_a_and_b + b2 = id_b ab + a2 = b2:A + a2.is_a A . should_be_true + a2.is_a B . should_be_false + + a2.a_method.should_equal "A method" + Test.expect_panic No_Such_Method (a2.b_method) + + group_builder.specify "passing A&B to function expecting A, then re-casting to B" <| + ab = make_a_and_b + a2 = id_a ab + b2 = a2:B + b2.is_a A . should_be_false + b2.is_a B . should_be_true + + Test.expect_panic No_Such_Method (b2.a_method) + b2.b_method.should_equal "B method" + + group_builder.specify "unpacking an intersection type via pattern matching" <| + ab = make_a_and_b + case ab of + ab_as_a : A -> + ab_as_a.a_method . should_equal "A method" + ab_as_a.is_a A . should_be_true + ab_as_a.is_a B . should_be_false + _ -> Test.fail "Expected ab to go to `: A` branch" + + case ab of + ab_as_b : B -> + ab_as_b.b_method . should_equal "B method" + ab_as_b.is_a A . should_be_false + ab_as_b.is_a B . should_be_true + _ -> Test.fail "Expected ab to go to `: B` branch" + + group_builder.specify "pattern matching does not apply conversions" <| + ab = make_a_and_b + r = case ab of + _ : C -> "matched C" + _ -> "was not C" + r.should_equal "was not C" + + group_builder.specify "using a conversion discards the multi-value structure and we 'start over'" <| + ab = make_a_and_b + c = ab:C + + c.is_a C . should_be_true + c.is_a A . should_be_false + c.is_a B . should_be_false + + # We cannot convert back to A/B as the mutli-value structure is lost + Test.expect_panic Type_Error (c:A) + Test.expect_panic Type_Error (c:B) + + group_builder.specify "conversion can keep the old types if they are listed explicitly in a cast expression" <| + ab = make_a_and_b + abc = ab:(A & B & C) + + abc.is_a A . should_be_true + abc.is_a B . should_be_true + abc.is_a C . should_be_true + + abc.a_method . should_equal "A method" + abc.b_method . should_equal "B method" + abc.c_method . should_equal "C method" + + # We hide A&B parts by casting to C + c = abc:C + c.is_a A . should_be_false + c.is_a B . should_be_false + c.is_a C . should_be_true + + Test.expect_panic No_Such_Method (c.a_method) + Test.expect_panic No_Such_Method (c.b_method) + c.c_method . should_equal "C method" + + # But because the structure was not lost, only hidden, we can cast back to A/B + (c:A).a_method . should_equal "A method" + (c:B).b_method . should_equal "B method" + + (c:A&B&C).a_method . should_equal "A method" + (c:A&B&C).b_method . should_equal "B method" + (c:A&B&C).c_method . should_equal "C method" + + main filter=Nothing = suite = Test.build suite_builder-> add_specs suite_builder diff --git a/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso b/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso index 0bb0c27187b6..104b4506aeaf 100644 --- a/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso +++ b/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso @@ -3,9 +3,13 @@ from project.Semantic.Type_Refinement.Hidden_Conversions import all type A A_Ctor x + a_method self = "A method" + type B B_Ctor x + b_method self = "B method" + make_a_and_b -> A & B = a = A.A_Ctor 1 # Relies on the hidden conversion From b864e7e8614a78c862f68c2e64930613aedf4b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 24 Jan 2025 20:04:58 +0100 Subject: [PATCH 03/13] add test related to https://github.com/enso-org/enso/issues/11827 --- .../Multi_Value_As_Type_Refinement_Spec.enso | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso index 15b23430a92b..5a9092aa46df 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -154,6 +154,19 @@ add_specs suite_builder = (c:A&B&C).b_method . should_equal "B method" (c:A&B&C).c_method . should_equal "C method" + group_builder.specify "default to_text should delegate to one of values" pending="TODO: https://github.com/enso-org/enso/issues/11827" <| + ab = make_a_and_b + ab.to_text . should_equal "(A_Ctor 1)" + + abc = ab:(A & B & C) + abc.to_text . should_equal "(A_Ctor 1)" + + c = abc:C + c.to_text . should_equal "(C_Ctor (B_Ctor (A_Ctor 1)))" + + (c:A).to_text . should_equal "(A_Ctor 1)" + (c:B).to_text . should_equal "(B_Ctor (A_Ctor 1))" + main filter=Nothing = suite = Test.build suite_builder-> From 2ef050dfb50495214fb459f1e84602f74300262d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 24 Jan 2025 20:06:41 +0100 Subject: [PATCH 04/13] structural matching test --- .../Multi_Value_As_Type_Refinement_Spec.enso | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso index 5a9092aa46df..6c2b3286c0b8 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -167,6 +167,20 @@ add_specs suite_builder = (c:A).to_text . should_equal "(A_Ctor 1)" (c:B).to_text . should_equal "(B_Ctor (A_Ctor 1))" + group_builder.specify "structural pattern matching should be able to match the primary type" <| + ab = make_a_and_b + r = case ab of + A.A_Ctor x -> "matched: "+x.to_text + _ -> "structural matching of A.A_Ctor failed" + r.should_equal "matched: 1" + + group_builder.specify "should structural matching match other types?" <| + ab = make_a_and_b + r = case ab of + B.B_Ctor x -> "matched: "+x.to_text + _ -> "structural matching of B.B_Ctor failed" + r.should_equal "matched: (A_Ctor 1)" + main filter=Nothing = suite = Test.build suite_builder-> From 1405da57d4021c3d6d09edce03814c22bf3ff44b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 24 Jan 2025 20:10:05 +0100 Subject: [PATCH 05/13] tests pending until https://github.com/enso-org/enso/issues/12142 --- .../src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso index 6c2b3286c0b8..2564bda4e334 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -167,14 +167,14 @@ add_specs suite_builder = (c:A).to_text . should_equal "(A_Ctor 1)" (c:B).to_text . should_equal "(B_Ctor (A_Ctor 1))" - group_builder.specify "structural pattern matching should be able to match the primary type" <| + group_builder.specify "structural pattern matching should be able to match the primary type" pending="TODO: https://github.com/enso-org/enso/issues/12142" <| ab = make_a_and_b r = case ab of A.A_Ctor x -> "matched: "+x.to_text _ -> "structural matching of A.A_Ctor failed" r.should_equal "matched: 1" - group_builder.specify "should structural matching match other types?" <| + group_builder.specify "should structural matching match other types?" pending="TODO: decide if we keep this test inhttps://github.com/enso-org/enso/issues/12142" <| ab = make_a_and_b r = case ab of B.B_Ctor x -> "matched: "+x.to_text From acfb79fce2a98474b8b3c21f5a941cfdc06a4c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 24 Jan 2025 20:19:02 +0100 Subject: [PATCH 06/13] more tests that check dispatch rules with self --- .../Multi_Value_As_Type_Refinement_Spec.enso | 76 +++++++++++++++++++ .../src/Semantic/Type_Refinement/Types.enso | 4 + 2 files changed, 80 insertions(+) diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso index 2564bda4e334..4886250a9291 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -8,6 +8,7 @@ from Standard.Test import all import Standard.Base.Errors.Common.Type_Error import Standard.Base.Errors.Common.No_Such_Conversion import Standard.Base.Errors.Common.No_Such_Method +import Standard.Base.Errors.Illegal_State.Illegal_State from project.Semantic.Type_Refinement.Types import A, B, make_a_and_b @@ -181,6 +182,81 @@ add_specs suite_builder = _ -> "structural matching of B.B_Ctor failed" r.should_equal "matched: (A_Ctor 1)" + group_builder.specify "calling a method on one of the types should not lose the intersection type" <| + ab = make_a_and_b + + ab.a_id_unchecked . is_a A . should_be_true + ab.a_id_unchecked . is_a B . should_be_true + ab.a_id_unchecked.a_method . should_equal "A method" + ab.a_id_unchecked.b_method . should_equal "B method" + + # Checked variant can hide the B part + ab.a_id . is_a A . should_be_true + ab.a_id . is_a B . should_be_false + # But it can be uncovered via explicit cast + b = (ab.a_id):B + b.is_a A . should_be_false + b.is_a B . should_be_true + + new_ab = (ab.a_id):A&B + new_ab.is_a A . should_be_true + new_ab.is_a B . should_be_true + new_ab.a_method . should_equal "A method" + new_ab.b_method . should_equal "B method" + + # The same should apply to the B part + ab.b_id_unchecked . is_a A . should_be_true + ab.b_id_unchecked . is_a B . should_be_true + ab.b_id_unchecked.a_method . should_equal "A method" + ab.b_id_unchecked.b_method . should_equal "B method" + + ab.b_id . is_a A . should_be_false + ab.b_id . is_a B . should_be_true + new_ab_2 = (ab.b_id):A&B + new_ab_2.is_a A . should_be_true + new_ab_2.is_a B . should_be_true + + group_builder.specify "calling `.catch` on an intersection type should not lose the refinements" <| + ab = make_a_and_b + r = ab.catch Any _->"catched" + r.is_a A . should_be_true + r.is_a B . should_be_true + r.a_method . should_equal "A method" + r.b_method . should_equal "B method" + + group_builder.specify "calling `.throw_on_warning` on an intersection type should not lose the refinements" <| + ab = make_a_and_b + r = ab.throw_on_warning + r.is_a A . should_be_true + r.is_a B . should_be_true + r.a_method . should_equal "A method" + r.b_method . should_equal "B method" + + group_builder.specify "attaching warnings to an intersection type should not lose the refinements" <| + ab = make_a_and_b + ab_with_warning = Warning.attach (Illegal_State.Error "my warning") ab + ab_with_warning.is_a A . should_be_true + ab_with_warning.is_a B . should_be_true + ab_with_warning.a_method . should_equal "A method" + ab_with_warning.b_method . should_equal "B method" + Problems.expect_only_warning Illegal_State ab_with_warning + + group_builder.specify "removing warnings from an intersection type should not lose the refinements" <| + ab = make_a_and_b + ab_with_warning = Warning.attach (Illegal_State.Error "my warning") ab + + ab_without_warning = ab_with_warning.remove_warnings + Problems.assume_no_problems ab_without_warning + ab_without_warning.is_a A . should_be_true + ab_without_warning.is_a B . should_be_true + ab_without_warning.a_method . should_equal "A method" + ab_without_warning.b_method . should_equal "B method" + + ab2 = ab.remove_warnings + ab2.is_a A . should_be_true + ab2.is_a B . should_be_true + ab2.a_method . should_equal "A method" + ab2.b_method . should_equal "B method" main filter=Nothing = suite = Test.build suite_builder-> diff --git a/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso b/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso index 104b4506aeaf..48a7bda7696f 100644 --- a/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso +++ b/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso @@ -4,11 +4,15 @@ type A A_Ctor x a_method self = "A method" + a_id_unchecked self = self + a_id self -> A = self type B B_Ctor x b_method self = "B method" + b_id_unchecked self = self + b_id self = self make_a_and_b -> A & B = a = A.A_Ctor 1 From 71c929076820ecdfe49dabf135fd003e6b5bffc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 24 Jan 2025 20:24:43 +0100 Subject: [PATCH 07/13] add a test --- .../src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso index 4886250a9291..dae8af99083a 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -258,6 +258,14 @@ add_specs suite_builder = ab2.a_method . should_equal "A method" ab2.b_method . should_equal "B method" + group_builder.specify "calling both throw_on_warning and catch should not lose the refinements" <| + ab = make_a_and_b + r = ab.throw_on_warning Illegal_State . catch Any _->"catched" + r.is_a A . should_be_true + r.is_a B . should_be_true + r.a_method . should_equal "A method" + r.b_method . should_equal "B method" + main filter=Nothing = suite = Test.build suite_builder-> add_specs suite_builder From bc6e2fc3e5a78723073692ea35535b47fe92633a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 24 Jan 2025 20:26:17 +0100 Subject: [PATCH 08/13] reorder test and mark failing as pending https://github.com/enso-org/enso/issues/12143 --- .../Multi_Value_As_Type_Refinement_Spec.enso | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso index dae8af99083a..9d2c309a1d57 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -182,14 +182,9 @@ add_specs suite_builder = _ -> "structural matching of B.B_Ctor failed" r.should_equal "matched: (A_Ctor 1)" - group_builder.specify "calling a method on one of the types should not lose the intersection type" <| + group_builder.specify "calling a method on one of the types should not lose the intersection type" pending="TODO: https://github.com/enso-org/enso/issues/12143" <| ab = make_a_and_b - ab.a_id_unchecked . is_a A . should_be_true - ab.a_id_unchecked . is_a B . should_be_true - ab.a_id_unchecked.a_method . should_equal "A method" - ab.a_id_unchecked.b_method . should_equal "B method" - # Checked variant can hide the B part ab.a_id . is_a A . should_be_true ab.a_id . is_a B . should_be_false @@ -204,17 +199,22 @@ add_specs suite_builder = new_ab.a_method . should_equal "A method" new_ab.b_method . should_equal "B method" - # The same should apply to the B part - ab.b_id_unchecked . is_a A . should_be_true - ab.b_id_unchecked . is_a B . should_be_true - ab.b_id_unchecked.a_method . should_equal "A method" - ab.b_id_unchecked.b_method . should_equal "B method" + # But unchecked variant should keep both types and not hide anything + ab.a_id_unchecked . is_a A . should_be_true + #ab.a_id_unchecked . is_a B . should_be_true + ab.a_id_unchecked.a_method . should_equal "A method" + #ab.a_id_unchecked.b_method . should_equal "B method" + # The same should apply to the B part ab.b_id . is_a A . should_be_false ab.b_id . is_a B . should_be_true new_ab_2 = (ab.b_id):A&B new_ab_2.is_a A . should_be_true new_ab_2.is_a B . should_be_true + ab.b_id_unchecked . is_a A . should_be_true + ab.b_id_unchecked . is_a B . should_be_true + ab.b_id_unchecked.a_method . should_equal "A method" + ab.b_id_unchecked.b_method . should_equal "B method" group_builder.specify "calling `.catch` on an intersection type should not lose the refinements" <| ab = make_a_and_b From ef55ee74f8df96460e60582fa081e1e8b3a2b58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 24 Jan 2025 23:30:03 +0100 Subject: [PATCH 09/13] add extra test cases for https://github.com/enso-org/enso/issues/12143 --- .../Multi_Value_As_Type_Refinement_Spec.enso | 70 ++++++++++++++++++- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso index 9d2c309a1d57..b41b3b3f6e59 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -201,9 +201,9 @@ add_specs suite_builder = # But unchecked variant should keep both types and not hide anything ab.a_id_unchecked . is_a A . should_be_true - #ab.a_id_unchecked . is_a B . should_be_true + ab.a_id_unchecked . is_a B . should_be_true ab.a_id_unchecked.a_method . should_equal "A method" - #ab.a_id_unchecked.b_method . should_equal "B method" + ab.a_id_unchecked.b_method . should_equal "B method" # The same should apply to the B part ab.b_id . is_a A . should_be_false @@ -258,7 +258,7 @@ add_specs suite_builder = ab2.a_method . should_equal "A method" ab2.b_method . should_equal "B method" - group_builder.specify "calling both throw_on_warning and catch should not lose the refinements" <| + group_builder.specify "calling both `throw_on_warning` and `catch` should not lose the refinements" <| ab = make_a_and_b r = ab.throw_on_warning Illegal_State . catch Any _->"catched" r.is_a A . should_be_true @@ -266,6 +266,70 @@ add_specs suite_builder = r.a_method . should_equal "A method" r.b_method . should_equal "B method" + group_builder.specify "calling `.catch` on an intersection type should not lose even the hidden refinements" <| + ab = make_a_and_b + x = ab:A + r = x.catch Any _->"catched" + r.a_method . should_equal "A method" + # After calling catch we should still be able to bring back the B part + (r:B).b_method . should_equal "B method" + + y = r:(A & B) + y.is_a A . should_be_true + y.is_a B . should_be_true + y.a_method . should_equal "A method" + y.b_method . should_equal "B method" + + group_builder.specify "calling `.throw_on_warning` on an intersection type should not lose even the hidden refinements" <| + ab = make_a_and_b + x = ab:A + r = x.throw_on_warning + + y = r:(A & B) + y.is_a A . should_be_true + y.is_a B . should_be_true + y.a_method . should_equal "A method" + y.b_method . should_equal "B method" + + group_builder.specify "attaching warnings to an intersection type should not lose even the hidden refinements" <| + ab = make_a_and_b + x = ab:A + x_with_warning = Warning.attach (Illegal_State.Error "my warning") x + + y = x_with_warning:(A & B) + y.is_a A . should_be_true + y.is_a B . should_be_true + y.a_method . should_equal "A method" + y.b_method . should_equal "B method" + Problems.expect_only_warning Illegal_State y + + group_builder.specify "removing warnings from an intersection type should not lose even the hidden refinements" <| + ab = make_a_and_b + x1 = Warning.attach (Illegal_State.Error "my warning") (ab:A) + x2 = (Warning.attach (Illegal_State.Error "my warning") ab):A + + x1_without_warning = x1.remove_warnings + x2_without_warning = x2.remove_warnings + + r1 = x1_without_warning:(A & B) + r2 = x2_without_warning:(A & B) + Problems.assume_no_problems r1 + r1.is_a A . should_be_true + r1.is_a B . should_be_true + r1.a_method . should_equal "A method" + r2.b_method . should_equal "B method" + Problems.assume_no_problems r2 + r2.is_a A . should_be_true + r2.is_a B . should_be_true + r2.a_method . should_equal "A method" + r2.b_method . should_equal "B method" + + r3 = (ab:A).remove_warnings:(A & B) + r3.is_a A . should_be_true + r3.is_a B . should_be_true + r3.a_method . should_equal "A method" + r3.b_method . should_equal "B method" + main filter=Nothing = suite = Test.build suite_builder-> add_specs suite_builder From 5d4c3e2cc5f981ad748174a2f79a1b9c00108fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 24 Jan 2025 23:31:53 +0100 Subject: [PATCH 10/13] mark https://github.com/enso-org/enso/issues/12143 tests as pending --- .../Semantic/Multi_Value_As_Type_Refinement_Spec.enso | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso index b41b3b3f6e59..208df69eeb9d 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -182,7 +182,8 @@ add_specs suite_builder = _ -> "structural matching of B.B_Ctor failed" r.should_equal "matched: (A_Ctor 1)" - group_builder.specify "calling a method on one of the types should not lose the intersection type" pending="TODO: https://github.com/enso-org/enso/issues/12143" <| + dispatch_pending="TODO: https://github.com/enso-org/enso/issues/12143" + group_builder.specify "calling a method on one of the types should not lose the intersection type" pending=dispatch_pending <| ab = make_a_and_b # Checked variant can hide the B part @@ -266,7 +267,7 @@ add_specs suite_builder = r.a_method . should_equal "A method" r.b_method . should_equal "B method" - group_builder.specify "calling `.catch` on an intersection type should not lose even the hidden refinements" <| + group_builder.specify "calling `.catch` on an intersection type should not lose even the hidden refinements" pending=dispatch_pending <| ab = make_a_and_b x = ab:A r = x.catch Any _->"catched" @@ -280,7 +281,7 @@ add_specs suite_builder = y.a_method . should_equal "A method" y.b_method . should_equal "B method" - group_builder.specify "calling `.throw_on_warning` on an intersection type should not lose even the hidden refinements" <| + group_builder.specify "calling `.throw_on_warning` on an intersection type should not lose even the hidden refinements" pending=dispatch_pending <| ab = make_a_and_b x = ab:A r = x.throw_on_warning @@ -291,7 +292,7 @@ add_specs suite_builder = y.a_method . should_equal "A method" y.b_method . should_equal "B method" - group_builder.specify "attaching warnings to an intersection type should not lose even the hidden refinements" <| + group_builder.specify "attaching warnings to an intersection type should not lose even the hidden refinements" pending=dispatch_pending <| ab = make_a_and_b x = ab:A x_with_warning = Warning.attach (Illegal_State.Error "my warning") x @@ -303,7 +304,7 @@ add_specs suite_builder = y.b_method . should_equal "B method" Problems.expect_only_warning Illegal_State y - group_builder.specify "removing warnings from an intersection type should not lose even the hidden refinements" <| + group_builder.specify "removing warnings from an intersection type should not lose even the hidden refinements" pending=dispatch_pending <| ab = make_a_and_b x1 = Warning.attach (Illegal_State.Error "my warning") (ab:A) x2 = (Warning.attach (Illegal_State.Error "my warning") ab):A From bbbfdf7d025c376e22f137cb45b5a7634f76ff31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Tue, 28 Jan 2025 10:47:51 +0100 Subject: [PATCH 11/13] Update test/Base_Tests/src/Semantic/Type_Refinement/Types.enso Co-authored-by: AdRiley --- test/Base_Tests/src/Semantic/Type_Refinement/Types.enso | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso b/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso index 48a7bda7696f..2abaa358c19b 100644 --- a/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso +++ b/test/Base_Tests/src/Semantic/Type_Refinement/Types.enso @@ -12,7 +12,7 @@ type B b_method self = "B method" b_id_unchecked self = self - b_id self = self + b_id self -> B = self make_a_and_b -> A & B = a = A.A_Ctor 1 From 82e4f3efe654d6309d717bed8e2de0f95420550b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Tue, 28 Jan 2025 12:07:41 +0100 Subject: [PATCH 12/13] Update test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso Co-authored-by: AdRiley --- .../src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso index 208df69eeb9d..83e8f4eeed97 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -89,7 +89,7 @@ add_specs suite_builder = Test.expect_panic No_Such_Method (b2.a_method) b2.b_method.should_equal "B method" - + Test.expect_panic Type_Error (b2:A) group_builder.specify "unpacking an intersection type via pattern matching" <| ab = make_a_and_b case ab of From 9470816e92b0cf776e6c38ddecd296d87ea1b180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Tue, 28 Jan 2025 12:10:59 +0100 Subject: [PATCH 13/13] fix --- .../src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso index 83e8f4eeed97..37bc78622039 100644 --- a/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso +++ b/test/Base_Tests/src/Semantic/Multi_Value_As_Type_Refinement_Spec.enso @@ -89,7 +89,9 @@ add_specs suite_builder = Test.expect_panic No_Such_Method (b2.a_method) b2.b_method.should_equal "B method" - Test.expect_panic Type_Error (b2:A) + # We can still explicitly cast back to A + (b2:A).a_method.should_equal "A method" + group_builder.specify "unpacking an intersection type via pattern matching" <| ab = make_a_and_b case ab of