Skip to content

Commit

Permalink
Improve comparisons for enum cases
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Aug 16, 2024
1 parent 2b9b48f commit 6659b41
Show file tree
Hide file tree
Showing 16 changed files with 459 additions and 135 deletions.
10 changes: 10 additions & 0 deletions src/aast_utils/naming_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,16 @@ impl<'ast> Visitor<'ast> for Scanner<'_> {
nc.in_member_id = false;
result
}
aast::Expr_::ClassConst(boxed) => {
let result = e.recurse(nc, self);

self.resolved_names.insert(
boxed.1 .0.start_offset() as u32,
self.interner.intern(boxed.1 .1.clone()),
);

result
}
_ => e.recurse(nc, self),
};

Expand Down
5 changes: 3 additions & 2 deletions src/analyzer/expr/const_fetch_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ use hakana_type::get_mixed_any;
use hakana_type::get_string;
use hakana_type::type_expander;
use hakana_type::type_expander::TypeExpansionOptions;
use hakana_type::wrap_atomic;

use crate::function_analysis_data::FunctionAnalysisData;
use crate::scope_analyzer::ScopeAnalyzer;
use crate::scope::BlockContext;
use crate::scope_analyzer::ScopeAnalyzer;
use crate::stmt_analyzer::AnalysisError;

