diff --git a/README.md b/README.md index f485c36..45eea20 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,12 @@ Type mismatch for field alias.score: expected NUMBER, but this value looks like The same check follows simple arithmetic and text-concatenation expressions. For example, `SET player.score player.name + 1` reports that the value looks like `TEXT`, rather than silently accepting an expression whose result cannot fit the `NUMBER` field. +The checker also identifies text operands in other arithmetic expressions. For example, `SET player.score player.score - player.name` reports the text result instead of silently treating an invalid numeric subtraction as unknown: + +```text +Type mismatch for field player.score: expected NUMBER, but this value looks like TEXT. +``` + TEXT-valued and YESNO-valued field-name mistakes are validated too: ```text diff --git a/docs/ADVANCED_STATIC_TYPING.md b/docs/ADVANCED_STATIC_TYPING.md index 22c4b1a..5638ab7 100644 --- a/docs/ADVANCED_STATIC_TYPING.md +++ b/docs/ADVANCED_STATIC_TYPING.md @@ -89,6 +89,18 @@ Type mismatch for field backup.score: expected NUMBER, but this value looks like This remains limited to direct assignments through simple alias chains; control-flow and complex object-flow analysis are still planned. +Text operands are also identified when they appear in subtraction, multiplication, or division expressions. This catches a common beginner mistake such as subtracting a text field from a number field: + +```claro +SET player.score player.score - player.name +``` + +```text +Type mismatch for field player.score: expected NUMBER, but this value looks like TEXT. +``` + +The expression checker still deliberately reports only the type it can infer; full operator-specific rules remain future work. + `CHECK TYPE` also preserves TEXT field metadata through the same chained aliases: ```claro diff --git a/docs/CURRENT_STATUS.md b/docs/CURRENT_STATUS.md index 629ee63..f810694 100644 --- a/docs/CURRENT_STATUS.md +++ b/docs/CURRENT_STATUS.md @@ -57,6 +57,7 @@ Ready now: Still needed: - Keep the focused typecheck validator's fixture list complete as new positive and negative examples are added. +- The expression checker now carries a known TEXT operand through all arithmetic operators so object-field diagnostics do not hide subtraction, multiplication, or division mistakes; operator-specific diagnostics remain planned. - richer typed function signatures and return values - type checking through branches and loops - richer object field type checking beyond simple direct assignments diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index e4bf0da..72c6bfd 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -36,6 +36,7 @@ See `CURRENT_STATUS.md` for the detailed feature matrix. 3b. Keep package security validation in Forgejo/Gitea CI so unsafe names, exact manifest-version/name/version/checksum mismatches, missing manifests, duplicate project manifest versions and packages, duplicate lock packages, duplicate package manifest names, versions, and checksums, and lockfile errors remain release blockers. 4. Add small examples for each foundation feature before adding bigger syntax. The object-field foundation now includes positive and negative validation for field expressions such as `SET player.score player.name`, `SET player.score player.score + 1`, `SET player.name player.score + 1`, explicitly typed field assignments, simple and chained aliases such as `SET alias player`, `SET backup alias`, followed by `SET backup.score ...` or `CHECK TYPE backup.score IS ...`, chained aliases in object-method calls through both modern `DO` and compatibility `CALL ... WITH` forms (including a dedicated positive modern `DO` fixture), and arithmetic/text expression mismatches; typed containers also accept a map with nested type metadata when it is added to a `LIST OF MAP`; broader alias/control-flow checking remains planned. 5. Keep the focused typecheck validator complete: every `typecheck_*.claro` fixture, including positive fixtures, must be exercised by release validation. +6. Continue narrowing expression diagnostics: known TEXT operands now remain visible through non-concatenation arithmetic, while operator-specific guidance is still future work. ## Complete-platform milestones diff --git a/src/claro.c b/src/claro.c index 7898e79..2d71105 100644 --- a/src/claro.c +++ b/src/claro.c @@ -546,7 +546,7 @@ static const char *simple_expr_type(Var *types,const char *expr){ char *left=substr(t,t+i), *right=xstrdup(t+i+1); const char *lt,*rt; lt=simple_expr_type(types,left); rt=simple_expr_type(types,right); free(left); free(right); - if(t[i]=='+'&&((lt&&ci_eq(lt,"TEXT"))||(rt&&ci_eq(rt,"TEXT")))) return "TEXT"; + if((lt&&ci_eq(lt,"TEXT"))||(rt&&ci_eq(rt,"TEXT"))) return "TEXT"; if(lt&&rt&&ci_eq(lt,"NUMBER")&&ci_eq(rt,"NUMBER")) return "NUMBER"; return NULL; } diff --git a/tests/typecheck_object_field_subtraction_bad.claro b/tests/typecheck_object_field_subtraction_bad.claro new file mode 100644 index 0000000..c5b33e6 --- /dev/null +++ b/tests/typecheck_object_field_subtraction_bad.claro @@ -0,0 +1,8 @@ +CLASS Player + HAS name TEXT + HAS score NUMBER +END + +NEW Player player +SET player.name "Ada" +SET player.score player.score - player.name diff --git a/tools/validate_typecheck_diagnostics.py b/tools/validate_typecheck_diagnostics.py index 0c8299f..ff993f8 100644 --- a/tools/validate_typecheck_diagnostics.py +++ b/tools/validate_typecheck_diagnostics.py @@ -110,6 +110,9 @@ EXPECTED = { "tests/typecheck_object_field_compound_bad.claro": [ "tests/typecheck_object_field_compound_bad.claro:8: Type mismatch for field player.score: expected NUMBER, but this value looks like TEXT.", ], + "tests/typecheck_object_field_subtraction_bad.claro": [ + "tests/typecheck_object_field_subtraction_bad.claro:8: Type mismatch for field player.score: expected NUMBER, but this value looks like TEXT.", + ], "tests/typecheck_object_field_text_expression_bad.claro": [ "tests/typecheck_object_field_text_expression_bad.claro:8: Type mismatch for field player.name: expected TEXT, but this value looks like NUMBER.", ],