Skip to main content

typr_core/components/context/
mod.rs

1pub mod config;
2pub mod fingerprint;
3pub mod graph;
4pub mod vartype;
5
6use crate::components::context::config::Config;
7use crate::components::context::config::Environment;
8use crate::components::context::config::TargetLanguage;
9use crate::components::context::graph::Graph;
10use crate::components::context::unification_map::UnificationMap;
11use crate::components::context::vartype::VarType;
12use crate::components::error_message::help_data::HelpData;
13use crate::components::language::var::Var;
14use crate::components::language::var_function::VarFunction;
15use crate::components::language::Lang;
16use crate::components::r#type::argument_type::ArgumentType;
17use crate::components::r#type::kind::Kind;
18use crate::components::r#type::type_system::TypeSystem;
19use crate::components::r#type::vector_type::ConstructorCategory;
20use crate::components::r#type::Type;
21use crate::processes::type_checking::facets;
22use crate::processes::type_checking::match_types_to_generic;
23use crate::processes::type_checking::type_comparison::reduce_type;
24use crate::processes::type_checking::unification_map;
25use crate::utils::builder;
26use crate::utils::standard_library::not_in_blacklist;
27use serde::Deserialize;
28use serde::Serialize;
29use std::collections::HashMap;
30use std::collections::HashSet;
31
32use std::ops::Add;
33use std::sync::Arc;
34use tap::Pipe;
35
36/// True for the auto-generated names given to anonymous record types
37/// (`Record0`, `Record1`, …), as produced by `VarType::push_alias_increment`
38/// (`format!("{}{}", TypeCategory::Record, count)`).
39fn is_anonymous_record_name(name: &str) -> bool {
40    name.strip_prefix("Record")
41        .map(|rest| !rest.is_empty() && rest.chars().all(|c| c.is_ascii_digit()))
42        .unwrap_or(false)
43}
44
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
46pub struct Context {
47    pub typing_context: VarType,
48    pub subtypes: Graph<Type>,
49    /// Registry of user-declared `typeconstructor`s: (name, parameter signature, category).
50    #[serde(default)]
51    pub type_constructors: Vec<(String, Vec<Type>, ConstructorCategory)>,
52    /// Constraints mapping a rigid generic variable name to its interface.
53    /// Introduced when an interface type appears in parameter position:
54    /// fn(i: I): R  ⇒  i : A  with A: I  stored here.
55    #[serde(default)]
56    pub interface_constraints: HashMap<String, Type>,
57    /// Counter for generating unique rigid generic variable names.
58    #[serde(default)]
59    pub rigid_counter: u64,
60    /// Flat, whole-program registry of every `type X <- list { ... }` record
61    /// alias declared anywhere, including inside `mod` bodies. Unlike
62    /// `typing_context.aliases`, this is never scoped away at a module
63    /// boundary: R's S3 class system has no module privacy, so transpilation
64    /// needs the full picture to compute structural supertypes for the class
65    /// vector (see `record_field_class` callers in `processes::transpiling`).
66    #[serde(default)]
67    pub record_aliases: Vec<(String, Type)>,
68    /// Named type embedding (`embed field: Type`): provenance of every function
69    /// auto-generated by forwarding/reconstruction, as `(type_name, method_name,
70    /// source_field_name)`. Used to detect a later explicit definition that
71    /// collides with an inherited embedded function (E-EMBED-003).
72    #[serde(default)]
73    pub embedded_methods: Vec<(String, String, String)>,
74    /// RFC-TR-031: lines injected at the top of a `Test { ... }` file so the
75    /// test body can reach `@testable` private members of the enclosing module
76    /// (e.g. `sq <- Math$.test_sq`). Set while transpiling a module body in a
77    /// test build; empty otherwise. Not serialised.
78    #[serde(skip)]
79    pub test_preamble: Vec<String>,
80    /// `Self:{ ... }` (generic_constructor.md): the type bound to the
81    /// enclosing function/method's first parameter, set only while
82    /// type-checking that function's body. `None` everywhere else, which is
83    /// what makes `Self` invalid outside a function body.
84    #[serde(skip)]
85    pub self_type: Option<Type>,
86    /// The declared return type of the function whose body is currently being
87    /// type-checked (audit_type_checking.md C1) — lets `Lang::Return` compare
88    /// an early `return` against the same target the trailing expression is
89    /// checked against in `function()`. `None` outside a function body.
90    #[serde(skip)]
91    pub expected_return_type: Option<Type>,
92    /// Inner typing contexts computed while type-checking each `module M { ... }`
93    /// body, keyed by module name. Populated during type-checking; consumed
94    /// during transpilation to avoid re-running `typing()` on every module body.
95    #[serde(skip)]
96    pub module_inner_contexts: HashMap<String, Arc<Context>>,
97    /// Cache of fully type-checked modules. Maps module name → its
98    /// `Type::Module` so that `use Module::*;` can be resolved without
99    /// re-walking the module path in the variable table. Populated by
100    /// `eval()` for `Lang::Module` and consumed by `typing()` for
101    /// `Lang::UseModule`.
102    #[serde(skip)]
103    pub processed_modules: HashMap<String, Type>,
104    /// Set of module names whose body is currently being type-checked.
105    /// Used to detect circular import chains at the type-checking level.
106    /// A `Lang::UseModule` targeting a name in this set is a cycle error.
107    #[serde(skip)]
108    pub modules_in_progress: HashSet<String>,
109    /// Registry of `@extern` function declarations: (TypR name, R-side qualified name).
110    /// When `Option<String>` is `None` the TypR name is used directly as the R call.
111    #[serde(default)]
112    pub extern_fns: Vec<(String, Option<String>)>,
113    /// Registry of `@importFrom` declarations: (TypR function name, "pkg::fn_name").
114    /// At call sites the transpiler emits `pkg::fn_name(args)` instead of `fn_name(args)`,
115    /// bypassing TypR's own S3 generic stubs for names like `get`, `map`, `factor`.
116    #[serde(default)]
117    pub import_from_fns: Vec<(String, String)>,
118    /// Names declared signature-only (`@name: T;`), i.e. typed here but
119    /// implemented in R somewhere else — base R, a package, or hand-written R.
120    /// Unlike an ordinary `let`, such a name has no TypR body to transpile
121    /// into `name.<Type>` methods, so shadowing it with a `UseMethod` stub
122    /// strands whatever R implementation it was declared for. `typr build`
123    /// reads this to tell the two cases apart when deciding whether a missing
124    /// `<name>.default` is worth reporting (see `r_name_lint`).
125    #[serde(default)]
126    pub signature_fns: Vec<String>,
127    /// Static vectorizability of user-declared functions, keyed by name:
128    /// `true` means every declaration seen so far for that name has a body
129    /// made only of natively-vectorized R operations (see
130    /// `processes::type_checking::vectorizability`), so a `Vec[N, T]` call
131    /// site may call it directly instead of wrapping it in `vapply`. Any
132    /// non-vectorizable overload of the same name downgrades the entry to
133    /// `false` for good (S3 dispatch at the call site can't tell overloads
134    /// apart by name alone).
135    #[serde(default)]
136    pub vectorizable_fns: Vec<(String, bool)>,
137    config: Config,
138}
139
140/// The canonical sentinel nodes seeded into every subtype `Graph` so the
141/// kind-sigil generic categories materialize as intermediate levels of the
142/// lattice. Because `is_subtype_raw` already gives `RecordN <: %_ <: Generic
143/// <: Any` (a concrete Record is a subtype of a record-kinded `KindedGen`, and
144/// any generic is a subtype of the bare `Generic`), seeding one anchor per
145/// kind makes every monomorphized record/interface/char/bool/number auto-nest
146/// under its `G*` node. These sentinels all answer `has_generic() == true`, so
147/// `get_classes` filters them out of generated R `class = c(...)` vectors —
148/// they are a compile-time organisation of the hierarchy only.
149fn generic_sentinels() -> Vec<Type> {
150    let h = HelpData::default();
151    let name = "_".to_string();
152    vec![
153        Type::Generic(name.clone(), h.clone()),
154        Type::KindedGen(Kind::Record, name.clone(), h.clone()),
155        Type::KindedGen(Kind::Interface, name.clone(), h.clone()),
156        Type::KindedGen(Kind::String, name.clone(), h.clone()),
157        Type::KindedGen(Kind::Boolean, name.clone(), h.clone()),
158        Type::IndexGen(name, h),
159    ]
160}
161
162/// A fresh subtype graph pre-seeded with the kind-sigil generic sentinels
163/// (see [`generic_sentinels`]). Built against `Context::empty()` since the
164/// sentinel ordering only exercises the structural `is_subtype_raw` arms
165/// (`(_, Generic)`, `(_, Any)`, the `KindedGen`/`IndexGen` arms) and needs no
166/// typing context.
167fn seeded_subtype_graph() -> Graph<Type> {
168    Graph::new().add_types(&generic_sentinels(), &Context::empty())
169}
170
171impl Default for Context {
172    fn default() -> Self {
173        let config = Config::default();
174        Context {
175            config: config.clone(),
176            typing_context: VarType::from_config(config),
177            subtypes: seeded_subtype_graph(),
178            type_constructors: Vec::new(),
179            interface_constraints: HashMap::new(),
180            rigid_counter: 0,
181            record_aliases: Vec::new(),
182            embedded_methods: Vec::new(),
183            test_preamble: Vec::new(),
184            self_type: None,
185            expected_return_type: None,
186            extern_fns: Vec::new(),
187            import_from_fns: Vec::new(),
188            signature_fns: Vec::new(),
189            vectorizable_fns: Vec::new(),
190            module_inner_contexts: HashMap::new(),
191            processed_modules: HashMap::new(),
192            modules_in_progress: HashSet::new(),
193        }
194    }
195}
196
197impl From<Vec<(Lang, Type)>> for Context {
198    fn from(val: Vec<(Lang, Type)>) -> Self {
199        let val2: Vec<(Var, Type)> = val
200            .iter()
201            .map(|(lan, typ)| (Var::from_language(lan.clone()).unwrap(), typ.clone()))
202            .collect();
203        Context {
204            typing_context: val2.into(),
205            ..Context::default()
206        }
207    }
208}
209
210impl Context {
211    pub fn new(types: Vec<(Var, Type)>) -> Context {
212        Context {
213            typing_context: types.into(),
214            ..Context::default()
215        }
216    }
217
218    pub fn empty() -> Self {
219        Context {
220            config: Config::default(),
221            typing_context: VarType::new(),
222            subtypes: Graph::new(),
223            type_constructors: Vec::new(),
224            interface_constraints: HashMap::new(),
225            rigid_counter: 0,
226            record_aliases: Vec::new(),
227            embedded_methods: Vec::new(),
228            test_preamble: Vec::new(),
229            self_type: None,
230            expected_return_type: None,
231            extern_fns: Vec::new(),
232            import_from_fns: Vec::new(),
233            signature_fns: Vec::new(),
234            vectorizable_fns: Vec::new(),
235            module_inner_contexts: HashMap::new(),
236            processed_modules: HashMap::new(),
237            modules_in_progress: HashSet::new(),
238        }
239    }
240
241    pub fn is_extern_fn(&self, name: &str) -> bool {
242        self.extern_fns.iter().any(|(n, _)| n == name)
243    }
244
245    /// Whether `name` was introduced by a signature declaration (`@name: T;`)
246    /// rather than by a TypR definition with a body.
247    pub fn is_signature_fn(&self, name: &str) -> bool {
248        self.signature_fns.iter().any(|n| n == name)
249    }
250
251    pub fn get_extern_r_name(&self, name: &str) -> Option<String> {
252        self.extern_fns
253            .iter()
254            .find(|(n, _)| n == name)
255            .and_then(|(_, r)| r.clone())
256    }
257
258    pub fn is_import_from_fn(&self, name: &str) -> bool {
259        self.import_from_fns.iter().any(|(n, _)| n == name)
260    }
261
262    pub fn get_import_from_r_name(&self, name: &str) -> Option<String> {
263        self.import_from_fns
264            .iter()
265            .find(|(n, _)| n == name)
266            .map(|(_, r)| r.clone())
267    }
268
269    /// Record whether a user function declaration has a natively-vectorizable
270    /// body. A name is only vectorizable while *every* declaration seen for it
271    /// is — one non-vectorizable overload downgrades the entry permanently.
272    pub fn register_vectorizable_fn(mut self, name: &str, is_vectorizable: bool) -> Self {
273        match self.vectorizable_fns.iter_mut().find(|(n, _)| n == name) {
274            Some(entry) => entry.1 = entry.1 && is_vectorizable,
275            None => self.vectorizable_fns.push((name.to_string(), is_vectorizable)),
276        }
277        self
278    }
279
280    pub fn is_vectorizable_fn(&self, name: &str) -> bool {
281        self.vectorizable_fns.iter().any(|(n, v)| n == name && *v)
282    }
283
284    pub fn set_config(self, config: Config) -> Self {
285        Self { config, ..self }
286    }
287
288    pub fn set_as_module_context(self) -> Context {
289        Self {
290            config: self.config.set_as_module(),
291            ..self
292        }
293    }
294
295    pub fn set_test_mode(self, val: bool) -> Context {
296        Self {
297            config: self.config.set_test_mode(val),
298            ..self
299        }
300    }
301
302    pub fn get_test_mode(&self) -> bool {
303        self.config.test_mode
304    }
305
306    pub fn set_checked_mode(self, val: bool) -> Context {
307        Self {
308            config: self.config.set_checked_mode(val),
309            ..self
310        }
311    }
312
313    pub fn get_checked_mode(&self) -> bool {
314        self.config.checked_mode
315    }
316
317    pub fn set_test_preamble(self, lines: Vec<String>) -> Context {
318        Self {
319            test_preamble: lines,
320            ..self
321        }
322    }
323
324    /// `Self:{ ... }` (generic_constructor.md §4.1): bind/clear the type
325    /// denoted by `Self` for the duration of typing a function body.
326    pub fn set_self_type(self, self_type: Option<Type>) -> Context {
327        Self { self_type, ..self }
328    }
329
330    /// Bind/clear the declared return type of the function whose body is
331    /// currently being type-checked (audit_type_checking.md C1).
332    pub fn set_expected_return_type(self, expected_return_type: Option<Type>) -> Context {
333        Self {
334            expected_return_type,
335            ..self
336        }
337    }
338
339    pub fn get_expected_return_type(&self) -> Option<Type> {
340        self.expected_return_type.clone()
341    }
342
343    pub fn store_module_inner_context(mut self, name: &str, inner: &Context) -> Self {
344        // `inner` is the module body's final context, which inherits (and thus
345        // still carries) every `module_inner_contexts` entry that was already
346        // present in the *ambient* context before this module started (nested
347        // sibling modules typed earlier in the same file/enclosing module).
348        // Storing `inner` as-is would re-embed all of those already-stored
349        // snapshots inside this module's own boxed snapshot; since `Context`
350        // is cloned pervasively throughout type-checking, and every module
351        // boundary would repeat this, the nesting depth (and thus clone cost)
352        // grows exponentially with the number of `mod` declarations. Keep
353        // only the entries genuinely *new* to this module's own body (i.e.
354        // not already known to the ambient context) — those are exactly the
355        // modules declared/nested directly within this one.
356        let new_entries: HashMap<String, Arc<Context>> = inner
357            .module_inner_contexts
358            .iter()
359            .filter(|(k, _)| !self.module_inner_contexts.contains_key(k.as_str()))
360            .map(|(k, v)| (k.clone(), v.clone()))
361            .collect();
362        let mut trimmed = inner.clone();
363        trimmed.module_inner_contexts = new_entries;
364        self.module_inner_contexts.insert(name.to_string(), Arc::new(trimmed));
365        self
366    }
367
368    pub fn get_module_inner_context(&self, name: &str) -> Option<&Context> {
369        self.module_inner_contexts.get(name).map(|b| b.as_ref())
370    }
371
372    /// Mark a module as currently being type-checked. Returns the updated
373    /// context with `name` added to `modules_in_progress`.
374    pub fn mark_module_in_progress(self, name: &str) -> Self {
375        let mut set = self.modules_in_progress.clone();
376        set.insert(name.to_string());
377        Self {
378            modules_in_progress: set,
379            ..self
380        }
381    }
382
383    /// Remove a module from the in-progress set after its body has been
384    /// fully type-checked.
385    pub fn unmark_module_in_progress(self, name: &str) -> Self {
386        let mut set = self.modules_in_progress.clone();
387        set.remove(name);
388        Self {
389            modules_in_progress: set,
390            ..self
391        }
392    }
393
394    /// True when `name` is currently being type-checked (its body is on the
395    /// call stack). A `use {name}::*;` encountered while this returns `true`
396    /// is a circular dependency.
397    pub fn is_module_in_progress(&self, name: &str) -> bool {
398        self.modules_in_progress.contains(name)
399    }
400
401    /// Register `module_type` in the processed-module cache so that
402    /// subsequent `use {name}::*;` directives can resolve it without
403    /// walking the full variable-path chain.
404    pub fn cache_processed_module(self, name: &str, module_type: Type) -> Self {
405        let mut map = self.processed_modules.clone();
406        map.insert(name.to_string(), module_type);
407        Self {
408            processed_modules: map,
409            ..self
410        }
411    }
412
413    /// Look up a previously cached module by name. Returns `Some(module_type)`
414    /// when `name` has already been fully type-checked in this session.
415    pub fn get_processed_module(&self, name: &str) -> Option<&Type> {
416        self.processed_modules.get(name)
417    }
418
419    pub fn set_in_module_body(self) -> Self {
420        Self {
421            config: self.config.set_in_module_body(true),
422            ..self
423        }
424    }
425
426    pub fn is_in_module_body(&self) -> bool {
427        self.config.in_module_body
428    }
429
430    /// See `Config::in_loop` — set while type-checking the body of a
431    /// `Loop`/`WhileLoop`/`ForLoop` so `break`/`next` inside it are valid.
432    pub fn set_in_loop(self, val: bool) -> Self {
433        Self {
434            config: self.config.set_in_loop(val),
435            ..self
436        }
437    }
438
439    pub fn is_in_loop(&self) -> bool {
440        self.config.in_loop
441    }
442
443    /// Retourne un nouveau Context avec le Graph de sous-typage mis à jour
444    pub fn with_subtypes(self, subtypes: Graph<Type>) -> Self {
445        Self { subtypes, ..self }
446    }
447
448    pub fn get_members(&self) -> Vec<(Var, Type)> {
449        self.typing_context
450            .variables()
451            .chain(self.aliases())
452            .cloned()
453            .collect::<Vec<_>>()
454    }
455
456    pub fn variable_exist(&self, var: Var) -> Option<Var> {
457        self.typing_context.variable_exist(var, self)
458    }
459
460    pub fn get_type_from_variable(&self, var: &Var) -> Result<Type, String> {
461        let res = self
462            .typing_context
463            .entries_named(&var.get_name())
464            .into_iter()
465            .flat_map(|(var2, typ)| {
466                let conditions =
467                    (var.is_opaque == var2.is_opaque) && var.related_type.is_subtype(&var2.related_type, self).0;
468                if conditions {
469                    Some(typ)
470                } else {
471                    None
472                }
473            })
474            .reduce(|acc, x| if x.is_subtype(&acc, self).0 { x } else { acc });
475        match res {
476            Some(typ) => Ok(typ),
477            // Every call site discards this message via `.ok()`/`unwrap_or_else`,
478            // so `display_typing_context()` (formats ~1700 stdlib+user entries)
479            // is never actually read — skip it rather than pay it on every
480            // speculative lookup (see project_typechecking_optimization memory).
481            _ => Err(format!("Didn't find {} in the context", var.get_name())),
482        }
483    }
484
485    pub fn get_types_from_name(&self, name: &str) -> Vec<Type> {
486        self.typing_context
487            .entries_named(name)
488            .into_iter()
489            .map(|(_, typ)| typ)
490            .collect()
491    }
492
493    pub fn get_type_from_aliases(&self, var: &Var) -> Option<Type> {
494        self.aliases()
495            .flat_map(|(var2, type_)| {
496                let conditions = (var.name == var2.name)
497                    && (var.is_opaque == var2.is_opaque)
498                    && var.related_type.is_subtype(&var2.related_type, self).0;
499                if conditions {
500                    Some(type_.clone())
501                } else {
502                    None
503                }
504            })
505            .next()
506    }
507
508    /// Search every module currently in scope (declared via `module M { ... }`
509    /// somewhere visible, whether or not any of its members were ever brought
510    /// in via `use`) for a public alias named `name`. Returns the module's
511    /// name on a hit — used to tell "genuinely undefined alias" apart from
512    /// "exists, but this file never imported it" so the error can point at
513    /// the fix (`use M::Name;`) instead of just saying "not defined".
514    pub fn find_alias_source_module(&self, name: &str) -> Option<String> {
515        self.variables().find_map(|(var, typ)| {
516            let module_type = typ.clone().to_module_type().ok()?;
517            module_type
518                .get_aliases()
519                .iter()
520                .any(|(alias_var, _)| alias_var.get_name() == name)
521                .then(|| var.get_name())
522        })
523    }
524
525    /// Same idea as `find_alias_source_module`, but for ordinary names
526    /// (variables and functions) rather than type aliases. Scans every
527    /// module currently in scope for a member named `name`, checking public
528    /// members first, then private ones — returns `(module_name,
529    /// is_public)` on a hit. A private hit still points the error at
530    /// `use M::name;` (per the fix this supports): the member exists and
531    /// this is where it lives, even though that particular `use` will itself
532    /// fail with `PrivateImport` until the declaration gains `@pub`/`@export`.
533    pub fn find_variable_source_module(&self, name: &str) -> Option<(String, bool)> {
534        self.variables().find_map(|(var, typ)| {
535            let module_type = typ.clone().to_module_type().ok()?;
536            if module_type.is_public_member(name) {
537                Some((var.get_name(), true))
538            } else if module_type.has_private_member(name) {
539                Some((var.get_name(), false))
540            } else {
541                None
542            }
543        })
544    }
545
546    fn is_matching_alias(&self, var1: &Var, var2: &Var) -> bool {
547        var1.name == var2.name
548    }
549
550    pub fn get_matching_alias_signature(&self, var: &Var) -> Option<(Type, Vec<Type>)> {
551        self.aliases()
552            .find(|(var2, _)| self.is_matching_alias(var, var2))
553            .map(|(var2, target_type)| {
554                if var2.is_opaque() {
555                    (var2.clone().to_alias_type(), vec![])
556                } else if let Type::Params(types, _) = var2.get_type() {
557                    (target_type.clone(), types.clone())
558                } else {
559                    panic!("The related type is not Params([...])");
560                }
561            })
562            // Module-internal record aliases are dropped from `aliases()` at
563            // the module boundary for encapsulation, but their names still
564            // appear inside hoisted structural types and exported signatures.
565            // `record_aliases` is the whole-program record registry kept for
566            // codegen (see `merge_record_aliases`) — resolve through it so
567            // structural subtype checks don't collapse such names to `Any`.
568            .or_else(|| {
569                self.record_aliases
570                    .iter()
571                    .find(|(name, _)| *name == var.get_name())
572                    .map(|(_, typ)| (typ.clone(), vec![]))
573            })
574    }
575
576    pub fn variables(&self) -> impl Iterator<Item = &(Var, Type)> + '_ {
577        self.typing_context.variables()
578    }
579
580    pub fn aliases(&self) -> impl Iterator<Item = &(Var, Type)> + '_ {
581        self.typing_context.aliases()
582    }
583
584    /// Generate a fresh rigid generic variable name (immutable builder pattern).
585    pub fn fresh_rigid_name(self) -> (String, Self) {
586        let name = format!("__rigid_{}", self.rigid_counter);
587        (
588            name,
589            Self {
590                rigid_counter: self.rigid_counter + 1,
591                ..self
592            },
593        )
594    }
595
596    /// Register a constraint: rigid variable → interface type.
597    pub fn add_interface_constraint(mut self, rigid_name: String, interface: Type) -> Context {
598        self.interface_constraints.insert(rigid_name, interface);
599        self
600    }
601
602    /// Look up the interface constraint for a rigid variable.
603    pub fn get_interface_constraint(&self, name: &str) -> Option<&Type> {
604        self.interface_constraints.get(name)
605    }
606
607    /// Check if a name is a constrained rigid variable.
608    pub fn is_rigid_constrained(&self, name: &str) -> bool {
609        self.interface_constraints.contains_key(name)
610    }
611
612    pub fn push_var_type(self, lang: Var, typ: Type, context: &Context) -> Context {
613        let reduced_type = typ.reduce(context);
614        let types = reduced_type.extract_types();
615        let new_subtypes = self.subtypes.add_types(&types, context);
616        let var_type = self
617            .typing_context
618            .pipe(|vt| {
619                if reduced_type.is_interface() && lang.is_variable() {
620                    vt.push_interface(lang.clone(), reduced_type, typ.clone(), context)
621                } else {
622                    vt.push_var_type(&[(lang.clone(), typ.clone())])
623                }
624            })
625            .push_types(&types);
626        Context {
627            typing_context: var_type,
628            subtypes: new_subtypes,
629            ..self
630        }
631    }
632
633    pub fn replace_or_push_var_type(self, lang: Var, typ: Type, context: &Context) -> Context {
634        let types = typ.reduce(context).extract_types();
635        let var_type = self
636            .typing_context
637            .clone()
638            .replace_or_push_var_type(&[(lang.clone(), typ.clone())])
639            .push_types(&types);
640        let new_subtypes = self.subtypes.add_types(&types, context);
641        Context {
642            typing_context: var_type,
643            subtypes: new_subtypes,
644            ..self
645        }
646    }
647
648    // Remove variables from the context
649    // For removing added variables for evaluating a function's body
650    pub fn remove_vars(self, vars: &[Var]) -> Context {
651        Context {
652            typing_context: self.typing_context.remove_vars(vars),
653            ..self
654        }
655    }
656
657    pub fn push_types(self, types: &[Type]) -> Self {
658        // The subtype graph is the whole-program registry the transpiler
659        // walks to compute class chains (`get_classes`): every registered
660        // type must be a node there, or values annotated with it lose their
661        // structural supertype classes at runtime dispatch.
662        let new_subtypes = self.subtypes.clone().add_types(types, &self);
663        Self {
664            typing_context: self.typing_context.clone().push_types(types),
665            subtypes: new_subtypes,
666            ..self
667        }
668    }
669
670    /// Hoists auto-generated type-alias registrations from an inner scope's
671    /// context (function body, module body) into this one — see
672    /// `VarType::hoist_aliases`. The hoisted types are also added to the
673    /// subtype graph so structural supertype lookups (S3 class chains)
674    /// keep working outside the scope that registered them.
675    pub fn hoist_aliases(self, inner: &Context) -> Self {
676        let hoisted_types: Vec<Type> = self
677            .typing_context
678            .hoisted_alias_pairs(&inner.typing_context)
679            .into_iter()
680            .map(|(_, typ)| typ)
681            .collect();
682        let new_subtypes = self.subtypes.clone().add_types(&hoisted_types, &self);
683        Self {
684            typing_context: self.typing_context.clone().hoist_aliases(&inner.typing_context),
685            subtypes: new_subtypes,
686            ..self
687        }
688    }
689
690    pub fn get_type_from_existing_variable(&self, var: Var) -> Type {
691        if let Type::UnknownFunction(_) = var.get_type() {
692            var.get_type()
693        } else {
694            self.typing_context
695                .variables()
696                .find(|(v, _)| var.match_with(v, self))
697                .map(|(_, ty)| ty)
698                // Return Any type instead of panicking if variable not found
699                .unwrap_or(&Type::Any(var.get_help_data()))
700                .clone()
701        }
702    }
703
704    pub fn get_true_variable(&self, var: &Var) -> Var {
705        let res = self
706            .typing_context
707            .variables()
708            .find(|(v, _)| var.match_with(v, self))
709            .map(|(v, _)| v);
710        match res {
711            Some(vari) => vari.clone(),
712            _ => {
713                // Return the variable with UnknownFunction type if it's a standard function
714                // Otherwise return with Any type to allow error collection
715                if self.is_an_untyped_function(&var.get_name()) {
716                    var.clone().set_type(Type::UnknownFunction(var.get_help_data()))
717                } else {
718                    var.clone().set_type(Type::Any(var.get_help_data()))
719                }
720            }
721        }
722    }
723
724    fn is_a_standard_function(&self, name: &str) -> bool {
725        !self.typing_context.name_exists_outside_of_std(name)
726    }
727
728    pub fn is_an_untyped_function(&self, name: &str) -> bool {
729        self.is_a_standard_function(name)
730    }
731
732    /// Step ③ (unification_arrays.md): does `t` denote an array with the
733    /// bare-atomic-vector runtime representation? See
734    /// `VarType::atomic_array_elem` — the single representation predicate.
735    pub fn atomic_array_elem(&self, t: &Type) -> Option<Type> {
736        self.typing_context.atomic_array_elem(t)
737    }
738
739    pub fn get_class(&self, t: &Type) -> String {
740        // For a named alias whose underlying type is a record or array, return the alias
741        // name directly. push_types may have also registered the same underlying type with
742        // an auto-generated "Record0"/"Array0" name; searching aliases by type value would
743        // find that first (insertion-order) and return the wrong name.
744        if let Type::Alias(name, _, false, _) = t {
745            if let Some((_, underlying)) = self.aliases().find(|(v, _)| v.get_name() == *name) {
746                if matches!(underlying, Type::Record(_, _) | Type::Vec(_, _, _, _)) {
747                    return "'".to_string() + name + "'";
748                }
749            }
750        }
751        let reduced = t.reduce(self);
752        if matches!(reduced, Type::Any(_)) {
753            if let Type::Alias(name, _, _, _) = t {
754                return "'".to_string() + name + "'";
755            }
756        }
757        self.typing_context.get_class(&reduced)
758    }
759
760    pub fn get_class_unquoted(&self, t: &Type) -> String {
761        // Same rationale as get_class: bypass the record/array alias search for named aliases.
762        if let Type::Alias(name, _, false, _) = t {
763            if let Some((_, underlying)) = self.aliases().find(|(v, _)| v.get_name() == *name) {
764                if matches!(underlying, Type::Record(_, _) | Type::Vec(_, _, _, _)) {
765                    return name.clone();
766                }
767            }
768        }
769        let reduced = t.reduce(self);
770        if matches!(reduced, Type::Any(_)) {
771            if let Type::Alias(name, _, _, _) = t {
772                return name.clone();
773            }
774        }
775        self.typing_context.get_class_unquoted(&reduced)
776    }
777
778    pub fn module_aliases(&self) -> Vec<(Var, Type)> {
779        self.variables()
780            .flat_map(|(_, typ)| typ.clone().to_module_type())
781            .flat_map(|module| module.get_aliases())
782            .collect()
783    }
784
785    pub fn get_type_anotations(&self) -> String {
786        self.aliases()
787            .chain(
788                [
789                    (Var::from_name("Integer"), builder::integer_type_default()),
790                    (Var::from_name("Character"), builder::character_type_default()),
791                    (Var::from_name("Number"), builder::number_type()),
792                    (Var::from_name("Boolean"), builder::boolean_type()),
793                ]
794                .iter(),
795            )
796            .cloned()
797            .chain(self.module_aliases())
798            .filter(|(_, typ)| typ.clone().to_module_type().is_err())
799            // Records that have a user-given alias are excluded: their `as.X` cast
800            // is emitted by the inline constructor/validator pipeline. Anonymous
801            // records (auto-named `Record0`, `Record1`, …) have no constructor, so
802            // they still need their `as.RecordN` annotation generated here.
803            .filter(|(var, typ)| !matches!(typ, Type::Record(_, _)) || is_anonymous_record_name(&var.get_name()))
804            // Aliases whose underlying type still mentions an unresolved generic
805            // (e.g. `type Animator<%T> <- %T & list { ... }`) have no single
806            // fixed runtime class — there's no monomorphization, so a static
807            // `as.Animator` cast can't be generated. Without this, get_class
808            // panics trying to render `%T` as an R class name.
809            .filter(|(_, typ)| !typ.has_generic())
810            .map(|(var, typ)| (typ, var.get_name()))
811            .map(|(typ, name)| {
812                let name0 = if ["Integer", "Character", "Boolean", "Number"].iter().any(|x| name == *x) {
813                    format!("'{}', ", name)
814                } else {
815                    Default::default()
816                };
817                let class_str = self.get_class(&typ);
818                let prefix = if name0.is_empty() && class_str != format!("'{}'", name) {
819                    format!("'{}', ", name)
820                } else {
821                    name0
822                };
823                format!(
824                    "as.{} <- function(x) x |> struct(c({}{}, {}))",
825                    name,
826                    prefix,
827                    class_str,
828                    self.get_classes(&typ).unwrap()
829                )
830            })
831            .collect::<Vec<_>>()
832            .join("\n")
833    }
834
835    pub fn get_type_anotation(&self, t: &Type) -> String {
836        self.typing_context.get_type_anotation(t)
837    }
838
839    pub fn get_type_anotation_no_parentheses(&self, t: &Type) -> String {
840        self.typing_context.get_type_anotation_no_parentheses(t)
841    }
842
843    /// Does `name` resolve (through alias hops) to the stdlib `Foreign<T>`
844    /// alias? See `VarType::resolves_to_foreign` / `get_type_anotation` for
845    /// the rationale (soundness_transpilation.md Phase D).
846    pub fn resolves_to_foreign_alias(&self, name: &str) -> bool {
847        self.typing_context.resolves_to_foreign(name)
848    }
849
850    pub fn get_classes(&self, t: &Type) -> Option<String> {
851        let mut classes: Vec<String> = self
852            .subtypes
853            .get_supertypes(t, self)
854            .iter()
855            .filter(|typ| (*typ).clone().to_module_type().is_err())
856            .filter(|typ| !typ.is_empty())
857            // A supertype that still mentions an unresolved generic (e.g. a
858            // record-kinded `%T` picked up structurally from a generic alias
859            // like `Animator<%T> <- %T & list {...}`) has no R class name —
860            // it's a compile-time-only constraint, never render it.
861            .filter(|typ| !typ.has_generic())
862            .map(|typ| self.get_class(typ))
863            .collect();
864        // A record's own class chain gets interface names injected ad hoc
865        // where its constructor is generated (transpiling/mod.rs, "Interfaces
866        // as classes"), keyed on structural interface satisfaction. Array
867        // aliases (`ArrayN`) never went through an equivalent step: an array
868        // of `Point` never gained `ArrayK` (registered for `[N, Eq]`) in its
869        // own class chain, even though `Point` satisfies `Eq` — so a function
870        // whose first param is `[N, Eq]` had no runtime class to dispatch on
871        // for a real `[N, Point]` value. Mirror the record injection here,
872        // generically, for any array whose element structurally satisfies
873        // another registered array's (pure-interface) element type.
874        if let Type::Vec(_, _, elem, _) = t {
875            let mut iface_array_classes: Vec<String> = self
876                .aliases()
877                .filter_map(|(_, other_typ)| match &other_typ {
878                    Type::Vec(_, _, other_elem, _)
879                        if facets::interface_facet(self, other_elem).is_some()
880                            && elem.is_subtype_raw(other_elem, self) =>
881                    {
882                        Some(self.get_class(&other_typ))
883                    }
884                    _ => None,
885                })
886                .filter(|cls| !classes.contains(cls))
887                .collect();
888            iface_array_classes.sort();
889            iface_array_classes.dedup();
890            classes.extend(iface_array_classes);
891        }
892        let res = classes.join(", ");
893        if res.is_empty() {
894            Some("'None'".to_string())
895        } else {
896            Some(res)
897        }
898    }
899
900    pub fn get_functions(&self, var1: Var) -> Vec<(Var, Type)> {
901        self.typing_context
902            .variables()
903            .filter(|(var2, typ)| {
904                let reduced_type1 = var1.get_type().reduce(self);
905                let reduced_type2 = var2.get_type().reduce(self);
906                var1.get_name() == var2.get_name()
907                    && typ.is_function()
908                    && reduced_type1.is_subtype(&reduced_type2, self).0
909            })
910            .cloned()
911            .collect()
912    }
913
914    pub fn get_all_generic_functions(&self) -> Vec<(Var, Type)> {
915        let res = self
916            .typing_context
917            .variables()
918            .filter(|(_, typ)| typ.is_function())
919            .filter(|(var, _)| not_in_blacklist(&var.get_name()))
920            .filter(|(var, _)| !var.get_type().is_any())
921            // `@extern`/`@importFrom` names call an existing R function
922            // directly by (possibly package-qualified) name — never through
923            // `UseMethod` dispatch. Emitting the standard `name <- function(x,
924            // ...) UseMethod('name', x)` stub for them here would shadow the
925            // real R function at exactly the call site meant to reach it (the
926            // `nlevels` bug's shape, see the std.R hard rule in CLAUDE.md),
927            // discovered while wiring up the Phase D interop matrix
928            // (soundness_transpilation.md) for a bare `@extern base::readRDS`.
929            .filter(|(var, _)| !self.is_extern_fn(&var.get_name()))
930            .filter(|(var, _)| !self.is_import_from_fn(&var.get_name()))
931            .collect::<HashSet<_>>();
932        let mut result: Vec<(Var, Type)> = res
933            .iter()
934            .map(|(var, typ)| (var.clone().add_backticks_if_percent(), typ.clone()))
935            .collect();
936        // Stable order: the list is rendered into generic_functions.R, which
937        // must not reshuffle between builds (HashSet iteration is random).
938        result.sort_by_key(|(var, _)| var.get_name());
939        result
940    }
941
942    pub fn get_first_matching_function(&self, var1: Var) -> Type {
943        let res = self.typing_context.variables().find(|(var2, typ)| {
944            let reduced_type1 = var1.get_type().reduce(self);
945            let reduced_type2 = var2.get_type().reduce(self);
946            var1.get_name() == var2.get_name()
947                && typ.is_function()
948                && (reduced_type1.is_subtype(&reduced_type2, self).0 || reduced_type1.is_upperrank_of(&reduced_type2))
949        });
950        if let Some(res) = res {
951            res.1.clone()
952        } else {
953            self.typing_context
954                .standard_library()
955                .iter()
956                .find(|(var2, _)| var2.get_name() == var1.get_name())
957                .unwrap_or_else(|| {
958                    panic!(
959                        "Can't find var {} in the context:\n {}",
960                        var1,
961                        self.display_typing_context()
962                    )
963                })
964                .1
965                .clone()
966        }
967    }
968
969    pub fn get_matching_typed_functions(&self, var1: Var) -> Vec<Type> {
970        self.typing_context
971            .variables()
972            .filter(|(var2, typ)| {
973                let reduced_type1 = var1.get_type().reduce(self);
974                let reduced_type2 = var2.get_type().reduce(self);
975                var1.get_name() == var2.get_name()
976                    && typ.is_function()
977                    && (reduced_type1.is_subtype(&reduced_type2, self).0
978                        || reduced_type1.is_upperrank_of(&reduced_type2))
979            })
980            .map(|(_, typ)| typ.clone())
981            .collect::<Vec<_>>()
982    }
983
984    pub fn get_matching_untyped_functions(&self, var: Var) -> Result<Vec<Type>, String> {
985        let name1 = var.get_name();
986        let std_lib = self.typing_context.standard_library();
987        let res = std_lib
988            .iter()
989            .find(|(var2, _)| var2.get_name() == name1)
990            .map(|(_, typ)| typ);
991        match res {
992            Some(val) => Ok(vec![val.clone()]),
993            _ => Err(format!(
994                "Can't find var {} in the context:\n {}",
995                var,
996                self.display_typing_context()
997            )),
998        }
999    }
1000
1001    pub fn get_matching_functions(&self, var: Var) -> Result<Vec<Type>, String> {
1002        let res = self.get_matching_typed_functions(var.clone());
1003        if res.is_empty() {
1004            self.get_matching_untyped_functions(var)
1005        } else {
1006            Ok(res)
1007        }
1008    }
1009
1010    pub fn get_type_from_class(&self, class: &str) -> Type {
1011        self.typing_context.get_type_from_class(class)
1012    }
1013
1014    pub fn add_arg_types(&self, params: &[ArgumentType]) -> Context {
1015        let param_types = params
1016            .iter()
1017            .map(|arg_typ| reduce_type(self, &arg_typ.get_type()).for_var())
1018            .map(|typ| match typ.to_owned() {
1019                Type::Function(typs, _, _) => {
1020                    if !typs.is_empty() {
1021                        typs[0].get_type()
1022                    } else {
1023                        typ
1024                    }
1025                }
1026                t => t,
1027            })
1028            .collect::<Vec<_>>();
1029        params
1030            .iter()
1031            .zip(param_types.clone())
1032            .map(|(arg_typ, par_typ): (&ArgumentType, Type)| {
1033                (
1034                    Var::from_name(&arg_typ.get_argument_str()).set_type(reduce_type(self, &par_typ)),
1035                    reduce_type(self, &arg_typ.get_type()),
1036                )
1037            })
1038            .fold(self.clone(), |cont: Context, (var, typ): (Var, Type)| {
1039                cont.clone().push_var_type(var, typ, &cont)
1040            })
1041    }
1042
1043    pub fn set_environment(&self, e: Environment) -> Context {
1044        Context {
1045            config: self.config.set_environment(e),
1046            ..self.clone()
1047        }
1048    }
1049
1050    pub fn display_typing_context(&self) -> String {
1051        let res = self
1052            .variables()
1053            .chain(self.aliases())
1054            .map(|(var, typ)| format!("{} ==> {}", var, typ))
1055            .collect::<Vec<_>>()
1056            .join("\n");
1057        format!("CONTEXT:\n{}", res)
1058    }
1059
1060    pub fn error(&self, msg: String) -> String {
1061        format!("{}{}", msg, self.display_typing_context())
1062    }
1063
1064    pub fn push_alias(self, alias_name: String, typ: Type) -> Self {
1065        Context {
1066            typing_context: self.typing_context.push_alias(alias_name, typ),
1067            ..self
1068        }
1069    }
1070
1071    /// Register a user-declared `typeconstructor` in the registry.
1072    pub fn push_type_constructor(self, name: String, parameters: Vec<Type>, category: ConstructorCategory) -> Self {
1073        let mut type_constructors = self.type_constructors.clone();
1074        // Last declaration wins: drop any previous entry with the same name.
1075        type_constructors.retain(|(n, _, _)| n != &name);
1076        type_constructors.push((name, parameters, category));
1077        Context {
1078            type_constructors,
1079            ..self
1080        }
1081    }
1082
1083    /// Look up a declared `typeconstructor` by name.
1084    pub fn get_type_constructor(&self, name: &str) -> Option<&(String, Vec<Type>, ConstructorCategory)> {
1085        self.type_constructors.iter().find(|(n, _, _)| n == name)
1086    }
1087
1088    /// Register a `type X <- list { ... }` record alias in the whole-program
1089    /// registry, regardless of the current module scope. No-op for non-record
1090    /// aliases. Last declaration for a given name wins.
1091    pub fn push_record_alias(self, name: String, typ: Type) -> Self {
1092        if !matches!(typ, Type::Record(_, _)) {
1093            return self;
1094        }
1095        let mut record_aliases = self.record_aliases.clone();
1096        record_aliases.retain(|(n, _)| n != &name);
1097        record_aliases.push((name, typ));
1098        Context { record_aliases, ..self }
1099    }
1100
1101    /// Merge another context's whole-program record-alias registry into this
1102    /// one. Used at module boundaries, where the rest of the inner typing
1103    /// context is intentionally discarded for encapsulation but this registry
1104    /// must still bubble up (see `Lang::Module` in `processes::type_checking`).
1105    pub fn merge_record_aliases(self, other: &Context) -> Self {
1106        let mut record_aliases = self.record_aliases.clone();
1107        for (name, typ) in &other.record_aliases {
1108            if !record_aliases.iter().any(|(n, _)| n == name) {
1109                record_aliases.push((name.clone(), typ.clone()));
1110            }
1111        }
1112        Context { record_aliases, ..self }
1113    }
1114
1115    /// Record that `method_name` on `type_name` was auto-generated by named type
1116    /// embedding (`embed field: Type`), forwarded from `field_name`. See
1117    /// `processes::type_checking::embedding`.
1118    pub fn push_embedded_method(self, type_name: String, method_name: String, field_name: String) -> Self {
1119        let mut embedded_methods = self.embedded_methods.clone();
1120        embedded_methods.push((type_name, method_name, field_name));
1121        Context {
1122            embedded_methods,
1123            ..self
1124        }
1125    }
1126
1127    /// If `method_name` on `type_name` was inherited via named type embedding,
1128    /// return the source field name it was forwarded from.
1129    pub fn get_embedded_method(&self, type_name: &str, method_name: &str) -> Option<String> {
1130        self.embedded_methods
1131            .iter()
1132            .find(|(t, m, _)| t == type_name && m == method_name)
1133            .map(|(_, _, field)| field.clone())
1134    }
1135
1136    pub fn push_alias2(self, alias_var: Var, typ: Type) -> Self {
1137        Context {
1138            typing_context: self.typing_context.push_alias2(alias_var, typ),
1139            ..self
1140        }
1141    }
1142
1143    pub fn in_a_project(&self) -> bool {
1144        self.config.environment == Environment::Project
1145    }
1146
1147    pub fn get_unification_map(&self, entered_types: &[Type], param_types: &[Type]) -> Option<UnificationMap> {
1148        let res = entered_types
1149            .iter()
1150            .zip(param_types.iter())
1151            .map(|(val_typ, par_typ)| match_types_to_generic(self, &val_typ.clone(), par_typ))
1152            .collect::<Option<Vec<_>>>();
1153
1154        res.map(|vec| vec.iter().flatten().cloned().collect::<Vec<_>>())
1155            .and_then(UnificationMap::try_new)
1156    }
1157
1158    fn s3_type_definition(&self, var: &Var, typ: &Type) -> String {
1159        let first_part = format!("{} <- function(x) x |> ", var.get_name());
1160        match typ {
1161            Type::RClass(v, _) => format!(
1162                "{} struct(c({}))",
1163                first_part,
1164                v.iter().cloned().collect::<Vec<_>>().join(", ")
1165            ),
1166            _ => {
1167                let class = if typ.is_primitive() {
1168                    format!("'{}'", var.get_name())
1169                } else {
1170                    self.get_class(typ)
1171                };
1172                format!("{} struct(c({}))", first_part, class)
1173            }
1174        }
1175    }
1176
1177    fn get_primitive_type_definition(&self) -> Vec<String> {
1178        let primitives = [
1179            ("Integer", builder::integer_type_default()),
1180            ("Character", builder::character_type_default()),
1181            ("Number", builder::number_type()),
1182            ("Boolean", builder::boolean_type()),
1183        ];
1184        let new_context = self
1185            .clone()
1186            .push_types(&primitives.iter().map(|(_, typ)| typ).cloned().collect::<Vec<_>>());
1187        primitives
1188            .iter()
1189            .map(|(name, prim)| {
1190                (
1191                    name,
1192                    new_context.get_classes(prim).unwrap(),
1193                    new_context.get_class(prim),
1194                )
1195            })
1196            .map(|(name, cls, cl)| format!("{} <- function(x) x |> struct(c({}, {}))", name, cls, cl))
1197            .collect::<Vec<_>>()
1198    }
1199
1200    pub fn get_related_functions(&self, typ: &Type, functions: &VarFunction) -> Vec<Lang> {
1201        let names = self.typing_context.get_related_functions(typ);
1202        functions.get_bodies(&names)
1203    }
1204
1205    pub fn get_functions_from_type(&self, typ: &Type) -> Vec<(Var, Type)> {
1206        // `var.get_type()` (the parser-set "related type" marking a function as
1207        // a dispatchable method, e.g. `let animate <- fn(self: Circle, …)`) is
1208        // the primary signal, matched either exactly or via reduced forms — a
1209        // caller may hold a structurally-identical but alias-stripped type
1210        // (e.g. an array literal's element type, which `typing_container`
1211        // reduces away from its alias for homogeneity checking — see
1212        // `[Object]`/`[Circle]` array-covariance).
1213        let reduced_typ = reduce_type(self, typ);
1214        self.variables()
1215            .filter(|&(var, typ2)| {
1216                if !typ2.is_function() {
1217                    return false;
1218                }
1219                if var.get_type() == *typ || reduce_type(self, &var.get_type()) == reduced_typ {
1220                    return true;
1221                }
1222                // Fallback: `var.get_type()` comes back `Empty` for a function
1223                // re-imported across a module boundary — `Lang::Module`'s
1224                // `pub_arg_types` export rebuilds a fresh `Var` from just the
1225                // exported name, losing the parser's related-type marker even
1226                // though the function itself is a perfectly good method.
1227                // The function's own declared first parameter can't be lost
1228                // this way, so use it as the structural anchor instead:
1229                // interface satisfaction in TypR is meant to be purely
1230                // structural, not keyed on a bookkeeping field surviving a
1231                // module re-export.
1232                typ2.get_first_parameter()
1233                    .is_some_and(|p| p == *typ || reduce_type(self, &p) == reduced_typ)
1234            })
1235            .cloned()
1236            .collect()
1237    }
1238
1239    pub fn get_functions_from_name(&self, name: &str) -> Vec<(Var, Type)> {
1240        self.typing_context
1241            .entries_named(name)
1242            .into_iter()
1243            .filter(|(_, typ2)| typ2.is_function())
1244            .collect()
1245    }
1246
1247    pub fn get_type_definition(&self, _functions: &VarFunction) -> String {
1248        match self.get_target_language() {
1249            TargetLanguage::R => self
1250                .typing_context
1251                .aliases
1252                .iter()
1253                .map(|(var, typ)| self.s3_type_definition(var, typ))
1254                .chain(self.get_primitive_type_definition().iter().cloned())
1255                .collect::<Vec<_>>()
1256                .join("\n"),
1257            TargetLanguage::JS => {
1258                todo!();
1259            }
1260        }
1261    }
1262
1263    pub fn update_variable(self, var: Var) -> Self {
1264        Self {
1265            typing_context: self.typing_context.update_variable(var),
1266            ..self
1267        }
1268    }
1269
1270    pub fn set_target_language(self, language: TargetLanguage) -> Self {
1271        Self {
1272            config: self.config.set_target_language(language),
1273            typing_context: self.typing_context.source(language),
1274            ..self
1275        }
1276    }
1277
1278    pub fn set_default_var_types(self) -> Self {
1279        Self {
1280            typing_context: self.typing_context.set_default_var_types(),
1281            ..self
1282        }
1283    }
1284
1285    pub fn get_target_language(&self) -> TargetLanguage {
1286        self.config.get_target_language()
1287    }
1288
1289    pub fn set_new_aliase_signature(self, alias: &str, related_type: Type) -> Self {
1290        let alias = Var::from_type(alias.parse::<Type>().unwrap()).unwrap();
1291        self.clone().push_alias2(alias, related_type)
1292    }
1293
1294    pub fn extract_module_as_vartype(&self, module_name: &str) -> Self {
1295        let typ = self
1296            .get_type_from_variable(&Var::from_name(module_name))
1297            .expect("The module name was not found");
1298        let empty_context = Context::default();
1299        let new_context = match typ.clone() {
1300            Type::Module(args, _, _) => {
1301                args.iter()
1302                    .rev()
1303                    .map(|arg_type| (Var::try_from(arg_type.0.clone()).unwrap(), arg_type.1.clone())) //TODO: Differenciate between pushing variable and
1304                    //aliases
1305                    .fold(empty_context.clone(), |acc, (var, typ)| {
1306                        acc.clone().push_var_type(var, typ, &acc)
1307                    })
1308            }
1309            _ => panic!("{} is not a module", module_name),
1310        };
1311        new_context
1312            .clone()
1313            .push_var_type(Var::from_name(module_name), typ, &new_context)
1314    }
1315
1316    pub fn get_vartype(&self) -> VarType {
1317        self.clone().typing_context
1318    }
1319
1320    pub fn get_environment(&self) -> Environment {
1321        self.config.environment
1322    }
1323    pub fn extend_typing_context(self, var_types: VarType) -> Self {
1324        Self {
1325            typing_context: self.typing_context + var_types,
1326            ..self
1327        }
1328    }
1329}
1330
1331impl Add for Context {
1332    type Output = Self;
1333
1334    fn add(self, other: Self) -> Self::Output {
1335        let mut type_constructors = self.type_constructors;
1336        for (name, params, cat) in other.type_constructors {
1337            type_constructors.retain(|(n, _, _)| n != &name);
1338            type_constructors.push((name, params, cat));
1339        }
1340        let mut interface_constraints = self.interface_constraints;
1341        interface_constraints.extend(other.interface_constraints);
1342        let rigid_counter = self.rigid_counter.max(other.rigid_counter);
1343        let mut test_preamble = self.test_preamble;
1344        test_preamble.extend(other.test_preamble);
1345        let mut record_aliases = self.record_aliases;
1346        for entry in other.record_aliases {
1347            if !record_aliases.contains(&entry) {
1348                record_aliases.push(entry);
1349            }
1350        }
1351        let mut embedded_methods = self.embedded_methods;
1352        for entry in other.embedded_methods {
1353            if !embedded_methods.contains(&entry) {
1354                embedded_methods.push(entry);
1355            }
1356        }
1357        let mut extern_fns = self.extern_fns;
1358        for entry in other.extern_fns {
1359            if !extern_fns.iter().any(|(n, _)| n == &entry.0) {
1360                extern_fns.push(entry);
1361            }
1362        }
1363        let mut import_from_fns = self.import_from_fns;
1364        for entry in other.import_from_fns {
1365            if !import_from_fns.iter().any(|(n, _)| n == &entry.0) {
1366                import_from_fns.push(entry);
1367            }
1368        }
1369        let mut signature_fns = self.signature_fns;
1370        for name in other.signature_fns {
1371            if !signature_fns.contains(&name) {
1372                signature_fns.push(name);
1373            }
1374        }
1375        let mut vectorizable_fns = self.vectorizable_fns;
1376        for (name, is_vec) in other.vectorizable_fns {
1377            match vectorizable_fns.iter_mut().find(|(n, _)| n == &name) {
1378                Some(entry) => entry.1 = entry.1 && is_vec,
1379                None => vectorizable_fns.push((name, is_vec)),
1380            }
1381        }
1382        let mut module_inner_contexts = self.module_inner_contexts;
1383        module_inner_contexts.extend(other.module_inner_contexts);
1384        let mut processed_modules = self.processed_modules;
1385        processed_modules.extend(other.processed_modules);
1386        let mut modules_in_progress = self.modules_in_progress;
1387        modules_in_progress.extend(other.modules_in_progress);
1388        Context {
1389            typing_context: self.typing_context + other.typing_context,
1390            subtypes: self.subtypes + other.subtypes,
1391            type_constructors,
1392            interface_constraints,
1393            rigid_counter,
1394            record_aliases,
1395            embedded_methods,
1396            test_preamble,
1397            self_type: None,
1398            expected_return_type: None,
1399            extern_fns,
1400            import_from_fns,
1401            signature_fns,
1402            vectorizable_fns,
1403            config: self.config,
1404            module_inner_contexts,
1405            processed_modules,
1406            modules_in_progress,
1407        }
1408    }
1409}
1410
1411#[cfg(test)]
1412mod tests {
1413    use super::*;
1414
1415    #[test]
1416    fn test_default_context1() {
1417        let context = Context::default();
1418        assert!(!context.display_typing_context().is_empty());
1419    }
1420
1421    #[test]
1422    fn test_record_nests_under_grecord_sentinel() {
1423        let ctx = Context::default();
1424        let rec = builder::record_type(&[("x".to_string(), builder::integer_type_default())]);
1425        let graph = ctx.subtypes.clone().add_type(rec.clone(), &ctx);
1426        let supers = graph.get_supertypes(&rec, &ctx);
1427        assert!(
1428            supers.iter().any(|t| matches!(t, Type::KindedGen(Kind::Record, _, _))),
1429            "a record must nest under the GRecord (%_) sentinel; supers = {:?}",
1430            supers
1431        );
1432        assert!(
1433            supers.iter().any(|t| matches!(t, Type::Generic(_, _))),
1434            "GRecord must itself sit under the bare Generic sentinel; supers = {:?}",
1435            supers
1436        );
1437    }
1438
1439    #[test]
1440    fn test_generic_sentinels_absent_from_r_classes() {
1441        let ctx = Context::default();
1442        let rec = builder::record_type(&[("x".to_string(), builder::integer_type_default())]);
1443        let graph = ctx.subtypes.clone().add_type(rec.clone(), &ctx);
1444        let ctx = ctx.with_subtypes(graph);
1445        let classes = ctx.get_classes(&rec).unwrap();
1446        assert!(
1447            !classes.contains("GRecord") && !classes.contains('%') && !classes.contains("Generic"),
1448            "generic sentinels must be filtered out of generated R classes, got: {}",
1449            classes
1450        );
1451    }
1452}