Skip to main content

luaur_analysis/methods/
magic_clone_handle_old_solver.rs

1use crate::functions::extend_type_pack::extend_type_pack;
2use crate::functions::follow_type::follow_type_id;
3use crate::functions::get_type_alt_j::get_type_id;
4use crate::functions::shallow_clone_clone_alt_b::shallow_clone;
5use crate::records::clone_state::CloneState;
6use crate::records::count_mismatch::CountMismatch;
7use crate::records::intersection_type::IntersectionType;
8use crate::records::module::Module;
9use crate::records::scope::Scope;
10use crate::records::table_type::TableType;
11use crate::records::type_checker::TypeChecker;
12use crate::records::type_pack::TypePack;
13use crate::records::with_predicate::WithPredicate;
14use crate::type_aliases::type_error_data::TypeErrorData;
15use crate::type_aliases::type_pack_id::TypePackId;
16use alloc::sync::Arc;
17use alloc::vec;
18use luaur_ast::records::ast_expr_call::AstExprCall;
19use luaur_common::records::dense_hash_map::DenseHashMap;
20
21// ({+ +}) -> {+ +}
22// <T: {}>(T) -> T
23pub fn magic_clone_handle_old_solver(
24    typechecker: &mut TypeChecker,
25    _scope: &Arc<Scope>,
26    expr: &AstExprCall,
27    with_predicate: WithPredicate<TypePackId>,
28) -> Option<WithPredicate<TypePackId>> {
29    let param_pack = with_predicate.r#type;
30
31    let builtin_types = typechecker.builtin_types;
32    let module = typechecker.current_module.as_ref()?;
33    let arena = unsafe { &mut (*(Arc::as_ptr(module) as *mut Module)).internal_types };
34
35    // in the old solver, nonstrict in particular is really bad about inferring `...any` for things that are definitely present
36    // and the only real way for us to deal with this is to just be more permissive here
37    let extended = extend_type_pack(arena, builtin_types, param_pack, 1, alloc::vec::Vec::new());
38    let param_types = extended.head;
39    if param_types.is_empty() || expr.args.size == 0 {
40        typechecker.report_error_location_type_error_data(
41            &expr.arg_location,
42            TypeErrorData::CountMismatch(CountMismatch {
43                expected: 1,
44                actual: 0,
45                ..Default::default()
46            }),
47        );
48        return None;
49    }
50
51    let input_type = unsafe { follow_type_id(param_types[0]) };
52
53    let table_ty = unsafe { get_type_id::<TableType>(input_type) };
54    let intersection_ty = unsafe { get_type_id::<IntersectionType>(input_type) };
55    if table_ty.is_null() && intersection_ty.is_null() {
56        return None;
57    }
58
59    if !intersection_ty.is_null() {
60        for &ty in unsafe { (*intersection_ty).parts.iter() } {
61            if unsafe { get_type_id::<TableType>(ty) }.is_null() {
62                return None;
63            }
64        }
65    }
66
67    let mut clone_state = CloneState {
68        builtin_types,
69        seen_types: DenseHashMap::new(core::ptr::null()),
70        seen_type_packs: DenseHashMap::new(core::ptr::null()),
71    };
72    let result_type = shallow_clone(
73        input_type,
74        arena,
75        &mut clone_state,
76        /* clonePersistentTypes */ false,
77    );
78
79    let cloned_type_pack = arena.add_type_pack_t(TypePack {
80        head: vec![result_type],
81        tail: None,
82    });
83    Some(WithPredicate::with_predicate_t(cloned_type_pack))
84}