1use std::collections::{HashMap, HashSet};
6
7use crate::apidoc::ApidocDict;
8use crate::ast::*;
9use crate::fields_dict::FieldsDict;
10use crate::inline_fn::InlineFnDict;
11use crate::intern::{InternedStr, StringInterner};
12use crate::parser::parse_type_from_string;
13use crate::rust_decl::RustDeclDict;
14use crate::source::{FileRegistry, SourceLocation};
15use crate::type_env::{TypeEnv, TypeConstraint as TypeEnvConstraint};
16use crate::type_repr::{
17 CTypeSource, CTypeSpecs, CDerivedType, InferredType,
18 RustTypeRepr, RustTypeSource, TypeRepr,
19};
20use crate::unified_type::{IntSize, UnifiedType};
21
22fn leftmost_param_ident(
30 expr: &Expr,
31 params: &HashSet<InternedStr>,
32) -> Option<(InternedStr, ExprId)> {
33 let mut cur = expr;
34 loop {
35 match &cur.kind {
36 ExprKind::Member { expr: base, .. }
37 | ExprKind::PtrMember { expr: base, .. }
38 | ExprKind::Deref(base)
39 | ExprKind::Cast { expr: base, .. } => cur = base,
40 ExprKind::StmtExpr(compound) => {
41 if let Some(inner) = mutable_ptr_inner_expr(compound) {
42 cur = inner;
43 } else {
44 return None;
45 }
46 }
47 ExprKind::Ident(name) if params.contains(name) => {
48 return Some((*name, cur.id));
49 }
50 _ => return None,
51 }
52 }
53}
54
55fn mutable_ptr_inner_expr(compound: &CompoundStmt) -> Option<&Expr> {
59 if compound.items.len() != 2 {
60 return None;
61 }
62 let decl = match &compound.items[0] {
63 BlockItem::Decl(d) => d,
64 _ => return None,
65 };
66 if decl.declarators.len() != 1 {
67 return None;
68 }
69 let init_decl = &decl.declarators[0];
70 let declared_name = init_decl.declarator.name?;
71 let init_expr = match init_decl.init.as_ref()? {
72 Initializer::Expr(e) => e.as_ref(),
73 _ => return None,
74 };
75 let last_expr = match &compound.items[1] {
76 BlockItem::Stmt(Stmt::Expr(Some(e), _)) => e,
77 _ => return None,
78 };
79 if let ExprKind::Ident(name) = &last_expr.kind {
80 if *name == declared_name {
81 return Some(init_expr);
82 }
83 }
84 None
85}
86
87fn is_anonymous_struct_or_union_field(t: &TypeRepr) -> bool {
96 if let TypeRepr::CType { specs, derived, .. } = t {
97 if !derived.is_empty() {
98 return false;
99 }
100 return matches!(
101 specs,
102 crate::type_repr::CTypeSpecs::Struct { name: None, .. }
103 );
104 }
105 false
106}
107
108fn extract_struct_name_str(t: &TypeRepr, interner: &crate::intern::StringInterner) -> Option<String> {
115 use crate::type_repr::{CTypeSpecs, RustTypeRepr};
116 match t {
117 TypeRepr::CType { specs, derived, .. } if derived.is_empty() => match specs {
118 CTypeSpecs::TypedefName(n) => Some(interner.get(*n).to_string()),
119 CTypeSpecs::Struct { name: Some(n), .. } => Some(interner.get(*n).to_string()),
120 _ => None,
121 },
122 TypeRepr::RustType { repr, .. } => match repr {
123 RustTypeRepr::Named(s) => Some(s.clone()),
124 _ => None,
125 },
126 TypeRepr::Inferred(inferred) => {
127 inferred.resolved_type().and_then(|t| extract_struct_name_str(t, interner))
128 }
129 _ => None,
130 }
131}
132
133fn wrap_with_outer_pointer(ty: TypeRepr, is_const: bool) -> TypeRepr {
138 use crate::type_repr::CDerivedType;
139 match ty {
140 TypeRepr::CType { specs, mut derived, source } => {
141 derived.push(CDerivedType::Pointer { is_const, is_volatile: false, is_restrict: false });
142 TypeRepr::CType { specs, derived, source }
143 }
144 other => other,
145 }
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
150pub struct TypeVar(usize);
151
152#[derive(Debug, Clone)]
154pub enum TypeConstraint {
155 FunctionArg {
157 var: TypeVar,
158 func_name: InternedStr,
159 arg_index: usize,
160 },
161 HasField {
163 var: TypeVar,
164 field: InternedStr,
165 },
166}
167
168#[derive(Debug, Clone, PartialEq)]
170pub enum Type {
171 Void,
173 Char,
175 SignedChar,
177 UnsignedChar,
179 Short,
181 UnsignedShort,
183 Int,
185 UnsignedInt,
187 Long,
189 UnsignedLong,
191 LongLong,
193 UnsignedLongLong,
195 Float,
197 Double,
199 LongDouble,
201 Bool,
203 Int128,
205 UnsignedInt128,
207 Pointer(Box<Type>, TypeQualifiers),
209 Array(Box<Type>, Option<usize>),
211 Function {
213 return_type: Box<Type>,
214 params: Vec<Type>,
215 variadic: bool,
216 },
217 Struct {
219 name: Option<InternedStr>,
220 members: Option<Vec<(InternedStr, Type)>>,
222 },
223 Union {
225 name: Option<InternedStr>,
226 members: Option<Vec<(InternedStr, Type)>>,
227 },
228 Enum {
230 name: Option<InternedStr>,
231 },
232 TypedefName(InternedStr),
234 Unknown,
236}
237
238impl Type {
239 pub fn display(&self, interner: &StringInterner) -> String {
241 match self {
242 Type::Void => "void".to_string(),
243 Type::Char => "char".to_string(),
244 Type::SignedChar => "signed char".to_string(),
245 Type::UnsignedChar => "unsigned char".to_string(),
246 Type::Short => "short".to_string(),
247 Type::UnsignedShort => "unsigned short".to_string(),
248 Type::Int => "int".to_string(),
249 Type::UnsignedInt => "unsigned int".to_string(),
250 Type::Long => "long".to_string(),
251 Type::UnsignedLong => "unsigned long".to_string(),
252 Type::LongLong => "long long".to_string(),
253 Type::UnsignedLongLong => "unsigned long long".to_string(),
254 Type::Float => "float".to_string(),
255 Type::Double => "double".to_string(),
256 Type::LongDouble => "long double".to_string(),
257 Type::Bool => "_Bool".to_string(),
258 Type::Int128 => "__int128".to_string(),
259 Type::UnsignedInt128 => "unsigned __int128".to_string(),
260 Type::Pointer(inner, quals) => {
261 let mut s = inner.display(interner);
262 s.push('*');
263 if quals.is_const {
264 s.push_str(" const");
265 }
266 if quals.is_volatile {
267 s.push_str(" volatile");
268 }
269 if quals.is_restrict {
270 s.push_str(" restrict");
271 }
272 s
273 }
274 Type::Array(inner, size) => {
275 let inner_s = inner.display(interner);
276 match size {
277 Some(n) => format!("{}[{}]", inner_s, n),
278 None => format!("{}[]", inner_s),
279 }
280 }
281 Type::Function { return_type, params, variadic } => {
282 let params_s: Vec<_> = params.iter()
283 .map(|p| p.display(interner))
284 .collect();
285 let mut s = format!("(function {} ({}))", return_type.display(interner), params_s.join(", "));
286 if *variadic {
287 s = s.replace("))", ", ...))");
288 }
289 s
290 }
291 Type::Struct { name, .. } => {
292 match name {
293 Some(n) => format!("struct {}", interner.get(*n)),
294 None => "struct <anonymous>".to_string(),
295 }
296 }
297 Type::Union { name, .. } => {
298 match name {
299 Some(n) => format!("union {}", interner.get(*n)),
300 None => "union <anonymous>".to_string(),
301 }
302 }
303 Type::Enum { name } => {
304 match name {
305 Some(n) => format!("enum {}", interner.get(*n)),
306 None => "enum <anonymous>".to_string(),
307 }
308 }
309 Type::TypedefName(name) => interner.get(*name).to_string(),
310 Type::Unknown => "<unknown>".to_string(),
311 }
312 }
313
314 pub fn is_integer(&self) -> bool {
316 matches!(
317 self,
318 Type::Char
319 | Type::SignedChar
320 | Type::UnsignedChar
321 | Type::Short
322 | Type::UnsignedShort
323 | Type::Int
324 | Type::UnsignedInt
325 | Type::Long
326 | Type::UnsignedLong
327 | Type::LongLong
328 | Type::UnsignedLongLong
329 | Type::Bool
330 | Type::Int128
331 | Type::UnsignedInt128
332 | Type::Enum { .. }
333 )
334 }
335
336 pub fn is_floating(&self) -> bool {
338 matches!(self, Type::Float | Type::Double | Type::LongDouble)
339 }
340
341 pub fn is_arithmetic(&self) -> bool {
343 self.is_integer() || self.is_floating()
344 }
345
346 pub fn is_pointer(&self) -> bool {
348 matches!(self, Type::Pointer(_, _))
349 }
350
351 pub fn to_unified(&self, interner: &StringInterner) -> UnifiedType {
353 match self {
354 Type::Void => UnifiedType::Void,
355 Type::Bool => UnifiedType::Bool,
356
357 Type::Char => UnifiedType::Char { signed: None },
358 Type::SignedChar => UnifiedType::Char { signed: Some(true) },
359 Type::UnsignedChar => UnifiedType::Char { signed: Some(false) },
360
361 Type::Short => UnifiedType::Int { signed: true, size: IntSize::Short },
362 Type::UnsignedShort => UnifiedType::Int { signed: false, size: IntSize::Short },
363 Type::Int => UnifiedType::Int { signed: true, size: IntSize::Int },
364 Type::UnsignedInt => UnifiedType::Int { signed: false, size: IntSize::Int },
365 Type::Long => UnifiedType::Int { signed: true, size: IntSize::Long },
366 Type::UnsignedLong => UnifiedType::Int { signed: false, size: IntSize::Long },
367 Type::LongLong => UnifiedType::Int { signed: true, size: IntSize::LongLong },
368 Type::UnsignedLongLong => UnifiedType::Int { signed: false, size: IntSize::LongLong },
369 Type::Int128 => UnifiedType::Int { signed: true, size: IntSize::Int128 },
370 Type::UnsignedInt128 => UnifiedType::Int { signed: false, size: IntSize::Int128 },
371
372 Type::Float => UnifiedType::Float,
373 Type::Double => UnifiedType::Double,
374 Type::LongDouble => UnifiedType::LongDouble,
375
376 Type::Pointer(inner, quals) => UnifiedType::Pointer {
377 inner: Box::new(inner.to_unified(interner)),
378 is_const: quals.is_const,
379 },
380
381 Type::Array(inner, size) => UnifiedType::Array {
382 inner: Box::new(inner.to_unified(interner)),
383 size: *size,
384 },
385
386 Type::Struct { name: Some(n), .. } => {
387 UnifiedType::Named(interner.get(*n).to_string())
388 }
389 Type::Struct { name: None, .. } => UnifiedType::Unknown,
390
391 Type::Union { name: Some(n), .. } => {
392 UnifiedType::Named(interner.get(*n).to_string())
393 }
394 Type::Union { name: None, .. } => UnifiedType::Unknown,
395
396 Type::Enum { name: Some(n) } => {
397 UnifiedType::Named(interner.get(*n).to_string())
398 }
399 Type::Enum { name: None } => UnifiedType::Int { signed: true, size: IntSize::Int },
400
401 Type::TypedefName(name) => {
402 UnifiedType::Named(interner.get(*name).to_string())
403 }
404
405 Type::Function { .. } => UnifiedType::Unknown, Type::Unknown => UnifiedType::Unknown,
408 }
409 }
410}
411
412#[derive(Debug, Clone)]
414pub struct Symbol {
415 pub name: InternedStr,
417 pub ty: Type,
419 pub loc: SourceLocation,
421 pub kind: SymbolKind,
423}
424
425#[derive(Debug, Clone, PartialEq)]
427pub enum SymbolKind {
428 Variable,
430 Function,
432 Typedef,
434 EnumConstant(i64),
436}
437
438#[derive(Debug)]
440pub struct Scope {
441 symbols: HashMap<InternedStr, Symbol>,
443 parent: Option<ScopeId>,
445}
446
447impl Scope {
448 fn new(parent: Option<ScopeId>) -> Self {
449 Self {
450 symbols: HashMap::new(),
451 parent,
452 }
453 }
454}
455
456#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
458pub struct ScopeId(usize);
459
460pub struct SemanticAnalyzer<'a> {
462 interner: &'a StringInterner,
464 scopes: Vec<Scope>,
466 current_scope: ScopeId,
468 struct_defs: HashMap<InternedStr, Vec<(InternedStr, Type)>>,
470 union_defs: HashMap<InternedStr, Vec<(InternedStr, Type)>>,
472 typedef_defs: HashMap<InternedStr, Type>,
474 apidoc: Option<&'a ApidocDict>,
476 fields_dict: Option<&'a FieldsDict>,
478 rust_decl_dict: Option<&'a RustDeclDict>,
480 inline_fn_dict: Option<&'a InlineFnDict>,
482 type_vars: HashMap<InternedStr, TypeVar>,
484 next_type_var: usize,
486 constraints: Vec<TypeConstraint>,
488 constraint_mode: bool,
490 macro_params: HashSet<InternedStr>,
492 macro_return_types: Option<&'a HashMap<String, String>>,
494 macro_param_types: Option<&'a HashMap<String, Vec<(String, String)>>>,
497 files: Option<&'a FileRegistry>,
499 parser_typedefs: Option<&'a HashSet<InternedStr>>,
501}
502
503impl<'a> SemanticAnalyzer<'a> {
504 pub fn new(
506 interner: &'a StringInterner,
507 apidoc: Option<&'a ApidocDict>,
508 fields_dict: Option<&'a FieldsDict>,
509 ) -> Self {
510 Self::with_rust_decl_dict(interner, apidoc, fields_dict, None, None)
511 }
512
513 pub fn with_rust_decl_dict(
515 interner: &'a StringInterner,
516 apidoc: Option<&'a ApidocDict>,
517 fields_dict: Option<&'a FieldsDict>,
518 rust_decl_dict: Option<&'a RustDeclDict>,
519 inline_fn_dict: Option<&'a InlineFnDict>,
520 ) -> Self {
521 let global_scope = Scope::new(None);
522 Self {
523 interner,
524 scopes: vec![global_scope],
525 current_scope: ScopeId(0),
526 struct_defs: HashMap::new(),
527 union_defs: HashMap::new(),
528 typedef_defs: HashMap::new(),
529 apidoc,
530 fields_dict,
531 rust_decl_dict,
532 inline_fn_dict,
533 type_vars: HashMap::new(),
534 next_type_var: 0,
535 constraints: Vec::new(),
536 constraint_mode: false,
537 macro_params: HashSet::new(),
538 macro_return_types: None,
539 macro_param_types: None,
540 files: None,
541 parser_typedefs: None,
542 }
543 }
544
545 pub fn set_macro_return_types(&mut self, cache: &'a HashMap<String, String>) {
547 self.macro_return_types = Some(cache);
548 }
549
550 pub fn set_macro_param_types(&mut self, cache: &'a HashMap<String, Vec<(String, String)>>) {
552 self.macro_param_types = Some(cache);
553 }
554
555 pub fn get_macro_return_type(&self, macro_name: &str) -> Option<&str> {
557 self.macro_return_types
558 .and_then(|cache| cache.get(macro_name))
559 .map(|s| s.as_str())
560 }
561
562 pub fn get_macro_param_types(&self, macro_name: &str) -> Option<&Vec<(String, String)>> {
564 self.macro_param_types
565 .and_then(|cache| cache.get(macro_name))
566 }
567
568 pub fn push_scope(&mut self) {
570 let new_scope = Scope::new(Some(self.current_scope));
571 let new_id = ScopeId(self.scopes.len());
572 self.scopes.push(new_scope);
573 self.current_scope = new_id;
574 }
575
576 pub fn pop_scope(&mut self) {
578 if let Some(parent) = self.scopes[self.current_scope.0].parent {
579 self.current_scope = parent;
580 }
581 }
582
583 pub fn define_symbol(&mut self, symbol: Symbol) {
585 let scope = &mut self.scopes[self.current_scope.0];
586 scope.symbols.insert(symbol.name, symbol);
587 }
588
589 pub fn lookup_symbol(&self, name: InternedStr) -> Option<&Symbol> {
591 let mut scope_id = Some(self.current_scope);
592 while let Some(id) = scope_id {
593 let scope = &self.scopes[id.0];
594 if let Some(sym) = scope.symbols.get(&name) {
595 return Some(sym);
596 }
597 scope_id = scope.parent;
598 }
599 None
600 }
601
602 pub fn begin_param_inference(&mut self, params: &[InternedStr]) {
608 self.constraint_mode = true;
609 self.type_vars.clear();
610 self.constraints.clear();
611 self.next_type_var = 0;
612
613 for ¶m in params {
614 let var = TypeVar(self.next_type_var);
615 self.next_type_var += 1;
616 self.type_vars.insert(param, var);
617 }
618 }
619
620 pub fn end_param_inference(&mut self) -> HashMap<InternedStr, Type> {
622 self.constraint_mode = false;
623 let solutions = self.solve_constraints();
624
625 let mut result = HashMap::new();
627 for (&name, &var) in &self.type_vars {
628 if let Some(ty) = solutions.get(&var) {
629 result.insert(name, ty.clone());
630 }
631 }
632
633 self.type_vars.clear();
635 self.constraints.clear();
636 self.next_type_var = 0;
637
638 result
639 }
640
641 fn solve_constraints(&self) -> HashMap<TypeVar, Type> {
643 let mut solutions = HashMap::new();
644
645 for constraint in &self.constraints {
646 match constraint {
647 TypeConstraint::FunctionArg { var, func_name, arg_index } => {
648 if solutions.contains_key(var) {
649 continue;
650 }
651
652 if let Some(ty) = self.lookup_rust_decl_param_type(*func_name, *arg_index) {
654 solutions.insert(*var, ty);
655 }
656 }
657 TypeConstraint::HasField { var, field } => {
658 if solutions.contains_key(var) {
659 continue;
660 }
661
662 if let Some(fields_dict) = self.fields_dict {
664 if let Some(struct_name) = fields_dict.lookup_unique(*field) {
665 solutions.insert(
667 *var,
668 Type::Pointer(
669 Box::new(Type::TypedefName(struct_name)),
670 TypeQualifiers::default(),
671 ),
672 );
673 }
674 }
675 }
676 }
677 }
678
679 solutions
680 }
681
682 fn lookup_rust_decl_param_type(&self, func_name: InternedStr, arg_index: usize) -> Option<Type> {
684 let rust_decl_dict = self.rust_decl_dict?;
685 let func_name_str = self.interner.get(func_name);
686 let rust_fn = rust_decl_dict.fns.get(func_name_str)?;
687 let param = rust_fn.params.get(arg_index)?;
688 Some(self.parse_rust_type_string(¶m.ty))
690 }
691
692 fn lookup_inline_fn_param_type_repr(
698 &self,
699 func_name: InternedStr,
700 arg_index: usize,
701 ) -> Option<TypeRepr> {
702 let dict = self.inline_fn_dict?;
703 let func_def = dict.get(func_name)?;
704
705 let param_list = func_def.declarator.derived.iter()
706 .find_map(|d| match d {
707 DerivedDecl::Function(params) => Some(params),
708 _ => None,
709 })?;
710
711 let param = param_list.params.get(arg_index)?;
712
713 let specs = CTypeSpecs::from_decl_specs(¶m.specs, self.interner);
714 let derived = param.declarator.as_ref()
715 .map(|d| {
716 CDerivedType::from_derived_decls(&d.derived)
718 .into_iter()
719 .take_while(|d| !matches!(d, CDerivedType::Function { .. }))
720 .collect()
721 })
722 .unwrap_or_default();
723
724 Some(TypeRepr::CType {
725 specs,
726 derived,
727 source: CTypeSource::InlineFn { func_name },
728 })
729 }
730
731 fn lookup_inline_fn_return_type_repr(&self, func_name: InternedStr) -> Option<TypeRepr> {
733 let dict = self.inline_fn_dict?;
734 let func_def = dict.get(func_name)?;
735
736 let specs = CTypeSpecs::from_decl_specs(&func_def.specs, self.interner);
737
738 let derived: Vec<_> = CDerivedType::from_derived_decls(&func_def.declarator.derived)
740 .into_iter()
741 .take_while(|d| !matches!(d, CDerivedType::Function { .. }))
742 .collect();
743
744 Some(TypeRepr::CType {
745 specs,
746 derived,
747 source: CTypeSource::InlineFn { func_name },
748 })
749 }
750
751 pub fn resolve_decl_specs(&mut self, specs: &DeclSpecs) -> Type {
753 let mut is_signed = false;
755 let mut is_unsigned = false;
756 let mut is_short = false;
757 let mut is_long = 0u8; let mut base_type: Option<Type> = None;
759
760 for spec in &specs.type_specs {
761 match spec {
762 TypeSpec::Void => base_type = Some(Type::Void),
763 TypeSpec::Char => base_type = Some(Type::Char),
764 TypeSpec::Short => is_short = true,
765 TypeSpec::Int => {
766 if base_type.is_none() {
767 base_type = Some(Type::Int);
768 }
769 }
770 TypeSpec::Long => is_long += 1,
771 TypeSpec::Float => base_type = Some(Type::Float),
772 TypeSpec::Double => base_type = Some(Type::Double),
773 TypeSpec::Signed => is_signed = true,
774 TypeSpec::Unsigned => is_unsigned = true,
775 TypeSpec::Bool => base_type = Some(Type::Bool),
776 TypeSpec::Int128 => base_type = Some(Type::Int128),
777 TypeSpec::Struct(s) => {
778 let members = self.resolve_struct_members(s);
779 if let (Some(name), Some(m)) = (s.name, &members) {
780 self.struct_defs.insert(name, m.clone());
781 }
782 base_type = Some(Type::Struct {
783 name: s.name,
784 members,
785 });
786 }
787 TypeSpec::Union(s) => {
788 let members = self.resolve_struct_members(s);
789 if let (Some(name), Some(m)) = (s.name, &members) {
790 self.union_defs.insert(name, m.clone());
791 }
792 base_type = Some(Type::Union {
793 name: s.name,
794 members,
795 });
796 }
797 TypeSpec::Enum(e) => {
798 self.process_enum(e);
800 base_type = Some(Type::Enum { name: e.name });
801 }
802 TypeSpec::TypedefName(name) => {
803 if let Some(ty) = self.typedef_defs.get(name) {
805 base_type = Some(ty.clone());
806 } else {
807 base_type = Some(Type::TypedefName(*name));
808 }
809 }
810 TypeSpec::TypeofExpr(_) => {
811 base_type = Some(Type::Unknown);
813 }
814 _ => {}
815 }
816 }
817
818 match (is_unsigned, is_signed, is_short, is_long, &base_type) {
820 (true, _, _, 0, None) | (true, _, _, 0, Some(Type::Int)) => Type::UnsignedInt,
822 (true, _, _, 1, _) => Type::UnsignedLong,
823 (true, _, _, 2, _) => Type::UnsignedLongLong,
824 (true, _, true, _, _) => Type::UnsignedShort,
825 (true, _, _, _, Some(Type::Char)) => Type::UnsignedChar,
826 (true, _, _, _, Some(Type::Int128)) => Type::UnsignedInt128,
827 (_, true, _, _, Some(Type::Char)) => Type::SignedChar,
829 (_, _, _, 1, None) | (_, _, _, 1, Some(Type::Int)) => Type::Long,
831 (_, _, _, 2, _) => Type::LongLong,
832 (_, _, _, 1, Some(Type::Double)) => Type::LongDouble,
833 (_, _, true, _, _) => Type::Short,
835 _ => base_type.unwrap_or(Type::Int),
837 }
838 }
839
840 fn resolve_struct_members(&mut self, spec: &StructSpec) -> Option<Vec<(InternedStr, Type)>> {
842 spec.members.as_ref().map(|members| {
843 let mut result = Vec::new();
844 for member in members {
845 let base_ty = self.resolve_decl_specs(&member.specs);
846 for decl in &member.declarators {
847 if let Some(ref d) = decl.declarator {
848 if let Some(name) = d.name {
849 let ty = self.apply_declarator(&base_ty, d);
850 result.push((name, ty));
851 }
852 }
853 }
854 }
855 result
856 })
857 }
858
859 fn process_enum(&mut self, spec: &EnumSpec) {
861 if let Some(ref enumerators) = spec.enumerators {
862 let mut value = 0i64;
863 for e in enumerators {
864 if e.value.is_some() {
865 value = 0; }
868 self.define_symbol(Symbol {
869 name: e.name,
870 ty: Type::Int,
871 loc: spec.loc.clone(),
872 kind: SymbolKind::EnumConstant(value),
873 });
874 value += 1;
875 }
876 }
877 }
878
879 pub fn apply_declarator(&self, base_type: &Type, decl: &Declarator) -> Type {
881 let mut ty = base_type.clone();
882
883 for derived in &decl.derived {
884 ty = match derived {
885 DerivedDecl::Pointer(quals) => Type::Pointer(Box::new(ty), quals.clone()),
886 DerivedDecl::Array(arr) => {
887 let _size = &arr.size;
889 Type::Array(Box::new(ty), None)
890 }
891 DerivedDecl::Function(params) => {
892 let param_types: Vec<_> = params.params
893 .iter()
894 .map(|p| {
895 let base = self.resolve_decl_specs_readonly(&p.specs);
896 if let Some(ref d) = p.declarator {
897 self.apply_declarator(&base, d)
898 } else {
899 base
900 }
901 })
902 .collect();
903 Type::Function {
904 return_type: Box::new(ty),
905 params: param_types,
906 variadic: params.is_variadic,
907 }
908 }
909 };
910 }
911
912 ty
913 }
914
915 fn resolve_decl_specs_readonly(&self, specs: &DeclSpecs) -> Type {
917 let mut is_unsigned = false;
919 let mut is_long = 0u8;
920 let mut base_type: Option<Type> = None;
921
922 for spec in &specs.type_specs {
923 match spec {
924 TypeSpec::Void => base_type = Some(Type::Void),
925 TypeSpec::Char => base_type = Some(Type::Char),
926 TypeSpec::Int => base_type = Some(Type::Int),
927 TypeSpec::Long => is_long += 1,
928 TypeSpec::Float => base_type = Some(Type::Float),
929 TypeSpec::Double => base_type = Some(Type::Double),
930 TypeSpec::Unsigned => is_unsigned = true,
931 TypeSpec::Bool => base_type = Some(Type::Bool),
932 TypeSpec::TypedefName(name) => {
933 if let Some(ty) = self.typedef_defs.get(name) {
934 base_type = Some(ty.clone());
935 } else {
936 base_type = Some(Type::TypedefName(*name));
937 }
938 }
939 _ => {}
940 }
941 }
942
943 match (is_unsigned, is_long, &base_type) {
944 (true, 0, None) | (true, 0, Some(Type::Int)) => Type::UnsignedInt,
945 (true, 1, _) => Type::UnsignedLong,
946 (_, 1, None) | (_, 1, Some(Type::Int)) => Type::Long,
947 (_, 2, _) => Type::LongLong,
948 _ => base_type.unwrap_or(Type::Int),
949 }
950 }
951
952 pub fn resolve_type_name(&self, type_name: &TypeName) -> Type {
954 let base_ty = self.resolve_decl_specs_readonly(&type_name.specs);
955 if let Some(ref abs_decl) = type_name.declarator {
956 self.apply_abstract_declarator(&base_ty, abs_decl)
957 } else {
958 base_ty
959 }
960 }
961
962 fn apply_abstract_declarator(&self, base_type: &Type, decl: &AbstractDeclarator) -> Type {
964 let mut ty = base_type.clone();
965
966 for derived in &decl.derived {
967 ty = match derived {
968 DerivedDecl::Pointer(quals) => Type::Pointer(Box::new(ty), quals.clone()),
969 DerivedDecl::Array(_) => {
970 Type::Array(Box::new(ty), None)
971 }
972 DerivedDecl::Function(params) => {
973 let param_types: Vec<_> = params.params
974 .iter()
975 .map(|p| {
976 let base = self.resolve_decl_specs_readonly(&p.specs);
977 if let Some(ref d) = p.declarator {
978 self.apply_declarator(&base, d)
979 } else {
980 base
981 }
982 })
983 .collect();
984 Type::Function {
985 return_type: Box::new(ty),
986 params: param_types,
987 variadic: params.is_variadic,
988 }
989 }
990 };
991 }
992
993 ty
994 }
995
996 pub fn process_declaration(&mut self, decl: &Declaration) {
998 let base_ty = self.resolve_decl_specs(&decl.specs);
999
1000 if decl.specs.storage == Some(StorageClass::Typedef) {
1002 for init_decl in &decl.declarators {
1003 if let Some(name) = init_decl.declarator.name {
1004 let ty = self.apply_declarator(&base_ty, &init_decl.declarator);
1005 self.typedef_defs.insert(name, ty);
1006 }
1007 }
1008 return;
1009 }
1010
1011 for init_decl in &decl.declarators {
1013 if let Some(name) = init_decl.declarator.name {
1014 let ty = self.apply_declarator(&base_ty, &init_decl.declarator);
1015 self.define_symbol(Symbol {
1016 name,
1017 ty,
1018 loc: decl.loc().clone(),
1019 kind: SymbolKind::Variable,
1020 });
1021 }
1022 }
1023 }
1024
1025 pub fn process_function_def(&mut self, func: &FunctionDef) {
1027 let return_ty = self.resolve_decl_specs(&func.specs);
1028 let func_ty = self.apply_declarator(&return_ty, &func.declarator);
1029
1030 if let Some(name) = func.declarator.name {
1032 self.define_symbol(Symbol {
1033 name,
1034 ty: func_ty.clone(),
1035 loc: func.loc().clone(),
1036 kind: SymbolKind::Function,
1037 });
1038 }
1039
1040 self.push_scope();
1042
1043 if let Type::Function { params, .. } = &func_ty {
1045 for derived in &func.declarator.derived {
1046 if let DerivedDecl::Function(param_list) = derived {
1047 for (param, param_ty) in param_list.params.iter().zip(params.iter()) {
1048 if let Some(ref decl) = param.declarator {
1049 if let Some(name) = decl.name {
1050 self.define_symbol(Symbol {
1051 name,
1052 ty: param_ty.clone(),
1053 loc: func.loc().clone(),
1054 kind: SymbolKind::Variable,
1055 });
1056 }
1057 }
1058 }
1059 break;
1060 }
1061 }
1062 }
1063
1064 self.process_compound_stmt(&func.body);
1066
1067 self.pop_scope();
1068 }
1069
1070 pub fn process_compound_stmt(&mut self, stmt: &CompoundStmt) {
1072 self.push_scope();
1073 for item in &stmt.items {
1074 match item {
1075 BlockItem::Decl(decl) => self.process_declaration(decl),
1076 BlockItem::Stmt(stmt) => self.process_stmt(stmt),
1077 }
1078 }
1079 self.pop_scope();
1080 }
1081
1082 fn process_stmt(&mut self, stmt: &Stmt) {
1084 match stmt {
1085 Stmt::Compound(compound) => self.process_compound_stmt(compound),
1086 Stmt::For { init, .. } => {
1087 self.push_scope();
1088 if let Some(ForInit::Decl(decl)) = init {
1089 self.process_declaration(decl);
1090 }
1091 self.pop_scope();
1093 }
1094 _ => {}
1095 }
1096 }
1097
1098 pub fn set_macro_params(&mut self, params: &[InternedStr]) {
1104 self.macro_params.clear();
1105 for ¶m in params {
1106 self.macro_params.insert(param);
1107 }
1108 }
1109
1110 pub fn clear_macro_params(&mut self) {
1112 self.macro_params.clear();
1113 }
1114
1115 pub fn register_macro_params_from_apidoc(
1123 &mut self,
1124 macro_name: InternedStr,
1125 params: &[InternedStr],
1126 files: &'a FileRegistry,
1127 typedefs: &'a HashSet<InternedStr>,
1128 ) {
1129 self.files = Some(files);
1131 self.parser_typedefs = Some(typedefs);
1132
1133 self.macro_params.clear();
1135 for ¶m in params {
1136 self.macro_params.insert(param);
1137 }
1138
1139 let macro_name_str = self.interner.get(macro_name);
1141 if let Some(apidoc) = self.apidoc {
1142 if let Some(entry) = apidoc.get(macro_name_str) {
1143 for (i, ¶m_name) in params.iter().enumerate() {
1145 if let Some(apidoc_arg) = entry.args.get(i) {
1146 match parse_type_from_string(
1148 &apidoc_arg.ty,
1149 self.interner,
1150 files,
1151 typedefs,
1152 ) {
1153 Ok(type_name) => {
1154 let ty = self.resolve_type_name(&type_name);
1155 self.define_symbol(Symbol {
1156 name: param_name,
1157 ty,
1158 loc: SourceLocation::default(),
1159 kind: SymbolKind::Variable,
1160 });
1161 }
1162 Err(_) => {}
1163 }
1164 }
1165 }
1166 }
1167 }
1168 }
1169
1170 fn parse_type_string(&self, s: &str) -> TypeRepr {
1175 if let (Some(files), Some(typedefs)) = (self.files, self.parser_typedefs) {
1176 TypeRepr::from_c_type_string(s, self.interner, files, typedefs)
1177 } else {
1178 TypeRepr::from_apidoc_string(s, self.interner)
1179 }
1180 }
1181
1182 fn is_macro_param(&self, name: InternedStr) -> bool {
1184 self.macro_params.contains(&name)
1185 }
1186
1187 fn make_sv_ptr_type(&self) -> TypeRepr {
1189 let sv_name = self.interner.lookup("SV")
1190 .expect("SV should be interned");
1191 TypeRepr::CType {
1192 specs: CTypeSpecs::TypedefName(sv_name),
1193 derived: vec![CDerivedType::Pointer { is_const: false, is_volatile: false, is_restrict: false }],
1194 source: CTypeSource::SvFamilyCast,
1195 }
1196 }
1197
1198 fn make_sv_family_ptr_type(&self, typedef_name: InternedStr) -> TypeRepr {
1200 TypeRepr::CType {
1201 specs: CTypeSpecs::TypedefName(typedef_name),
1202 derived: vec![CDerivedType::Pointer { is_const: false, is_volatile: false, is_restrict: false }],
1203 source: CTypeSource::CommonMacroFieldInference,
1204 }
1205 }
1206
1207 fn try_infer_sv_family_from_member(
1213 &self,
1214 member: InternedStr,
1215 base: &Expr,
1216 type_env: &mut TypeEnv,
1217 ) {
1218 let Some(fields_dict) = self.fields_dict else { return };
1219 let Some(macro_id) = fields_dict.defining_macro_of(member) else { return };
1220 let Some(sv_typedef) = fields_dict.sv_family_of_common_macro(macro_id) else { return };
1221 let Some((_param_name, param_node_id)) = leftmost_param_ident(base, &self.macro_params)
1222 else {
1223 return;
1224 };
1225 let sv_type = self.make_sv_family_ptr_type(sv_typedef);
1226 let typedef_str = self.interner.get(sv_typedef);
1227 let member_str = self.interner.get(member);
1228 type_env.add_constraint(TypeEnvConstraint::new(
1229 param_node_id,
1230 sv_type,
1231 format!("common-macro field {} implies {}*", member_str, typedef_str),
1232 ));
1233 }
1234
1235 fn get_expr_type_repr(&self, expr_id: ExprId, type_env: &TypeEnv) -> Option<TypeRepr> {
1237 type_env.expr_constraints.get(&expr_id)
1238 .and_then(|c| c.first())
1239 .map(|c| c.ty.clone())
1240 }
1241
1242 fn get_expr_type_repr_or_unknown(&self, expr_id: ExprId, type_env: &TypeEnv) -> TypeRepr {
1248 self.get_expr_type_repr(expr_id, type_env)
1249 .unwrap_or_else(|| TypeRepr::from_apidoc_string("<unknown>", self.interner))
1250 }
1251
1252 fn get_expr_type_str(&self, expr_id: ExprId, type_env: &TypeEnv) -> String {
1254 if let Some(constraints) = type_env.expr_constraints.get(&expr_id) {
1255 if let Some(c) = constraints.first() {
1256 return c.ty.to_display_string(self.interner);
1257 }
1258 }
1259 "<unknown>".to_string()
1260 }
1261
1262 fn compute_binary_type_str(&self, op: &BinOp, lhs_id: ExprId, rhs_id: ExprId, type_env: &TypeEnv) -> String {
1264 match op {
1265 BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge |
1267 BinOp::Eq | BinOp::Ne | BinOp::LogAnd | BinOp::LogOr => "int".to_string(),
1268 _ => {
1270 let lhs_ty = self.get_expr_type_str(lhs_id, type_env);
1271 let rhs_ty = self.get_expr_type_str(rhs_id, type_env);
1272 self.usual_arithmetic_conversion_str(&lhs_ty, &rhs_ty)
1273 }
1274 }
1275 }
1276
1277 fn usual_arithmetic_conversion_str(&self, lhs: &str, rhs: &str) -> String {
1279 let is_ptr = |ty: &str| ty.contains('*');
1281 if is_ptr(lhs) && !is_ptr(rhs) {
1282 return lhs.to_string();
1283 }
1284 if is_ptr(rhs) && !is_ptr(lhs) {
1285 return rhs.to_string();
1286 }
1287
1288 let rank = |ty: &str| -> u8 {
1290 match ty {
1291 "long double" => 10,
1292 "double" => 9,
1293 "float" => 8,
1294 "unsigned long long" => 7,
1295 "long long" => 6,
1296 "unsigned long" => 5,
1297 "long" => 4,
1298 "unsigned int" => 3,
1299 "int" => 2,
1300 "unsigned short" => 1,
1301 "short" => 1,
1302 _ => 0,
1303 }
1304 };
1305
1306 if rank(lhs) >= rank(rhs) {
1307 lhs.to_string()
1308 } else {
1309 rhs.to_string()
1310 }
1311 }
1312
1313 fn compute_conditional_type_str(&self, then_id: ExprId, else_id: ExprId, type_env: &TypeEnv) -> String {
1315 let then_ty = self.get_expr_type_str(then_id, type_env);
1316 let else_ty = self.get_expr_type_str(else_id, type_env);
1317 let is_void_ptr = |s: &str| s.contains("void") && s.contains('*');
1319 let is_concrete_ptr = |s: &str| !s.contains("void") && s.contains('*');
1320 if is_void_ptr(&then_ty) && is_concrete_ptr(&else_ty) {
1321 return else_ty;
1322 }
1323 if is_void_ptr(&else_ty) && is_concrete_ptr(&then_ty) {
1324 return then_ty;
1325 }
1326 self.usual_arithmetic_conversion_str(&then_ty, &else_ty)
1327 }
1328
1329 pub fn collect_stmt_constraints(&mut self, stmt: &Stmt, type_env: &mut TypeEnv) {
1333 match stmt {
1334 Stmt::Compound(compound) => {
1335 for item in &compound.items {
1336 match item {
1337 BlockItem::Stmt(s) => self.collect_stmt_constraints(s, type_env),
1338 BlockItem::Decl(_) => {} }
1340 }
1341 }
1342 Stmt::Expr(Some(expr), _) => {
1343 self.collect_expr_constraints(expr, type_env);
1344 }
1345 Stmt::If { cond, then_stmt, else_stmt, .. } => {
1346 self.collect_expr_constraints(cond, type_env);
1347 self.collect_stmt_constraints(then_stmt, type_env);
1348 if let Some(else_s) = else_stmt {
1349 self.collect_stmt_constraints(else_s, type_env);
1350 }
1351 }
1352 Stmt::While { cond, body, .. } => {
1353 self.collect_expr_constraints(cond, type_env);
1354 self.collect_stmt_constraints(body, type_env);
1355 }
1356 Stmt::DoWhile { body, cond, .. } => {
1357 self.collect_stmt_constraints(body, type_env);
1358 self.collect_expr_constraints(cond, type_env);
1359 }
1360 Stmt::For { init, cond, step, body, .. } => {
1361 if let Some(ForInit::Expr(e)) = init {
1362 self.collect_expr_constraints(e, type_env);
1363 }
1364 if let Some(c) = cond {
1365 self.collect_expr_constraints(c, type_env);
1366 }
1367 if let Some(s) = step {
1368 self.collect_expr_constraints(s, type_env);
1369 }
1370 self.collect_stmt_constraints(body, type_env);
1371 }
1372 Stmt::Return(Some(expr), _) => {
1373 self.collect_expr_constraints(expr, type_env);
1374 }
1375 Stmt::Switch { expr, body, .. } => {
1376 self.collect_expr_constraints(expr, type_env);
1377 self.collect_stmt_constraints(body, type_env);
1378 }
1379 Stmt::Case { expr, stmt, .. } => {
1380 self.collect_expr_constraints(expr, type_env);
1381 self.collect_stmt_constraints(stmt, type_env);
1382 }
1383 Stmt::Default { stmt, .. } | Stmt::Label { stmt, .. } => {
1384 self.collect_stmt_constraints(stmt, type_env);
1385 }
1386 _ => {} }
1388 }
1389
1390 fn resolve_typedef_to_struct_name<'b>(&self, name: &'b str) -> std::borrow::Cow<'b, str> {
1405 let Some(rd) = self.rust_decl_dict else {
1406 return std::borrow::Cow::Borrowed(name);
1407 };
1408 let mut current = std::borrow::Cow::Borrowed(name);
1409 for _ in 0..8 {
1410 if rd.structs.contains_key(current.as_ref()) {
1412 return current;
1413 }
1414 let Some(alias) = rd.types.get(current.as_ref()) else {
1416 return current;
1417 };
1418 current = std::borrow::Cow::Owned(alias.ty.clone());
1419 }
1420 current
1421 }
1422
1423 fn replace_anonymous_with_bindings(
1424 &self,
1425 parent_struct_name_str: &str,
1426 field_name_str: &str,
1427 c_field_type: TypeRepr,
1428 ) -> TypeRepr {
1429 if !is_anonymous_struct_or_union_field(&c_field_type) {
1430 return c_field_type;
1431 }
1432 let Some(rd) = self.rust_decl_dict else {
1433 return c_field_type;
1434 };
1435 let resolved = self.resolve_typedef_to_struct_name(parent_struct_name_str);
1436 let Some(rust_struct) = rd.structs.get(resolved.as_ref()) else {
1437 return c_field_type;
1438 };
1439 let Some(rust_field) = rust_struct.fields.iter().find(|f| f.name == field_name_str) else {
1440 return c_field_type;
1441 };
1442 TypeRepr::from_unified_type(&rust_field.uty, self.interner)
1446 }
1447
1448 fn lookup_field_in_bindings(
1453 &self,
1454 parent_struct_name_str: &str,
1455 field_name_str: &str,
1456 ) -> Option<TypeRepr> {
1457 let rd = self.rust_decl_dict?;
1458 let resolved = self.resolve_typedef_to_struct_name(parent_struct_name_str);
1459 let rust_struct = rd.structs.get(resolved.as_ref())?;
1460 let rust_field = rust_struct.fields.iter().find(|f| f.name == field_name_str)?;
1461 Some(TypeRepr::from_unified_type(&rust_field.uty, self.interner))
1462 }
1463
1464 pub fn collect_expr_constraints(&mut self, expr: &Expr, type_env: &mut TypeEnv) {
1468 match &expr.kind {
1469 ExprKind::IntLit(_) => {
1471 type_env.add_constraint(TypeEnvConstraint::new(
1472 expr.id,
1473 TypeRepr::Inferred(InferredType::IntLiteral),
1474 "integer literal",
1475 ));
1476 }
1477 ExprKind::UIntLit(_) => {
1478 type_env.add_constraint(TypeEnvConstraint::new(
1479 expr.id,
1480 TypeRepr::Inferred(InferredType::UIntLiteral),
1481 "unsigned integer literal",
1482 ));
1483 }
1484 ExprKind::FloatLit(_) => {
1485 type_env.add_constraint(TypeEnvConstraint::new(
1486 expr.id,
1487 TypeRepr::Inferred(InferredType::FloatLiteral),
1488 "float literal",
1489 ));
1490 }
1491 ExprKind::CharLit(_) => {
1492 type_env.add_constraint(TypeEnvConstraint::new(
1493 expr.id,
1494 TypeRepr::Inferred(InferredType::CharLiteral),
1495 "char literal",
1496 ));
1497 }
1498 ExprKind::StringLit(_) => {
1499 type_env.add_constraint(TypeEnvConstraint::new(
1500 expr.id,
1501 TypeRepr::Inferred(InferredType::StringLiteral),
1502 "string literal",
1503 ));
1504 }
1505
1506 ExprKind::Ident(name) => {
1508 let name_str = self.interner.get(*name);
1509
1510 if let Some(sym) = self.lookup_symbol(*name) {
1512 let ty_str = sym.ty.display(self.interner);
1513 let resolved = TypeRepr::from_apidoc_string(&ty_str, self.interner);
1516 type_env.add_constraint(TypeEnvConstraint::new(
1517 expr.id,
1518 TypeRepr::Inferred(InferredType::SymbolLookup {
1519 name: *name,
1520 resolved_type: Box::new(resolved),
1521 }),
1522 "symbol lookup",
1523 ));
1524 } else if let Some(rust_decl_dict) = self.rust_decl_dict {
1526 if let Some(rust_const) = rust_decl_dict.lookup_const(name_str) {
1527 type_env.add_constraint(TypeEnvConstraint::new(
1528 expr.id,
1529 TypeRepr::RustType {
1530 repr: RustTypeRepr::from_type_string(&rust_const.ty),
1531 source: RustTypeSource::Const {
1532 const_name: name_str.to_string(),
1533 },
1534 },
1535 "bindings constant",
1536 ));
1537 } else if name_str == "my_perl" {
1538 type_env.add_constraint(TypeEnvConstraint::new(
1540 expr.id,
1541 TypeRepr::Inferred(InferredType::ThxDefault),
1542 "THX default type",
1543 ));
1544 }
1545 } else if name_str == "my_perl" {
1546 type_env.add_constraint(TypeEnvConstraint::new(
1548 expr.id,
1549 TypeRepr::Inferred(InferredType::ThxDefault),
1550 "THX default type",
1551 ));
1552 }
1553
1554 if self.is_macro_param(*name) {
1556 type_env.link_expr_to_param(expr.id, *name, "parameter reference");
1557 }
1558 }
1559
1560 ExprKind::Call { func, args } => {
1562 self.collect_expr_constraints(func, type_env);
1564 for arg in args {
1565 self.collect_expr_constraints(arg, type_env);
1566 }
1567 self.collect_call_constraints(expr.id, func, args, type_env);
1569 }
1570
1571 ExprKind::Binary { op, lhs, rhs } => {
1573 self.collect_expr_constraints(lhs, type_env);
1575 self.collect_expr_constraints(rhs, type_env);
1576 let result_ty_str = self.compute_binary_type_str(op, lhs.id, rhs.id, type_env);
1578 let result_type = TypeRepr::from_apidoc_string(&result_ty_str, self.interner);
1579 type_env.add_constraint(TypeEnvConstraint::new(
1580 expr.id,
1581 TypeRepr::Inferred(InferredType::BinaryOp {
1582 op: *op,
1583 result_type: Box::new(result_type),
1584 }),
1585 "binary expression",
1586 ));
1587 }
1588
1589 ExprKind::Conditional { cond, then_expr, else_expr } => {
1591 self.collect_expr_constraints(cond, type_env);
1592 self.collect_expr_constraints(then_expr, type_env);
1593 self.collect_expr_constraints(else_expr, type_env);
1594 let then_type = self.get_expr_type_repr_or_unknown(then_expr.id, type_env);
1595 let else_type = self.get_expr_type_repr_or_unknown(else_expr.id, type_env);
1596 let result_ty_str = self.compute_conditional_type_str(then_expr.id, else_expr.id, type_env);
1599 let result_type = TypeRepr::from_apidoc_string(&result_ty_str, self.interner);
1600 type_env.add_constraint(TypeEnvConstraint::new(
1601 expr.id,
1602 TypeRepr::Inferred(InferredType::Conditional {
1603 then_type: Box::new(then_type),
1604 else_type: Box::new(else_type),
1605 result_type: Box::new(result_type),
1606 }),
1607 "conditional expression",
1608 ));
1609 }
1610
1611 ExprKind::Cast { type_name, expr: inner } => {
1613 self.collect_expr_constraints(inner, type_env);
1614 let specs = CTypeSpecs::from_decl_specs(&type_name.specs, self.interner);
1616 let derived: Vec<CDerivedType> = type_name.declarator.as_ref()
1617 .map(|d| {
1618 CDerivedType::from_derived_decls(&d.derived)
1619 .into_iter()
1620 .take_while(|d| !matches!(d, CDerivedType::Function { .. }))
1621 .collect()
1622 })
1623 .unwrap_or_default();
1624 let target_type = TypeRepr::CType {
1625 specs: specs.clone(),
1626 derived: derived.clone(),
1627 source: CTypeSource::Cast,
1628 };
1629 type_env.add_constraint(TypeEnvConstraint::new(
1630 expr.id,
1631 TypeRepr::Inferred(InferredType::Cast {
1632 target_type: Box::new(target_type),
1633 }),
1634 "cast expression",
1635 ));
1636
1637 if let Some(fields_dict) = self.fields_dict {
1640 let is_single_ptr = derived.len() == 1
1641 && matches!(derived[0], CDerivedType::Pointer { .. });
1642 if is_single_ptr {
1643 if let Some(type_name_id) = specs.type_name() {
1644 if fields_dict.is_sv_family_type(type_name_id) {
1645 if let ExprKind::Ident(param_name) = &inner.kind {
1646 if self.is_macro_param(*param_name) {
1647 let sv_type = self.make_sv_ptr_type();
1648 type_env.add_constraint(TypeEnvConstraint::new(
1649 inner.id,
1650 sv_type,
1651 "SV family cast",
1652 ));
1653 }
1654 }
1655 }
1656 }
1657 }
1658 }
1659 }
1660
1661 ExprKind::Index { expr: base, index } => {
1663 self.collect_expr_constraints(base, type_env);
1664 self.collect_expr_constraints(index, type_env);
1665 let base_ty_str = self.get_expr_type_str(base.id, type_env);
1667 let elem_ty_str = if base_ty_str.ends_with('*') {
1668 base_ty_str.trim_end_matches('*').trim().to_string()
1669 } else if base_ty_str.contains('[') {
1670 base_ty_str.split('[').next().unwrap_or(&base_ty_str).trim().to_string()
1671 } else {
1672 "<unknown>".to_string()
1673 };
1674 let base_type = TypeRepr::from_apidoc_string(&base_ty_str, self.interner);
1675 let element_type = TypeRepr::from_apidoc_string(&elem_ty_str, self.interner);
1676 type_env.add_constraint(TypeEnvConstraint::new(
1677 expr.id,
1678 TypeRepr::Inferred(InferredType::ArraySubscript {
1679 base_type: Box::new(base_type),
1680 element_type: Box::new(element_type),
1681 }),
1682 "array subscript",
1683 ));
1684 }
1685
1686 ExprKind::Member { expr: base, member } => {
1688 self.collect_expr_constraints(base, type_env);
1689
1690 let base_ty = self.get_expr_type_str(base.id, type_env);
1691 let member_name = self.interner.get(*member);
1692
1693 let field_type = if self.is_sv_u_access(base) {
1697 self.lookup_sv_u_field_type(*member)
1699 .map(|c_type| Box::new(TypeRepr::from_apidoc_string(&c_type, self.interner)))
1700 } else {
1701 let base_type_repr = self.get_expr_type_repr(base.id, type_env);
1703 let struct_name_id = base_type_repr.as_ref().and_then(|t| t.type_name());
1704 let struct_name_str = base_type_repr.as_ref()
1706 .and_then(|t| extract_struct_name_str(t, self.interner));
1707 let field_str = self.interner.get(*member);
1708 let flex_ptr = struct_name_id.and_then(|n| {
1710 self.fields_dict?
1711 .flexible_array_element(n, *member)
1712 .map(|elem| Box::new(wrap_with_outer_pointer(elem.clone(), false)))
1713 });
1714 let direct = flex_ptr.or_else(|| {
1716 struct_name_id.and_then(|n| {
1717 self.fields_dict?.get_field_type(n, *member).map(|ft| {
1718 let parent_str = self.interner.get(n);
1719 let patched = self.replace_anonymous_with_bindings(
1720 parent_str, field_str, ft.type_repr.clone(),
1721 );
1722 Box::new(patched)
1723 })
1724 })
1725 });
1726 let direct = direct.or_else(|| {
1729 struct_name_str.as_deref().and_then(|parent_str| {
1730 self.lookup_field_in_bindings(parent_str, field_str)
1731 .map(Box::new)
1732 })
1733 });
1734 direct.or_else(|| {
1737 self.fields_dict
1738 .and_then(|fd| fd.rust_type_of_common_field(*member))
1739 .cloned()
1740 .map(Box::new)
1741 })
1742 };
1743
1744 type_env.add_constraint(TypeEnvConstraint::new(
1745 expr.id,
1746 TypeRepr::Inferred(InferredType::MemberAccess {
1747 base_type: base_ty.clone(),
1748 member: *member,
1749 field_type,
1750 }),
1751 format!("{}.{}", base_ty, member_name),
1752 ));
1753
1754 self.try_infer_sv_family_from_member(*member, base, type_env);
1756 }
1757
1758 ExprKind::PtrMember { expr: base, member } => {
1760 self.collect_expr_constraints(base, type_env);
1761
1762 let base_ty = self.get_expr_type_str(base.id, type_env);
1764 let member_name = self.interner.get(*member);
1765
1766 if let Some(fields_dict) = self.fields_dict {
1769 if base_ty == "/* unknown */" || self.is_ident_expr(base) {
1771 let inferred_struct = fields_dict.lookup_unique(*member)
1774 .or_else(|| fields_dict.get_consistent_base_type(*member, self.interner));
1775
1776 if let Some(struct_name) = inferred_struct {
1777 let type_name = fields_dict.get_typedef_for_struct(struct_name)
1779 .unwrap_or(struct_name);
1780 let type_name_str = self.interner.get(type_name);
1781 let base_type = TypeRepr::CType {
1782 specs: CTypeSpecs::TypedefName(type_name),
1783 derived: vec![CDerivedType::Pointer {
1784 is_const: false,
1785 is_volatile: false,
1786 is_restrict: false,
1787 }],
1788 source: CTypeSource::FieldInference { field_name: *member },
1789 };
1790 type_env.add_constraint(TypeEnvConstraint::new(
1791 base.id,
1792 base_type,
1793 format!("field {} implies {}*", member_name, type_name_str),
1794 ));
1795 }
1796 }
1797 }
1798
1799 let base_type_repr = self.get_expr_type_repr(base.id, type_env);
1801 let pointee = base_type_repr.as_ref().and_then(|t| t.pointee_name());
1802 let (field_type, used_consistent_type) = if let Some(name) = pointee {
1803 let flex_ptr = self.fields_dict.and_then(|fd| {
1805 fd.flexible_array_element(name, *member)
1806 .map(|elem| Box::new(wrap_with_outer_pointer(elem.clone(), false)))
1807 });
1808 let parent_str = self.interner.get(name);
1809 let field_str = self.interner.get(*member);
1810 let direct = flex_ptr.or_else(|| {
1813 self.fields_dict
1814 .and_then(|fd| fd.get_field_type(name, *member))
1815 .map(|ft| {
1816 let patched = self.replace_anonymous_with_bindings(
1817 parent_str, field_str, ft.type_repr.clone(),
1818 );
1819 Box::new(patched)
1820 })
1821 });
1822 let direct = direct.or_else(|| {
1825 self.lookup_field_in_bindings(parent_str, field_str)
1826 .map(Box::new)
1827 });
1828 let ty = direct.or_else(|| {
1829 self.fields_dict
1831 .and_then(|fd| fd.rust_type_of_common_field(*member))
1832 .cloned()
1833 .map(Box::new)
1834 });
1835 (ty, false)
1836 } else if let Some(fields_dict) = self.fields_dict {
1837 let consistent = fields_dict.get_consistent_field_type(*member)
1839 .cloned()
1840 .map(Box::new);
1841 let ty = consistent.or_else(|| {
1842 fields_dict.rust_type_of_common_field(*member)
1843 .cloned()
1844 .map(Box::new)
1845 });
1846 (ty, true)
1847 } else {
1848 (None, false)
1849 };
1850
1851 type_env.add_constraint(TypeEnvConstraint::new(
1852 expr.id,
1853 TypeRepr::Inferred(InferredType::PtrMemberAccess {
1854 base_type: base_ty.clone(),
1855 member: *member,
1856 field_type,
1857 used_consistent_type,
1858 }),
1859 format!("{}->{}", base_ty, member_name),
1860 ));
1861
1862 self.try_infer_sv_family_from_member(*member, base, type_env);
1864 }
1865
1866 ExprKind::Assign { lhs, rhs, .. } => {
1868 self.collect_expr_constraints(lhs, type_env);
1869 self.collect_expr_constraints(rhs, type_env);
1870 let lhs_type = self.get_expr_type_repr_or_unknown(lhs.id, type_env);
1872 type_env.add_constraint(TypeEnvConstraint::new(
1873 expr.id,
1874 TypeRepr::Inferred(InferredType::Assignment {
1875 lhs_type: Box::new(lhs_type),
1876 }),
1877 "assignment expression",
1878 ));
1879 }
1880
1881 ExprKind::Comma { lhs, rhs } => {
1883 self.collect_expr_constraints(lhs, type_env);
1884 self.collect_expr_constraints(rhs, type_env);
1885 let rhs_type = self.get_expr_type_repr_or_unknown(rhs.id, type_env);
1887 type_env.add_constraint(TypeEnvConstraint::new(
1888 expr.id,
1889 TypeRepr::Inferred(InferredType::Comma {
1890 rhs_type: Box::new(rhs_type),
1891 }),
1892 "comma expression",
1893 ));
1894 }
1895
1896 ExprKind::PreInc(inner) | ExprKind::PreDec(inner) |
1898 ExprKind::PostInc(inner) | ExprKind::PostDec(inner) => {
1899 self.collect_expr_constraints(inner, type_env);
1900 let inner_type = self.get_expr_type_repr_or_unknown(inner.id, type_env);
1901 type_env.add_constraint(TypeEnvConstraint::new(
1902 expr.id,
1903 TypeRepr::Inferred(InferredType::IncDec {
1904 inner_type: Box::new(inner_type),
1905 }),
1906 "increment/decrement",
1907 ));
1908 }
1909
1910 ExprKind::AddrOf(inner) => {
1912 self.collect_expr_constraints(inner, type_env);
1913 let inner_type = self.get_expr_type_repr_or_unknown(inner.id, type_env);
1914 type_env.add_constraint(TypeEnvConstraint::new(
1915 expr.id,
1916 TypeRepr::Inferred(InferredType::AddressOf {
1917 inner_type: Box::new(inner_type),
1918 }),
1919 "address-of",
1920 ));
1921 }
1922
1923 ExprKind::Deref(inner) => {
1925 self.collect_expr_constraints(inner, type_env);
1926 let pointer_type = self.get_expr_type_repr_or_unknown(inner.id, type_env);
1927 type_env.add_constraint(TypeEnvConstraint::new(
1928 expr.id,
1929 TypeRepr::Inferred(InferredType::Dereference {
1930 pointer_type: Box::new(pointer_type),
1931 }),
1932 "dereference",
1933 ));
1934 }
1935
1936 ExprKind::UnaryPlus(inner) | ExprKind::UnaryMinus(inner) => {
1938 self.collect_expr_constraints(inner, type_env);
1939 let inner_type = self.get_expr_type_repr_or_unknown(inner.id, type_env);
1940 type_env.add_constraint(TypeEnvConstraint::new(
1941 expr.id,
1942 TypeRepr::Inferred(InferredType::UnaryArithmetic {
1943 inner_type: Box::new(inner_type),
1944 }),
1945 "unary plus/minus",
1946 ));
1947 }
1948
1949 ExprKind::BitNot(inner) => {
1951 self.collect_expr_constraints(inner, type_env);
1952 let inner_type = self.get_expr_type_repr_or_unknown(inner.id, type_env);
1953 type_env.add_constraint(TypeEnvConstraint::new(
1954 expr.id,
1955 TypeRepr::Inferred(InferredType::UnaryArithmetic {
1956 inner_type: Box::new(inner_type),
1957 }),
1958 "bitwise not",
1959 ));
1960 }
1961
1962 ExprKind::LogNot(inner) => {
1964 self.collect_expr_constraints(inner, type_env);
1965 type_env.add_constraint(TypeEnvConstraint::new(
1966 expr.id,
1967 TypeRepr::Inferred(InferredType::LogicalNot),
1968 "logical not",
1969 ));
1970 }
1971
1972 ExprKind::Sizeof(inner) => {
1974 self.collect_expr_constraints(inner, type_env);
1975 type_env.add_constraint(TypeEnvConstraint::new(
1976 expr.id,
1977 TypeRepr::Inferred(InferredType::Sizeof),
1978 "sizeof expression",
1979 ));
1980 }
1981
1982 ExprKind::SizeofType(_) => {
1984 type_env.add_constraint(TypeEnvConstraint::new(
1985 expr.id,
1986 TypeRepr::Inferred(InferredType::Sizeof),
1987 "sizeof type",
1988 ));
1989 }
1990
1991 ExprKind::Alignof(_) => {
1993 type_env.add_constraint(TypeEnvConstraint::new(
1994 expr.id,
1995 TypeRepr::Inferred(InferredType::Alignof),
1996 "alignof",
1997 ));
1998 }
1999
2000 ExprKind::CompoundLit { type_name, .. } => {
2002 let ty = self.resolve_type_name(type_name);
2003 let ty_str = ty.display(self.interner);
2004 let type_name_repr = TypeRepr::from_apidoc_string(&ty_str, self.interner);
2005 type_env.add_constraint(TypeEnvConstraint::new(
2006 expr.id,
2007 TypeRepr::Inferred(InferredType::CompoundLiteral {
2008 type_name: Box::new(type_name_repr),
2009 }),
2010 "compound literal",
2011 ));
2012 }
2013
2014 ExprKind::StmtExpr(compound) => {
2016 self.collect_compound_constraints(compound, type_env);
2017 if let Some(last_expr_id) = self.get_last_expr_id(compound) {
2019 let last_expr_type = self.get_expr_type_repr_or_unknown(last_expr_id, type_env);
2020 type_env.add_constraint(TypeEnvConstraint::new(
2021 expr.id,
2022 TypeRepr::Inferred(InferredType::StmtExpr {
2023 last_expr_type: Some(Box::new(last_expr_type)),
2024 }),
2025 "statement expression",
2026 ));
2027 } else {
2028 type_env.add_constraint(TypeEnvConstraint::new(
2029 expr.id,
2030 TypeRepr::Inferred(InferredType::StmtExpr {
2031 last_expr_type: None,
2032 }),
2033 "statement expression (empty)",
2034 ));
2035 }
2036 }
2037
2038 ExprKind::Assert { condition, .. } => {
2040 self.collect_expr_constraints(condition, type_env);
2041 type_env.add_constraint(TypeEnvConstraint::new(
2042 expr.id,
2043 TypeRepr::Inferred(InferredType::Assert),
2044 "assertion",
2045 ));
2046 }
2047
2048 ExprKind::BuiltinCall { name, args } => {
2050 for arg in args {
2052 if let crate::ast::BuiltinArg::Expr(e) = arg {
2053 self.collect_expr_constraints(e, type_env);
2054 }
2055 }
2056 let func_name = self.interner.get(*name);
2058 if func_name == "offsetof" || func_name == "__builtin_offsetof"
2059 || func_name == "STRUCT_OFFSET"
2060 {
2061 type_env.add_constraint(TypeEnvConstraint::new(
2062 expr.id,
2063 TypeRepr::Inferred(InferredType::Sizeof),
2064 "offsetof returns size_t",
2065 ));
2066 }
2067 }
2068
2069 ExprKind::MacroCall { name, args, expanded, .. } => {
2071 for arg in args {
2073 self.collect_expr_constraints(arg, type_env);
2074 }
2075
2076 let macro_name_str = self.interner.get(*name);
2078 if let Some(param_types) = self.get_macro_param_types(macro_name_str) {
2079 for (i, arg) in args.iter().enumerate() {
2080 if let Some((param_name, type_str)) = param_types.get(i) {
2081 let constraint = TypeEnvConstraint::new(
2083 arg.id,
2084 TypeRepr::from_rust_string(type_str),
2085 format!("arg {} ({}) of macro {}()", i, param_name, macro_name_str),
2086 );
2087 type_env.add_constraint(constraint);
2088 }
2089 }
2090 }
2091
2092 self.collect_expr_constraints(expanded, type_env);
2094 if let Some(constraints) = type_env.get_expr_constraints(expanded.id) {
2096 if let Some(constraint) = constraints.first() {
2097 type_env.add_constraint(TypeEnvConstraint::new(
2098 expr.id,
2099 constraint.ty.clone(),
2100 "macro call (expanded)",
2101 ));
2102 }
2103 }
2104 }
2105 }
2106 }
2107
2108 fn get_last_expr_id(&self, compound: &CompoundStmt) -> Option<ExprId> {
2110 if let Some(BlockItem::Stmt(Stmt::Expr(Some(expr), _))) = compound.items.last() {
2111 Some(expr.id)
2112 } else {
2113 None
2114 }
2115 }
2116
2117 fn is_sv_u_access(&self, base: &Expr) -> bool {
2121 if let ExprKind::PtrMember { member, .. } = &base.kind {
2122 let sv_u_id = self.interner.lookup("sv_u");
2123 sv_u_id.map_or(false, |id| *member == id)
2124 } else {
2125 false
2126 }
2127 }
2128
2129 fn is_ident_expr(&self, expr: &Expr) -> bool {
2133 matches!(expr.kind, ExprKind::Ident(_))
2134 }
2135
2136 fn lookup_sv_u_field_type(&self, field: InternedStr) -> Option<String> {
2141 self.fields_dict?
2142 .get_sv_u_field_type(field)
2143 .map(|s| s.to_string())
2144 }
2145
2146 fn collect_call_constraints(
2148 &mut self,
2149 call_expr_id: ExprId,
2150 func: &Expr,
2151 args: &[Expr],
2152 type_env: &mut TypeEnv,
2153 ) {
2154 let func_name = match &func.kind {
2156 ExprKind::Ident(name) => *name,
2157 _ => return, };
2159
2160 let func_name_str = self.interner.get(func_name);
2161
2162 if let Some(rust_decl_dict) = self.rust_decl_dict {
2164 if let Some(rust_fn) = rust_decl_dict.fns.get(func_name_str) {
2165 for (i, arg) in args.iter().enumerate() {
2166 if let Some(param) = rust_fn.params.get(i) {
2167 let constraint = TypeEnvConstraint::new(
2168 arg.id,
2169 TypeRepr::RustType {
2170 repr: RustTypeRepr::from_type_string(¶m.ty),
2171 source: RustTypeSource::FnParam {
2172 func_name: func_name_str.to_string(),
2173 param_index: i,
2174 },
2175 },
2176 format!("arg {} of {}()", i, func_name_str),
2177 );
2178 type_env.add_constraint(constraint);
2179 }
2180 }
2181
2182 if let Some(ref ret_ty) = rust_fn.ret_ty {
2184 let return_constraint = TypeEnvConstraint::new(
2185 call_expr_id,
2186 TypeRepr::RustType {
2187 repr: RustTypeRepr::from_type_string(ret_ty),
2188 source: RustTypeSource::FnReturn {
2189 func_name: func_name_str.to_string(),
2190 },
2191 },
2192 format!("return type of {}()", func_name_str),
2193 );
2194 type_env.add_constraint(return_constraint);
2195 }
2196 }
2197 }
2198
2199 if let Some(apidoc) = self.apidoc {
2201 if let Some(entry) = apidoc.get(func_name_str) {
2202 for (i, arg) in args.iter().enumerate() {
2204 if let Some(apidoc_arg) = entry.args.get(i) {
2205 let constraint = TypeEnvConstraint::new(
2206 arg.id,
2207 self.parse_type_string(&apidoc_arg.ty),
2208 format!("arg {} ({}) of {}()", i, apidoc_arg.name, func_name_str),
2209 );
2210 type_env.add_constraint(constraint);
2211 }
2212 }
2213
2214 if let Some(ref return_type) = entry.return_type {
2216 let return_constraint = TypeEnvConstraint::new(
2217 call_expr_id,
2218 self.parse_type_string(return_type),
2219 format!("return type of {}()", func_name_str),
2220 );
2221 type_env.add_constraint(return_constraint);
2222 }
2223 }
2224 }
2225
2226 if self.inline_fn_dict.is_some() {
2228 for (i, arg) in args.iter().enumerate() {
2230 if let Some(type_repr) = self.lookup_inline_fn_param_type_repr(func_name, i) {
2231 let constraint = TypeEnvConstraint::new(
2232 arg.id,
2233 type_repr,
2234 format!("arg {} of inline {}()", i, func_name_str),
2235 );
2236 type_env.add_constraint(constraint);
2237 }
2238 }
2239
2240 if let Some(type_repr) = self.lookup_inline_fn_return_type_repr(func_name) {
2242 let return_constraint = TypeEnvConstraint::new(
2243 call_expr_id,
2244 type_repr,
2245 format!("return type of inline {}()", func_name_str),
2246 );
2247 type_env.add_constraint(return_constraint);
2248 }
2249 }
2250
2251 if let Some(param_types) = self.get_macro_param_types(func_name_str) {
2253 for (i, arg) in args.iter().enumerate() {
2254 if let Some((param_name, type_str)) = param_types.get(i) {
2255 let constraint = TypeEnvConstraint::new(
2257 arg.id,
2258 TypeRepr::from_rust_string(type_str),
2259 format!("arg {} ({}) of macro {}()", i, param_name, func_name_str),
2260 );
2261 type_env.add_constraint(constraint);
2262 }
2263 }
2264 }
2265
2266 if let Some(return_type_str) = self.get_macro_return_type(func_name_str) {
2268 let return_constraint = TypeEnvConstraint::new(
2270 call_expr_id,
2271 TypeRepr::from_rust_string(return_type_str),
2272 format!("return type of macro {}()", func_name_str),
2273 );
2274 type_env.add_constraint(return_constraint);
2275 }
2276 }
2277
2278 fn collect_compound_constraints(&mut self, compound: &CompoundStmt, type_env: &mut TypeEnv) {
2280 for item in &compound.items {
2281 match item {
2282 BlockItem::Decl(decl) => {
2283 self.collect_decl_initializer_constraints(decl, type_env);
2285 }
2286 BlockItem::Stmt(Stmt::Expr(Some(expr), _)) => {
2287 self.collect_expr_constraints(expr, type_env);
2288 }
2289 BlockItem::Stmt(Stmt::Return(Some(expr), _)) => {
2290 self.collect_expr_constraints(expr, type_env);
2291 }
2292 BlockItem::Stmt(Stmt::Compound(inner)) => {
2293 self.collect_compound_constraints(inner, type_env);
2294 }
2295 _ => {}
2296 }
2297 }
2298 }
2299
2300 fn collect_decl_initializer_constraints(&mut self, decl: &Declaration, type_env: &mut TypeEnv) {
2302 for init_decl in &decl.declarators {
2303 if let Some(ref init) = init_decl.init {
2304 self.collect_initializer_constraints(init, type_env);
2305 }
2306 }
2307 }
2308
2309 fn collect_initializer_constraints(&mut self, init: &Initializer, type_env: &mut TypeEnv) {
2311 match init {
2312 Initializer::Expr(expr) => {
2313 self.collect_expr_constraints(expr, type_env);
2314 }
2315 Initializer::List(items) => {
2316 for item in items {
2317 self.collect_initializer_constraints(&item.init, type_env);
2318 }
2319 }
2320 }
2321 }
2322
2323 fn parse_rust_type_string(&self, type_str: &str) -> Type {
2325 let normalized = type_str
2327 .replace("* mut", "*mut")
2328 .replace("* const", "*const");
2329 let trimmed = normalized.trim();
2330
2331 if let Some(rest) = trimmed.strip_prefix("*mut ") {
2333 return Type::Pointer(
2334 Box::new(self.parse_rust_type_string(rest)),
2335 TypeQualifiers::default(),
2336 );
2337 }
2338 if let Some(rest) = trimmed.strip_prefix("*const ") {
2339 return Type::Pointer(
2340 Box::new(self.parse_rust_type_string(rest)),
2341 TypeQualifiers { is_const: true, ..Default::default() },
2342 );
2343 }
2344
2345 match trimmed {
2347 "()" => Type::Void,
2348 "c_char" => Type::Char,
2349 "c_int" => Type::Int,
2350 "c_uint" => Type::UnsignedInt,
2351 "c_long" => Type::Long,
2352 "c_ulong" => Type::UnsignedLong,
2353 "bool" => Type::Bool,
2354 "usize" => Type::UnsignedLong,
2355 "isize" => Type::Long,
2356 _ => {
2357 if let Some(interned) = self.interner.lookup(trimmed) {
2359 Type::TypedefName(interned)
2360 } else {
2361 Type::Unknown
2362 }
2363 }
2364 }
2365 }
2366}
2367
2368#[cfg(test)]
2369mod tests {
2370 use super::*;
2371
2372 #[test]
2373 fn test_type_display() {
2374 let interner = StringInterner::new();
2375
2376 assert_eq!(Type::Int.display(&interner), "int");
2377 assert_eq!(Type::UnsignedLong.display(&interner), "unsigned long");
2378 assert_eq!(
2379 Type::Pointer(Box::new(Type::Char), TypeQualifiers::default()).display(&interner),
2380 "char*"
2381 );
2382 }
2383
2384 #[test]
2385 fn test_scope_management() {
2386 let mut interner = StringInterner::new();
2387 let x = interner.intern("x");
2388 let mut analyzer = SemanticAnalyzer::new(&interner, None, None);
2389
2390 analyzer.define_symbol(Symbol {
2392 name: x,
2393 ty: Type::Int,
2394 loc: SourceLocation::default(),
2395 kind: SymbolKind::Variable,
2396 });
2397
2398 assert!(analyzer.lookup_symbol(x).is_some());
2399
2400 analyzer.push_scope();
2402
2403 assert!(analyzer.lookup_symbol(x).is_some());
2405
2406 analyzer.define_symbol(Symbol {
2408 name: x,
2409 ty: Type::Float, loc: SourceLocation::default(),
2411 kind: SymbolKind::Variable,
2412 });
2413
2414 let sym = analyzer.lookup_symbol(x).unwrap();
2416 assert_eq!(sym.ty, Type::Float);
2417
2418 analyzer.pop_scope();
2420
2421 let sym = analyzer.lookup_symbol(x).unwrap();
2423 assert_eq!(sym.ty, Type::Int);
2424 }
2425}