Summary
The expression resolver (resolve_rhs_expression) currently widens
scalar literals to their base types (string, int, float) at
the point of resolution. This means compound expressions like
ternaries, match, and null-coalesce lose literal precision and require
a separate post-hoc narrowing pass in the diagnostic path
(narrow_literal_type) to recover it.
PHPStan preserves literal types from the start and only widens where
specifically needed. Adopting this approach would make the type system
more precise across the board — diagnostics, hover, completion — and
eliminate the need for the narrowing workaround.
Current state
resolve_rhs_expression returns PhpType::string() for
Expression::Literal(Literal::String(...)), etc.
- The diagnostic path uses
narrow_literal_type() to recover
precise literal types for argument type checking.
- Array shape and list element tracking depend on the widened types
(array{name: string} vs array{name: 'John'}).
What needs to change
- Make
resolve_rhs_expression return literal types for scalar
literals (PhpType::literal_string_raw, literal_int,
literal_float).
- Add a widening step in the array shape and list tracking layers
so that $arr['name'] = 'John' still infers
array{name: string} rather than array{name: 'John'}.
- Audit and update tests — an initial attempt showed 15 failures
in shape/list tracking tests that expect widened types.
- Once the resolver preserves literals, remove the
narrow_literal_type workaround from the diagnostic path.
Context
Discovered while fixing #180. The narrowing approach works for the
immediate issue but is architecturally fragile — it requires
enumerating every compound expression form rather than getting
precision for free from the resolver.
Summary
The expression resolver (
resolve_rhs_expression) currently widensscalar literals to their base types (
string,int,float) atthe point of resolution. This means compound expressions like
ternaries, match, and null-coalesce lose literal precision and require
a separate post-hoc narrowing pass in the diagnostic path
(
narrow_literal_type) to recover it.PHPStan preserves literal types from the start and only widens where
specifically needed. Adopting this approach would make the type system
more precise across the board — diagnostics, hover, completion — and
eliminate the need for the narrowing workaround.
Current state
resolve_rhs_expressionreturnsPhpType::string()forExpression::Literal(Literal::String(...)), etc.narrow_literal_type()to recoverprecise literal types for argument type checking.
(
array{name: string}vsarray{name: 'John'}).What needs to change
resolve_rhs_expressionreturn literal types for scalarliterals (
PhpType::literal_string_raw,literal_int,literal_float).so that
$arr['name'] = 'John'still infersarray{name: string}rather thanarray{name: 'John'}.in shape/list tracking tests that expect widened types.
narrow_literal_typeworkaround from the diagnostic path.Context
Discovered while fixing #180. The narrowing approach works for the
immediate issue but is architecturally fragile — it requires
enumerating every compound expression form rather than getting
precision for free from the resolver.