Implement singleton binary literal types#10816
Conversation
Erlang's type system supports singleton types for atoms ('foo') and
integers (42), but not for binaries. This adds Phase 1 support for
binary literal types like <<"hello">> in -type, -spec, and -callback
declarations.
In this phase, Dialyzer treats <<"foo">> structurally as <<_:24>>
(by bit size). Full value tracking is planned for Phase 2.
Changes:
- Parser: grammar rule for `<< string >>` producing {bin_type, Anno, Binary}
- Linter: accept {bin_type, _, Value} in type positions
- Pretty printer: render bin_type back as <<"...">>
- Dialyzer: from_form maps to t_bitstr(0, BitSize), t_form_to_string
- Syntax tools: binary_literal_type node type with constructor/accessor/revert
- Documentation: abstract format and type spec reference updated
- Tests: erl_lint, erl_pp, syntax_tools, and dialyzer test data
Extend Dialyzer to track binary literal values, not just bit sizes.
<<"foo">> is now a distinct tracked value rather than just <<_:24>>,
enabling type narrowing, map key tracking, and set operations.
Uses the qualifier field of #c{} (unused for binary types) to store
an ordset of known binary values, following the same pattern as atom
and integer singleton sets.
Changes in erl_types.erl:
- ?bitstr_vals macro and t_binary_val/1 constructor
- from_form uses t_binary_val for value-level precision
- t_from_term tracks binary values (not just bitstring sizes)
- t_sup_aux: union of binary value sets with SET_LIMIT widening
- t_inf_aux: intersection with value sets and structural types
- t_subtract_aux: element-wise subtraction of value sets
- is_singleton_type: recognizes single-value binary sets
- separate_key: expands binary value sets for map key tracking
- t_to_string/t_elements: render and expand value sets
Add a unit test in erl_types_SUITE that directly exercises
type_form_to_remote_modules with {bin_type, _, _} forms, verifying
that binary literal types are correctly treated as leaf types with
no module dependencies.
Also extend the small_SUITE bin_type integration test with a type
that combines a binary literal and a remote type reference
(<<"hello">> | binary:part()), exercising the full Dialyzer pipeline
through get_modules_mentioned.
Fix missing binary_literal_type clauses in erl_prettypr:lay_2/2, erl_syntax:concrete/1, and erl_syntax:is_literal/1 that would crash or return wrong results for binary literal type nodes. Add comprehensive tests for binary val type operations in erl_types, empty binary edge cases in erl_pp and erl_lint, and concrete/is_literal coverage in syntax_tools.
Dialyzer's check_record_fields/3 was missing a clause for {bin_type, _, _}
forms, causing a function_clause crash when analyzing records with binary
literal type fields (e.g., -record(msg, {tag :: <<"hello">>})).
Support <<"..."/utf8>>, <<"..."/utf16>>, <<"..."/utf32>>, <<"..."/latin1>>,
and ~"..." sigil syntax in type specifications. Only the parser needed
changes since {bin_type, Anno, Bin} stores the final binary value.
Reuse existing non-terminals (opt_bit_type_list, sigil) instead of duplicating grammar structure. Reduces 3 rules to 2 and unifies builder functions, while producing identical AST output.
CT Test Results 6 files 257 suites 2h 8m 27s ⏱️ Results for commit eeaacb5. ♻️ This comment has been updated with latest results. To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass. See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally. Artifacts// Erlang/OTP Github Action Bot |
The t_from_term change now tracks exact binary values (like atoms), producing more precise type names in Dialyzer output: - <<>> becomes <<"">> - <<_:8>> becomes <<"f">> or <<"*">> for known values - <<_:16>> becomes <<"hi">> for known values - Binary map keys show as singleton values (e.g., <<"50">>) Also fix make_bitstr_vals to properly compute Unit/Base from filtered values after intersection, rather than assuming uniform sizes.
The CI license-header check requires headers on modified files. The test comparator skips %-prefixed lines, so headers are safe.
|
hey @williamthome are you still actively trying to get this one in? I was about to contribute the same feature and I found your PR, so I wonder if you can't continue the work or what is left (also, CI is failing) |
Hey @yordis! Well, not actively trying; I'm awaiting a review of erlang/eep#84 before making any code changes or fixes |
|
@IngelaAndin @bjorng can you help with the situation? |
This is an implementation of singleton binary literal types as described in erlang/eep#84.