use crate::enums::table_state::TableState;
use crate::enums::value_context::ValueContext;
use crate::functions::follow_type::follow_type_id;
use crate::functions::get_mutable_type::getMutable;
use crate::functions::get_type_alt_j::get_type_id;
use crate::functions::lookup_extern_type_prop::lookup_extern_type_prop;
use crate::functions::maybe_string::maybe_string;
use crate::records::assign_prop_constraint::AssignPropConstraint;
use crate::records::blocked_type::BlockedType;
use crate::records::constraint::Constraint;
use crate::records::constraint_solver::ConstraintSolver;
use crate::records::extern_type::ExternType;
use crate::records::metatable_type::MetatableType;
use crate::records::property_type::Property;
use crate::records::table_type::TableType;
use crate::records::union_type::UnionType;
use luaur_common::macros::luau_assert::LUAU_ASSERT;
use luaur_common::FFlag;
impl ConstraintSolver {
pub fn try_dispatch_assign_prop_constraint_not_null_constraint(
&mut self,
c: &AssignPropConstraint,
constraint: *const Constraint,
) -> bool {
let mut lhs_type = unsafe { follow_type_id(c.lhs_type) };
let rhs_type = unsafe { follow_type_id(c.rhs_type) };
if self.is_blocked_type_id(lhs_type) {
return self.block_type_id_not_null_constraint(lhs_type, constraint);
}
let lhs_extern_type = unsafe { get_type_id::<ExternType>(lhs_type) };
if !lhs_extern_type.is_null() {
let prop = unsafe { lookup_extern_type_prop(&*lhs_extern_type, &c.prop_name) };
if prop.is_null() {
self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, unsafe {
(*self.builtin_types).anyType
});
return true;
}
if let Some(write_ty) = unsafe { (*prop).write_ty } {
self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, write_ty);
self.constraint_solver_unify(constraint, rhs_type, write_ty);
} else {
self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, unsafe {
(*self.builtin_types).anyType
});
}
return true;
}
let lookup = self
.lookup_table_prop_not_null_constraint_type_id_string_value_context_bool_bool(
constraint,
lhs_type,
&c.prop_name,
ValueContext::LValue,
false,
false,
);
if !lookup.blocked_types.is_empty() {
for blocked in lookup.blocked_types {
self.block_type_id_not_null_constraint(blocked, constraint);
}
return false;
}
if let Some(prop_ty) = lookup.prop_type {
let bound_prop_ty = if lookup.is_index {
unsafe {
(*self.arena).add_type(UnionType {
options: alloc::vec![prop_ty, (*self.builtin_types).nilType],
})
}
} else {
prop_ty
};
self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, bound_prop_ty);
self.constraint_solver_unify(constraint, rhs_type, prop_ty);
return true;
}
let mut lhs_table = unsafe { getMutable::<TableType>(lhs_type) };
if lhs_table.is_null() {
let lhs_meta = unsafe { get_type_id::<MetatableType>(lhs_type) };
if !lhs_meta.is_null() {
lhs_type = unsafe { follow_type_id((*lhs_meta).table) };
lhs_table = unsafe { getMutable::<TableType>(lhs_type) };
}
}
if !lhs_table.is_null() {
let table = unsafe { &mut *lhs_table };
if let Some(prop) = table.props.get_mut(&c.prop_name) {
if let Some(write_ty) = prop.write_ty {
self.bind_not_null_constraint_type_id_type_id(
constraint,
c.prop_type,
write_ty,
);
self.constraint_solver_unify(constraint, rhs_type, write_ty);
return true;
}
if (table.state == TableState::Unsealed || table.state == TableState::Free)
&& prop.read_ty.is_some()
{
prop.write_ty = prop.read_ty;
let write_ty = prop.write_ty.unwrap();
self.bind_not_null_constraint_type_id_type_id(
constraint,
c.prop_type,
write_ty,
);
self.constraint_solver_unify(constraint, rhs_type, write_ty);
return true;
}
self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, unsafe {
(*self.builtin_types).errorType
});
return true;
}
if let Some(indexer) = &table.indexer {
if maybe_string(indexer.index_type) {
let prop_ty = indexer.index_result_type;
let union = unsafe {
(*self.arena).add_type(UnionType {
options: alloc::vec![prop_ty, (*self.builtin_types).nilType],
})
};
self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, union);
self.constraint_solver_unify(constraint, rhs_type, prop_ty);
return true;
}
}
if table.state == TableState::Unsealed || table.state == TableState::Free {
if FFlag::LuauConstraintGraph.get() {
LUAU_ASSERT!(!self.cgraph.is_null());
unsafe { (*self.cgraph).copy_dependencies_of_type_id(lhs_type, rhs_type) };
} else {
self.deprecate_d_shift_references(lhs_type, rhs_type);
}
self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, rhs_type);
let mut prop = Property::rw_type_id(rhs_type);
prop.location = c.prop_location;
table.props.insert(c.prop_name.clone(), prop);
if table.state == TableState::Unsealed && c.decrement_prop_count {
LUAU_ASSERT!(table.remaining_props > 0);
table.remaining_props -= 1;
self.unblock_type_id_location(lhs_type, unsafe { (*constraint).location });
}
return true;
}
}
let prop_type_is_blocked = unsafe { !get_type_id::<BlockedType>(c.prop_type).is_null() };
if prop_type_is_blocked {
self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, unsafe {
(*self.builtin_types).errorType
});
}
true
}
}