use oxidized::ast_defs;
Expand Down Expand Up @@ -53,7 +54,7 @@ pub(crate) fn analyze(
} else if *name == StrId::FUNCTION_CONST {
get_string()
} else if let Some(t) = &constant_storage.inferred_type {
t.clone()
wrap_atomic(t.clone())
} else if let Some(t) = &constant_storage.provided_type {
t.clone()
} else {
Expand Down
68 changes: 48 additions & 20 deletions src/analyzer/reconciler/assertion_reconciler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ use hakana_reflection_info::{
use hakana_str::StrId;
use hakana_type::{
get_arraykey, get_mixed_any, get_mixed_maybe_from_loop, get_nothing, type_combiner,
type_comparator::{atomic_type_comparator, type_comparison_result::TypeComparisonResult},
type_comparator::{
atomic_type_comparator::{self, expand_constant_value},
type_comparison_result::TypeComparisonResult,
},
type_expander::{self, TypeExpansionOptions},
wrap_atomic,
};
Expand Down Expand Up @@ -279,13 +282,9 @@ pub(crate) fn intersect_atomic_with_atomic(
) {
for (_, c1) in &storage_1.constants {
for (_, c2) in &storage_2.constants {
if let (Some(c1_type), Some(c2_type)) =
(&c1.inferred_type, &c2.inferred_type)
{
if c1_type == c2_type {
return Some(type_2_atomic.clone());
}
} else {
let c1_value = expand_constant_value(c1, codebase);
let c2_value = expand_constant_value(c2, codebase);
if c1_value == c2_value {
return Some(type_2_atomic.clone());
}
}
Expand All @@ -308,19 +307,42 @@ pub(crate) fn intersect_atomic_with_atomic(
) {
if let Some(c1) = &storage_1.constants.get(member_name) {
for (_, c2) in &storage_2.constants {
if let (Some(c1_type), Some(c2_type)) =
(&c1.inferred_type, &c2.inferred_type)
{
if c1_type == c2_type {
return Some(type_2_atomic.clone());
}
} else {
let c1_value = expand_constant_value(c1, codebase);
let c2_value = expand_constant_value(c2, codebase);

if c1_value == c2_value {
return Some(type_2_atomic.clone());
}
}
}
}
}
(
TAtomic::TEnum {
name: type_1_name, ..
},
TAtomic::TEnumLiteralCase {
enum_name: type_2_name,
member_name,
..
},
) => {
if let (Some(storage_1), Some(storage_2)) = (
codebase.classlike_infos.get(type_1_name),
codebase.classlike_infos.get(type_2_name),
) {
if let Some(c2) = &storage_2.constants.get(member_name) {
for (_, c1) in &storage_1.constants {
let c1_value = expand_constant_value(c1, codebase);
let c2_value = expand_constant_value(c2, codebase);

if c1_value == c2_value {
return Some(type_1_atomic.clone());
}
}
}
}
}
(
TAtomic::TEnumLiteralCase {
enum_name: type_1_name,
Expand Down Expand Up @@ -872,9 +894,12 @@ fn intersect_enumcase_with_string(
let enum_storage = codebase.classlike_infos.get(type_1_name).unwrap();
if let Some(member_storage) = enum_storage.constants.get(type_1_member_name) {
if let Some(inferred_type) = &member_storage.inferred_type {
if let Some(inferred_value) = inferred_type.get_single_literal_string_value() {
if let TAtomic::TLiteralString {
value: inferred_value,
} = inferred_type
{
return Some(TAtomic::TLiteralString {
value: inferred_value,
value: inferred_value.clone(),
});
}
}
Expand All @@ -891,9 +916,12 @@ fn intersect_enum_case_with_int(
let enum_storage = codebase.classlike_infos.get(type_1_name).unwrap();
if let Some(member_storage) = enum_storage.constants.get(type_1_member_name) {
if let Some(inferred_type) = &member_storage.inferred_type {
if let Some(inferred_value) = inferred_type.get_single_literal_int_value() {
if let TAtomic::TLiteralInt {
value: inferred_value,
} = inferred_type
{
return Some(TAtomic::TLiteralInt {
value: inferred_value,
value: *inferred_value,
});
}
}
Expand All @@ -912,7 +940,7 @@ fn intersect_enum_with_literal(

for (case_name, enum_case) in &enum_storage.constants {
if let Some(inferred_type) = &enum_case.inferred_type {
if inferred_type.get_single() == type_2_atomic {
if inferred_type == type_2_atomic {
return Some(TAtomic::TEnumLiteralCase {
enum_name: *type_1_name,
member_name: *case_name,
Expand Down
21 changes: 12 additions & 9 deletions src/analyzer/reconciler/negated_assertion_reconciler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,10 +484,11 @@ fn handle_literal_negated_equality(
let mut member_enum_literals = vec![];
for (cname, const_info) in &enum_storage.constants {
if let Some(inferred_type) = &const_info.inferred_type {
if let Some(const_inferred_value) =
inferred_type.get_single_literal_string_value()
if let TAtomic::TLiteralString {
value: const_inferred_value,
} = inferred_type
{
if &const_inferred_value != assertion_value {
if const_inferred_value != assertion_value {
if let Some(constant_type) = codebase.get_class_constant_type(
&existing_name,
false,
Expand Down Expand Up @@ -522,10 +523,11 @@ fn handle_literal_negated_equality(
let mut member_enum_literals = vec![];
for (cname, const_info) in &enum_storage.constants {
if let Some(inferred_type) = &const_info.inferred_type {
if let Some(const_inferred_value) =
inferred_type.get_single_literal_int_value()
if let TAtomic::TLiteralInt {
value: const_inferred_value,
} = inferred_type
{
if &const_inferred_value != assertion_value {
if const_inferred_value != assertion_value {
if let Some(constant_type) = codebase.get_class_constant_type(
&existing_name,
false,
Expand Down Expand Up @@ -577,10 +579,11 @@ fn handle_literal_negated_equality(

if let Some(const_info) = enum_storage.constants.get(&existing_member_name) {
if let Some(const_inferred_type) = &const_info.inferred_type {
if let Some(const_inferred_value) =
const_inferred_type.get_single_literal_string_value()
if let TAtomic::TLiteralString {
value: const_inferred_value,
} = const_inferred_type
{
if &const_inferred_value == value {
if const_inferred_value == value {
matched_string = true;
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/code_info/class_constant_info.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use serde::{Deserialize, Serialize};

use crate::{
code_location::HPos, functionlike_parameter::UnresolvedConstantComponent, t_union::TUnion,
code_location::HPos, functionlike_parameter::UnresolvedConstantComponent, t_atomic::TAtomic,
t_union::TUnion,
};

#[derive(Clone, Debug, Serialize, Deserialize)]
Expand All @@ -12,7 +13,7 @@ pub struct ConstantInfo {

pub provided_type: Option<TUnion>,

pub inferred_type: Option<TUnion>,
pub inferred_type: Option<TAtomic>,

pub unresolved_value: Option<UnresolvedConstantComponent>,

Expand Down
12 changes: 4 additions & 8 deletions src/code_info/codebase_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,11 @@ impl CodebaseInfo {
}]))
} else if let Some(constant_storage) = classlike_storage.constants.get(const_name) {
if matches!(classlike_storage.kind, SymbolKind::EnumClass) {
return constant_storage.provided_type.as_ref().cloned();
return constant_storage.provided_type.as_ref().map(|t| t.clone());
} else if let Some(provided_type) = &constant_storage.provided_type {
if provided_type.types.iter().all(|v| v.is_boring_scalar()) && !is_this {
if let Some(inferred_type) = &constant_storage.inferred_type {
Some(inferred_type.clone())
Some(TUnion::new(vec![inferred_type.clone()]))
} else {
Some(provided_type.clone())
}
Expand All @@ -236,7 +236,7 @@ impl CodebaseInfo {
}
} else if let Some(inferred_type) = &constant_storage.inferred_type {
if !is_this {
Some(inferred_type.clone())
Some(TUnion::new(vec![inferred_type.clone()]))
} else {
None
}
Expand All @@ -258,11 +258,7 @@ impl CodebaseInfo {
) -> Option<&TAtomic> {
if let Some(classlike_storage) = self.classlike_infos.get(fq_class_name) {
if let Some(constant_storage) = classlike_storage.constants.get(const_name) {
if let Some(inferred_type) = &constant_storage.inferred_type {
Some(inferred_type.get_single())
} else {
None
}
constant_storage.inferred_type.as_ref()
} else {
None
}
Expand Down
51 changes: 51 additions & 0 deletions src/code_info/t_atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ pub enum TAtomic {
member_name: StrId,
constraint_type: Option<Box<TAtomic>>,
},
TMemberReference {
classlike_name: StrId,
member_name: StrId,
},
TLiteralInt {
value: i64,
},
Expand Down Expand Up @@ -397,6 +401,25 @@ impl TAtomic {
}
str
}
TAtomic::TMemberReference {
classlike_name,
member_name,
..
} => {
let mut str = String::new();
if let Some(interner) = interner {
str += interner.lookup(classlike_name);
} else {
str += classlike_name.0.to_string().as_str();
}
str += "::";
if let Some(interner) = interner {
str += interner.lookup(member_name);
} else {
str += member_name.0.to_string().as_str();
}
str
}
TAtomic::TLiteralInt { value } => {
let mut str = String::new();
str += "int(";
Expand Down Expand Up @@ -706,6 +729,7 @@ impl TAtomic {
| TAtomic::TLiteralClassname { .. }
| TAtomic::TLiteralInt { .. }
| TAtomic::TEnumLiteralCase { .. }
| TAtomic::TMemberReference { .. }
| TAtomic::TClassTypeConstant { .. }
| TAtomic::TLiteralString { .. }
| TAtomic::TVoid
Expand Down Expand Up @@ -1836,6 +1860,33 @@ pub fn populate_atomic_type(
};
}
}
TAtomic::TMemberReference {
ref classlike_name,
ref member_name,
} => {
match reference_source {
ReferenceSource::Symbol(in_signature, a) => symbol_references
.add_symbol_reference_to_class_member(
*a,
(*classlike_name, *member_name),
*in_signature,
),
ReferenceSource::ClasslikeMember(in_signature, a, b) => symbol_references
.add_class_member_reference_to_class_member(
(*a, *b),
(*classlike_name, *member_name),
*in_signature,
),
}

if let Some(SymbolKind::Enum) = codebase_symbols.all.get(classlike_name) {
*t_atomic = TAtomic::TEnumLiteralCase {
enum_name: *classlike_name,
member_name: *member_name,
constraint_type: None,
};
}
}
TAtomic::TClassname { as_type } | TAtomic::TTypename { as_type } => {
populate_atomic_type(
as_type,
Expand Down
6 changes: 2 additions & 4 deletions src/code_info_builder/classlike_scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,10 +608,8 @@ pub(crate) fn scan(
simple_type_inferer::infer(attribute_param_expr, resolved_names);

if let Some(attribute_param_type) = attribute_param_type {
for atomic in attribute_param_type.types.into_iter() {
if let TAtomic::TLiteralClassname { name: value } = atomic {
child_classlikes.insert(value);
}
if let TAtomic::TLiteralClassname { name: value } = attribute_param_type {
child_classlikes.insert(value);
}
}
}
Expand Down
Loading

0 comments on commit 6659b41

Please sign in to comment.