diff --git a/CHANGELOG.md b/CHANGELOG.md index 3103d92..ff68fb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +### Validate explicitly typed TEXT object-field assignments + +- Added positive typecheck coverage for `SET player.name TEXT "Ada"` when the class declares `HAS name TEXT`. +- Added the fixture to the complete typecheck validation matrix and documented the explicit annotation form. + ### Diagnose missing class field names - `claro typecheck` now explains how to repair a bare `HAS` declaration instead of reporting a confusing missing type for an unnamed field. diff --git a/docs/ADVANCED_STATIC_TYPING.md b/docs/ADVANCED_STATIC_TYPING.md index 08fc2b1..cb3f51f 100644 --- a/docs/ADVANCED_STATIC_TYPING.md +++ b/docs/ADVANCED_STATIC_TYPING.md @@ -806,6 +806,21 @@ NEW Player player SET player.score 10 ``` +An assignment may repeat the field type when the explicit form is easier to read: + +```claro +CLASS Player + HAS name TEXT +END + +NEW Player player +SET player.name TEXT "Ada" +``` + +The explicit `TEXT` annotation must agree with the class field declaration. This +keeps typed field examples consistent with typed variable assignments while +still allowing the shorter `SET player.name "Ada"` form. + If a learner assigns the wrong value type directly to that known field: ```claro @@ -930,7 +945,7 @@ Output: Object player is not known yet. Create it with NEW ClassName player before setting player.score. ``` -Both sides of this narrow field foundation are covered by validation: `tests/typecheck_object_field_good.claro` checks that `SET player.score 10` is accepted for a `HAS score NUMBER` field, `tests/typecheck_object_field_text_good.claro` checks that `SET player.name "Ada"` is accepted for a `HAS name TEXT` field, `tests/typecheck_object_field_yesno_good.claro` checks that `SET player.ready YES` is accepted for a `HAS ready YESNO` field, `tests/typecheck_object_field_unknown_object_bad.claro` checks that `SET player.score 10` before `NEW Player player` reports the missing-object assignment diagnostic, `tests/typecheck_object_field_check_type_unknown_object_bad.claro` checks the matching missing-object `CHECK TYPE` diagnostic, and the remaining object-field fixtures cover known-field mismatches, unknown NUMBER/TEXT/YESNO fields, and unknown-field assignments whose value type is not inferable yet. +Both sides of this narrow field foundation are covered by validation: `tests/typecheck_object_field_good.claro` checks that `SET player.score 10` is accepted for a `HAS score NUMBER` field, `tests/typecheck_object_field_typed_good.claro` checks the explicit `NUMBER` annotation, `tests/typecheck_object_field_text_good.claro` checks that `SET player.name "Ada"` is accepted for a `HAS name TEXT` field, `tests/typecheck_object_field_typed_text_good.claro` checks the explicit `TEXT` annotation, `tests/typecheck_object_field_yesno_good.claro` checks that `SET player.ready YES` is accepted for a `HAS ready YESNO` field, `tests/typecheck_object_field_unknown_object_bad.claro` checks that `SET player.score 10` before `NEW Player player` reports the missing-object assignment diagnostic, `tests/typecheck_object_field_check_type_unknown_object_bad.claro` checks the matching missing-object `CHECK TYPE` diagnostic, and the remaining object-field fixtures cover known-field mismatches, unknown NUMBER/TEXT/YESNO fields, and unknown-field assignments whose value type is not inferable yet. This slice is intentionally small: it covers direct `NEW Class object` plus `SET object.field value` cases in one file. Field declarations are collected even when a learner writes a simple method before a later `HAS` field, so the type checker can still report the field's declared type. Broader object flows, aliases, method return checks, and richer object signatures remain future work. diff --git a/tests/test_validate_typecheck_diagnostics.py b/tests/test_validate_typecheck_diagnostics.py index 16092f1..d8809b3 100644 --- a/tests/test_validate_typecheck_diagnostics.py +++ b/tests/test_validate_typecheck_diagnostics.py @@ -39,6 +39,12 @@ class ValidateTypecheckDiagnosticsTests(unittest.TestCase): MODULE.EXPECTED_OK, ) + def test_includes_explicitly_typed_text_field_success_fixture(self): + self.assertIn( + "tests/typecheck_object_field_typed_text_good.claro", + MODULE.EXPECTED_OK, + ) + def test_includes_reverse_text_concatenation_success_fixture(self): self.assertIn( "tests/typecheck_object_field_text_concat_reverse_good.claro", diff --git a/tests/typecheck_object_field_typed_text_good.claro b/tests/typecheck_object_field_typed_text_good.claro new file mode 100644 index 0000000..c1704e3 --- /dev/null +++ b/tests/typecheck_object_field_typed_text_good.claro @@ -0,0 +1,7 @@ +CLASS Player + HAS name TEXT +END + +NEW Player player +SET player.name TEXT "Ada" +CHECK TYPE player.name IS TEXT diff --git a/tools/validate_typecheck_diagnostics.py b/tools/validate_typecheck_diagnostics.py index 6047c9d..3714845 100644 --- a/tools/validate_typecheck_diagnostics.py +++ b/tools/validate_typecheck_diagnostics.py @@ -540,6 +540,7 @@ EXPECTED_OK = [ "tests/typecheck_method_call_good.claro", "tests/typecheck_object_field_good.claro", "tests/typecheck_object_field_typed_good.claro", + "tests/typecheck_object_field_typed_text_good.claro", "tests/typecheck_object_field_expression_good.claro", "tests/typecheck_object_field_compound_good.claro", "tests/typecheck_object_field_subtraction_good.claro",