Skip to content

Commit af57901

Browse files
committed
fix(codex): expand properties-of<T> to array<non-empty-string, mixed> for generic object constraints
closes #759 Signed-off-by: azjezz <[email protected]>
1 parent 986c121 commit af57901

File tree

3 files changed

+34
-9
lines changed

3 files changed

+34
-9
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
abstract class AbstractProperty
6+
{
7+
/**
8+
* @template T of object
9+
*
10+
* @param T $object
11+
* @param key-of<properties-of<T>> $field
12+
*/
13+
public static function isInitialized(object $object, string $field): bool
14+
{
15+
// @mago-expect analysis:unhandled-thrown-type
16+
$property = new ReflectionProperty($object::class, $field);
17+
18+
return $property->isInitialized($object);
19+
}
20+
}

crates/analyzer/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ test_case!(readonly_proptected_set);
153153
test_case!(value_of_enum_resolution);
154154
test_case!(properties_of_enum);
155155
test_case!(properties_of_class);
156+
test_case!(properties_of_generic);
156157
test_case!(properties_of_visibility);
157158
test_case!(assert_or_type);
158159
test_case!(impossible_assertion);

crates/codex/src/ttype/atomic/derived/properties_of.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::ttype::atomic::object::TObject;
1818
use crate::ttype::atomic::object::r#enum::TEnum;
1919
use crate::ttype::atomic::scalar::TScalar;
2020
use crate::ttype::get_mixed;
21-
use crate::ttype::get_string;
21+
use crate::ttype::get_non_empty_string;
2222
use crate::ttype::union::TUnion;
2323
use crate::visibility::Visibility;
2424

@@ -194,23 +194,27 @@ impl TPropertiesOf {
194194
}
195195
}
196196
}
197-
TAtomic::GenericParameter(_parameter) => {
198-
// For generic parameters, we can't expand at this point
199-
// The caller should handle unexpanded types
197+
TAtomic::GenericParameter(parameter) => {
198+
if parameter.get_constraint().is_objecty() {
199+
needs_unsealed = true;
200+
}
200201
}
201202
_ => {}
202203
}
203204
}
204205

205-
if known_items.is_empty() {
206+
if known_items.is_empty() && !needs_unsealed {
206207
None
207208
} else {
208-
let mut keyed_array = TKeyedArray::new().with_known_items(known_items).with_non_empty(true);
209+
let has_known_items = !known_items.is_empty();
210+
let mut keyed_array = TKeyedArray::new().with_known_items(known_items);
209211

210-
// For non-final classes, make the array unsealed to indicate
211-
// that subclasses may have additional properties
212212
if needs_unsealed {
213-
keyed_array = keyed_array.with_parameters(Box::new(get_string()), Box::new(get_mixed()));
213+
keyed_array = keyed_array.with_parameters(Box::new(get_non_empty_string()), Box::new(get_mixed()));
214+
}
215+
216+
if has_known_items {
217+
keyed_array = keyed_array.with_non_empty(true);
214218
}
215219

216220
Some(TAtomic::Array(TArray::Keyed(keyed_array)))

0 commit comments

Comments
 (0)