py2erg/
convert.rs

1use core::fmt;
2use std::path::Path;
3
4use erg_common::config::ErgConfig;
5use erg_common::dict::Dict as HashMap;
6use erg_common::error::Location as ErgLocation;
7use erg_common::fresh::FRESH_GEN;
8use erg_common::set::Set as HashSet;
9use erg_common::traits::{Locational, Stream, Traversable};
10use erg_common::{fmt_vec, log, set};
11use erg_compiler::artifact::IncompleteArtifact;
12use erg_compiler::erg_parser::ast::{
13    Accessor, Args, BinOp, Block, ClassAttr, ClassAttrs, ClassDef, Compound, ConstAccessor,
14    ConstApp, ConstArgs, ConstAttribute, ConstBinOp, ConstBlock, ConstDict, ConstExpr,
15    ConstKeyValue, ConstLambda, ConstList, ConstListWithLength, ConstNormalList, ConstNormalSet,
16    ConstPosArg, ConstSet, Decorator, Def, DefBody, DefId, DefaultParamSignature, Dict,
17    DictComprehension, Dummy, Expr, Identifier, KeyValue, KwArg, Lambda, LambdaSignature, List,
18    ListComprehension, Literal, Methods, Module, NonDefaultParamSignature, NormalDict, NormalList,
19    NormalRecord, NormalSet, NormalTuple, ParamPattern, ParamTySpec, Params, PosArg,
20    PreDeclTypeSpec, ReDef, Record, RecordAttrs, Set, SetComprehension, Signature, SubrSignature,
21    SubrTypeSpec, Tuple, TupleTypeSpec, TypeAppArgs, TypeAppArgsKind, TypeAscription,
22    TypeBoundSpec, TypeBoundSpecs, TypeSpec, TypeSpecWithOp, UnaryOp, VarName, VarPattern,
23    VarRecordAttr, VarRecordAttrs, VarRecordPattern, VarSignature, VisModifierSpec,
24};
25use erg_compiler::erg_parser::desugar::Desugarer;
26use erg_compiler::erg_parser::token::{Token, TokenKind, AS, COLON, DOT, EQUAL};
27use erg_compiler::erg_parser::Parser;
28use erg_compiler::error::{CompileError, CompileErrors};
29use rustpython_ast::located::LocatedMut;
30use rustpython_ast::source_code::RandomLocator;
31use rustpython_parser::ast::located::{
32    self as py_ast, Alias, Arg, Arguments, BoolOp, CmpOp, ExprConstant, Keyword, Located,
33    ModModule, Operator, Stmt, String, Suite, TypeParam, UnaryOp as UnOp,
34};
35use rustpython_parser::ast::Fold;
36use rustpython_parser::source_code::{
37    OneIndexed, SourceLocation as PyLocation, SourceRange as PySourceRange,
38};
39use rustpython_parser::Parse;
40
41use crate::ast_util::accessor_name;
42use crate::error::*;
43
44macro_rules! global_unary_collections {
45    () => {
46        "Collection" | "Container" | "Generator" | "Iterable" | "Iterator" | "Sequence" | "Set"
47    };
48}
49
50macro_rules! global_mutable_unary_collections {
51    () => {
52        "MutableSequence" | "MutableSet" | "MutableMapping"
53    };
54}
55
56macro_rules! global_binary_collections {
57    () => {
58        "Mapping"
59    };
60}
61
62pub const ARROW: Token = Token::dummy(TokenKind::FuncArrow, "->");
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
65pub enum RenameKind {
66    Let,
67    Phi,
68    Redef,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Hash)]
72pub enum NameKind {
73    Variable,
74    Class,
75    Function,
76}
77
78impl NameKind {
79    pub const fn is_variable(&self) -> bool {
80        matches!(self, Self::Variable)
81    }
82    pub const fn is_class(&self) -> bool {
83        matches!(self, Self::Class)
84    }
85    pub const fn is_function(&self) -> bool {
86        matches!(self, Self::Function)
87    }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
91pub enum BlockKind {
92    If,
93    /// else, except, finally
94    Else {
95        if_block_id: usize,
96    },
97    For,
98    While,
99    Try,
100    With,
101    Function,
102    AsyncFunction,
103    Class,
104    Module,
105}
106
107impl BlockKind {
108    pub const fn is_if(&self) -> bool {
109        matches!(self, Self::If)
110    }
111    pub const fn is_function(&self) -> bool {
112        matches!(self, Self::Function | Self::AsyncFunction)
113    }
114    pub const fn makes_scope(&self) -> bool {
115        matches!(self, Self::Function | Self::AsyncFunction | Self::Class)
116    }
117    pub const fn is_else(&self) -> bool {
118        matches!(self, Self::Else { .. })
119    }
120    pub const fn if_block_id(&self) -> Option<usize> {
121        match self {
122            Self::Else { if_block_id } => Some(*if_block_id),
123            _ => None,
124        }
125    }
126}
127
128/// Variables are automatically rewritten with `py_compat`,
129/// but types are rewritten here because they are complex components used inseparably in the Erg system.
130fn escape_name(name: String) -> String {
131    match &name[..] {
132        "object" => "Obj".into(),
133        "int" => "Int".into(),
134        "float" => "Float".into(),
135        "complex" => "Complex".into(),
136        "str" => "Str".into(),
137        "bool" => "Bool".into(),
138        "list" => "GenericList".into(),
139        "bytes" => "Bytes".into(),
140        "bytearray" => "ByteArray!".into(),
141        // "range" => "GenericRange".into(),
142        "dict" => "GenericDict".into(),
143        "set" => "GenericSet".into(),
144        "tuple" => "GenericTuple".into(),
145        "type" => "Type".into(),
146        "ModuleType" => "GeneticModule".into(),
147        _ => name,
148    }
149}
150
151fn is_global_poly_type(name: &str) -> bool {
152    matches!(
153        name,
154        "list"
155            | "dict"
156            | "set"
157            | "tuple"
158            | "List"
159            | "Dict"
160            | "Tuple"
161            | global_unary_collections!()
162            | global_mutable_unary_collections!()
163            | global_binary_collections!()
164    )
165}
166
167fn quoted_symbol(sym: &str, lineno: u32, col_begin: u32) -> Token {
168    let col_end = col_begin + sym.chars().count() as u32;
169    Token {
170        kind: TokenKind::StrLit,
171        content: format!("\"{sym}\"").into(),
172        lineno,
173        col_begin,
174        col_end,
175    }
176}
177
178fn op_to_token(op: Operator) -> Token {
179    let (kind, cont) = match op {
180        Operator::Add => (TokenKind::Plus, "+"),
181        Operator::Sub => (TokenKind::Minus, "-"),
182        Operator::Mult => (TokenKind::Star, "*"),
183        Operator::Div => (TokenKind::Slash, "/"),
184        Operator::Mod => (TokenKind::Mod, "%"),
185        Operator::Pow => (TokenKind::Pow, "**"),
186        Operator::LShift => (TokenKind::Shl, "<<"),
187        Operator::RShift => (TokenKind::Shr, ">>"),
188        Operator::BitOr => (TokenKind::BitOr, "||"),
189        Operator::BitXor => (TokenKind::BitXor, "^^"),
190        Operator::BitAnd => (TokenKind::BitAnd, "&&"),
191        Operator::FloorDiv => (TokenKind::FloorDiv, "//"),
192        Operator::MatMult => (TokenKind::AtSign, "@"),
193    };
194    Token::from_str(kind, cont)
195}
196
197pub fn pyloc_to_ergloc(range: PySourceRange) -> erg_common::error::Location {
198    erg_common::error::Location::range(
199        range.start.row.get(),
200        range.start.column.to_zero_indexed(),
201        range.end.unwrap().row.get(),
202        range.end.unwrap().column.to_zero_indexed(),
203    )
204}
205
206pub fn ergloc_to_pyloc(loc: erg_common::error::Location) -> PySourceRange {
207    PySourceRange::new(
208        PyLocation {
209            row: OneIndexed::from_zero_indexed(loc.ln_begin().unwrap_or(0)),
210            column: OneIndexed::from_zero_indexed(loc.col_begin().unwrap_or(0)),
211        },
212        PyLocation {
213            row: OneIndexed::from_zero_indexed(loc.ln_end().unwrap_or(0)),
214            column: OneIndexed::from_zero_indexed(loc.col_end().unwrap_or(0)),
215        },
216    )
217}
218
219fn attr_name_loc(value: &Expr) -> PyLocation {
220    PyLocation {
221        row: OneIndexed::from_zero_indexed(value.ln_end().unwrap_or(0)).saturating_sub(1),
222        column: OneIndexed::from_zero_indexed(value.col_end().unwrap_or(0)).saturating_add(1),
223    }
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227pub enum DefinedPlace {
228    Known(String),
229    Unknown,
230}
231
232impl PartialEq<str> for DefinedPlace {
233    fn eq(&self, other: &str) -> bool {
234        match self {
235            Self::Known(s) => s == other,
236            Self::Unknown => false,
237        }
238    }
239}
240
241impl PartialEq<String> for DefinedPlace {
242    fn eq(&self, other: &String) -> bool {
243        match self {
244            Self::Known(s) => s == other,
245            Self::Unknown => false,
246        }
247    }
248}
249
250impl DefinedPlace {
251    pub const fn is_unknown(&self) -> bool {
252        matches!(self, Self::Unknown)
253    }
254}
255
256#[derive(Debug, Clone, PartialEq, Eq, Hash)]
257pub struct NameInfo {
258    kind: NameKind,
259    rename: Option<String>,
260    defined_in: DefinedPlace,
261    defined_block_id: usize,
262    defined_times: usize,
263    referenced: HashSet<String>,
264}
265
266impl NameInfo {
267    pub fn new(
268        kind: NameKind,
269        rename: Option<String>,
270        defined_in: DefinedPlace,
271        defined_block_id: usize,
272        defined_times: usize,
273    ) -> Self {
274        Self {
275            kind,
276            rename,
277            defined_in,
278            defined_block_id,
279            defined_times,
280            referenced: HashSet::new(),
281        }
282    }
283
284    // TODO: referrer can be usize
285    pub fn add_referrer(&mut self, referrer: String) {
286        self.referenced.insert(referrer);
287    }
288}
289
290#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
291pub enum ShadowingMode {
292    Invisible,
293    Visible,
294}
295
296#[derive(Debug, Clone, PartialEq, Eq, Hash)]
297pub struct TypeVarInfo {
298    name: String,
299    constraints: Vec<Expr>,
300    bound: Option<Expr>,
301}
302
303impl fmt::Display for TypeVarInfo {
304    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        if let Some(bound) = &self.bound {
306            write!(
307                f,
308                "TypeVarInfo({}, [{}], bound={})",
309                self.name,
310                fmt_vec(&self.constraints),
311                bound
312            )
313        } else {
314            write!(
315                f,
316                "TypeVarInfo({}, [{}])",
317                self.name,
318                fmt_vec(&self.constraints)
319            )
320        }
321    }
322}
323
324impl TypeVarInfo {
325    pub const fn new(name: String, constraints: Vec<Expr>, bound: Option<Expr>) -> Self {
326        Self {
327            name,
328            constraints,
329            bound,
330        }
331    }
332}
333
334#[derive(Debug)]
335pub struct BlockInfo {
336    pub id: usize,
337    pub kind: BlockKind,
338}
339
340#[derive(Debug)]
341pub enum ReturnKind {
342    None,
343    Return,
344    Yield,
345}
346
347impl ReturnKind {
348    pub const fn is_none(&self) -> bool {
349        matches!(self, Self::None)
350    }
351}
352
353#[derive(Debug)]
354pub struct LocalContext {
355    pub name: String,
356    pub kind: BlockKind,
357    /// Erg does not allow variables to be defined multiple times, so rename them using this
358    names: HashMap<String, NameInfo>,
359    type_vars: HashMap<String, TypeVarInfo>,
360    // e.g. def id(x: T) -> T: ... => appeared_types = {T}
361    appeared_type_names: HashSet<String>,
362    return_kind: ReturnKind,
363}
364
365impl LocalContext {
366    pub fn new(name: String, kind: BlockKind) -> Self {
367        Self {
368            name,
369            kind,
370            names: HashMap::new(),
371            type_vars: HashMap::new(),
372            appeared_type_names: HashSet::new(),
373            return_kind: ReturnKind::None,
374        }
375    }
376}
377
378#[derive(Debug, Default)]
379pub struct CommentStorage {
380    comments: HashMap<u32, (String, Option<py_ast::Expr>)>,
381}
382
383impl fmt::Display for CommentStorage {
384    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
385        for (i, (comment, expr)) in &self.comments {
386            writeln!(f, "line {i}: \"{comment}\" (expr: {})", expr.is_some())?;
387        }
388        Ok(())
389    }
390}
391
392impl CommentStorage {
393    pub fn new() -> Self {
394        Self {
395            comments: HashMap::new(),
396        }
397    }
398
399    pub fn read(&mut self, code: &str) {
400        // NOTE: This locater is meaningless.
401        let mut locater = RandomLocator::new(code);
402        for (i, line) in code.lines().enumerate() {
403            let mut split = line.split('#');
404            let _code = split.next().unwrap();
405            if let Some(comment) = split.next() {
406                let comment = comment.to_string();
407                let trimmed = comment.trim_start();
408                let expr = if trimmed.starts_with("type:") {
409                    let typ = trimmed.trim_start_matches("type:").trim();
410                    let typ = if typ == "ignore" { "Any" } else { typ };
411                    rustpython_ast::Expr::parse(typ, "<module>")
412                        .ok()
413                        .and_then(|expr| locater.fold(expr).ok())
414                } else {
415                    None
416                };
417                self.comments.insert(i as u32, (comment, expr));
418            }
419        }
420    }
421
422    /// line: 0-origin
423    pub fn get_code(&self, line: u32) -> Option<&String> {
424        self.comments.get(&line).map(|(code, _)| code)
425    }
426
427    /// line: 0-origin
428    pub fn get_type(&self, line: u32) -> Option<&py_ast::Expr> {
429        self.comments.get(&line).and_then(|(_, ty)| ty.as_ref())
430    }
431}
432
433#[derive(Debug, Clone)]
434pub struct PyFuncTypeSpec {
435    type_params: Vec<py_ast::TypeParam>,
436    args: py_ast::Arguments,
437    returns: Option<py_ast::Expr>,
438}
439
440#[derive(Debug, Clone)]
441pub enum PyTypeSpec {
442    Var(py_ast::Expr),
443    Func(PyFuncTypeSpec),
444}
445
446#[derive(Debug, Default)]
447pub struct PyiTypeStorage {
448    decls: HashMap<String, PyTypeSpec>,
449    classes: HashMap<String, HashMap<String, PyTypeSpec>>,
450}
451
452impl fmt::Display for PyiTypeStorage {
453    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
454        for (name, t_spec) in &self.decls {
455            writeln!(f, "{name}: {t_spec:?}")?;
456        }
457        for (class, methods) in &self.classes {
458            writeln!(f, "class {class}:")?;
459            for (name, t_spec) in methods {
460                writeln!(f, "    {name}: {t_spec:?}")?;
461            }
462        }
463        Ok(())
464    }
465}
466
467impl PyiTypeStorage {
468    pub fn new() -> Self {
469        Self {
470            decls: HashMap::new(),
471            classes: HashMap::new(),
472        }
473    }
474
475    pub fn parse(&mut self, filename: &str) {
476        let Ok(code) = std::fs::read_to_string(filename) else {
477            return;
478        };
479        let Ok(py_program) = rustpython_ast::ModModule::parse(&code, filename) else {
480            return;
481        };
482        let mut locator = RandomLocator::new(&code);
483        let Ok(py_program) = locator.fold(py_program);
484        for stmt in py_program.body {
485            match stmt {
486                py_ast::Stmt::AnnAssign(assign) => {
487                    let py_ast::Expr::Name(name) = *assign.target else {
488                        continue;
489                    };
490                    self.decls
491                        .insert(name.id.to_string(), PyTypeSpec::Var(*assign.annotation));
492                }
493                py_ast::Stmt::FunctionDef(def) => {
494                    let returns = def.returns.map(|anot| *anot);
495                    self.decls.insert(
496                        def.name.to_string(),
497                        PyTypeSpec::Func(PyFuncTypeSpec {
498                            type_params: def.type_params,
499                            args: *def.args,
500                            returns,
501                        }),
502                    );
503                }
504                py_ast::Stmt::AsyncFunctionDef(def) => {
505                    let returns = def.returns.map(|anot| *anot);
506                    self.decls.insert(
507                        def.name.to_string(),
508                        PyTypeSpec::Func(PyFuncTypeSpec {
509                            type_params: def.type_params,
510                            args: *def.args,
511                            returns,
512                        }),
513                    );
514                }
515                py_ast::Stmt::ClassDef(class) => {
516                    let mut methods = HashMap::new();
517                    for stmt in class.body {
518                        match stmt {
519                            py_ast::Stmt::AnnAssign(assign) => {
520                                let py_ast::Expr::Name(name) = *assign.target else {
521                                    continue;
522                                };
523                                methods.insert(
524                                    name.id.to_string(),
525                                    PyTypeSpec::Var(*assign.annotation),
526                                );
527                            }
528                            py_ast::Stmt::FunctionDef(def) => {
529                                let returns = def.returns.map(|anot| *anot);
530                                methods.insert(
531                                    def.name.to_string(),
532                                    PyTypeSpec::Func(PyFuncTypeSpec {
533                                        type_params: def.type_params,
534                                        args: *def.args,
535                                        returns,
536                                    }),
537                                );
538                            }
539                            py_ast::Stmt::AsyncFunctionDef(def) => {
540                                let returns = def.returns.map(|anot| *anot);
541                                methods.insert(
542                                    def.name.to_string(),
543                                    PyTypeSpec::Func(PyFuncTypeSpec {
544                                        type_params: def.type_params,
545                                        args: *def.args,
546                                        returns,
547                                    }),
548                                );
549                            }
550                            _ => {}
551                        }
552                    }
553                    self.classes.insert(class.name.to_string(), methods);
554                }
555                _ => {}
556            }
557        }
558    }
559
560    pub fn get_type(&self, name: &str) -> Option<&PyTypeSpec> {
561        self.decls.get(name)
562    }
563
564    pub fn get_class_member_type(&self, class: &str, name: &str) -> Option<&PyTypeSpec> {
565        self.classes
566            .get(class)
567            .and_then(|methods| methods.get(name))
568    }
569}
570
571/// AST must be converted in the following order:
572///
573/// Params -> Block -> Signature
574///
575/// If you convert it from left to right, for example
576///
577/// ```python
578/// i = 1
579/// i = i + 1
580/// ```
581///
582/// would be converted as follows. This is a mistake.
583///
584/// ```python
585/// i = 1
586/// i = i2 + 1
587/// ```
588///
589/// The correct conversion is as follows.
590///
591/// ```python
592/// i = 1
593/// i2 = i + 1
594/// ```
595#[derive(Debug)]
596pub struct ASTConverter {
597    cfg: ErgConfig,
598    shadowing: ShadowingMode,
599    comments: CommentStorage,
600    pyi_types: PyiTypeStorage,
601    block_id_counter: usize,
602    /// block != scope (if block doesn't make a scope, for example)
603    blocks: Vec<BlockInfo>,
604    contexts: Vec<LocalContext>,
605    warns: CompileErrors,
606    errs: CompileErrors,
607}
608
609impl ASTConverter {
610    pub fn new(cfg: ErgConfig, shadowing: ShadowingMode, comments: CommentStorage) -> Self {
611        let mut pyi_types = PyiTypeStorage::new();
612        pyi_types.parse(&cfg.input.path().with_extension("pyi").to_string_lossy());
613        Self {
614            shadowing,
615            pyi_types,
616            cfg,
617            comments,
618            block_id_counter: 0,
619            blocks: vec![BlockInfo {
620                id: 0,
621                kind: BlockKind::Module,
622            }],
623            contexts: vec![LocalContext::new("<module>".into(), BlockKind::Module)],
624            warns: CompileErrors::empty(),
625            errs: CompileErrors::empty(),
626        }
627    }
628
629    fn get_name(&self, name: &str) -> Option<&NameInfo> {
630        for ctx in self.contexts.iter().rev() {
631            if let Some(ni) = ctx.names.get(name) {
632                return Some(ni);
633            }
634        }
635        None
636    }
637
638    fn get_mut_name(&mut self, name: &str) -> Option<&mut NameInfo> {
639        for ctx in self.contexts.iter_mut().rev() {
640            if let Some(ni) = ctx.names.get_mut(name) {
641                return Some(ni);
642            }
643        }
644        None
645    }
646
647    fn get_type_var(&self, name: &str) -> Option<&TypeVarInfo> {
648        for ctx in self.contexts.iter().rev() {
649            if let Some(tv) = ctx.type_vars.get(name) {
650                return Some(tv);
651            }
652        }
653        None
654    }
655
656    fn is_type_name(&self, name: &str) -> bool {
657        is_global_poly_type(name)
658            || self
659                .contexts
660                .iter()
661                .rev()
662                .any(|ctx| ctx.names.get(name).is_some_and(|ni| ni.kind.is_class()))
663    }
664
665    fn define_name(&mut self, name: String, info: NameInfo) {
666        self.contexts.last_mut().unwrap().names.insert(name, info);
667    }
668
669    fn declare_name(&mut self, name: String, info: NameInfo) {
670        self.contexts.first_mut().unwrap().names.insert(name, info);
671    }
672
673    fn define_type_var(&mut self, name: String, info: TypeVarInfo) {
674        self.contexts
675            .last_mut()
676            .unwrap()
677            .type_vars
678            .insert(name, info);
679    }
680
681    fn grow(&mut self, namespace: String, kind: BlockKind) {
682        self.contexts.push(LocalContext::new(namespace, kind));
683    }
684
685    fn pop(&mut self) {
686        self.contexts.pop();
687    }
688
689    fn cur_block_kind(&self) -> BlockKind {
690        self.blocks.last().unwrap().kind
691    }
692
693    fn cur_block_id(&self) -> usize {
694        self.blocks.last().unwrap().id
695    }
696
697    /// foo.bar.baz
698    fn cur_namespace(&self) -> String {
699        self.contexts
700            .iter()
701            .map(|ctx| &ctx.name[..])
702            .collect::<Vec<_>>()
703            .join(".")
704    }
705
706    // baz
707    fn cur_name(&self) -> &str {
708        &self.contexts.last().unwrap().name
709    }
710
711    fn cur_context(&self) -> &LocalContext {
712        self.contexts.last().unwrap()
713    }
714
715    fn cur_context_mut(&mut self) -> &mut LocalContext {
716        self.contexts.last_mut().unwrap()
717    }
718
719    fn parent_name(&self) -> &str {
720        &self.contexts[self.contexts.len().saturating_sub(2)].name
721    }
722
723    fn cur_appeared_type_names(&self) -> &HashSet<String> {
724        &self.contexts.last().unwrap().appeared_type_names
725    }
726
727    fn register_name_info(&mut self, name: &str, kind: NameKind) -> RenameKind {
728        let cur_namespace = self.cur_namespace();
729        let cur_block_id = self.cur_block_id();
730        let cur_block_kind = self.cur_block_kind();
731        if let Some(name_info) = self.get_mut_name(name) {
732            if name_info.defined_in == cur_namespace && name_info.defined_block_id == cur_block_id {
733                name_info.defined_times += 1;
734            }
735            if name_info.defined_in.is_unknown() {
736                name_info.defined_in = DefinedPlace::Known(cur_namespace);
737                name_info.defined_times += 1; // 0 -> 1
738            }
739            if cur_block_kind
740                .if_block_id()
741                .is_some_and(|id| id == name_info.defined_block_id)
742            {
743                RenameKind::Phi
744            } else if cur_block_kind.makes_scope()
745                || name_info.defined_block_id == cur_block_id
746                || name_info.defined_times == 0
747            {
748                RenameKind::Let
749            } else {
750                RenameKind::Redef
751            }
752        } else {
753            // In Erg, classes can only be defined in uppercase
754            // So if not, prefix it with `Type_`
755            let rename = if kind.is_class() && !name.starts_with(char::is_uppercase) {
756                Some(format!("Type_{name}"))
757            } else {
758                None
759            };
760            let defined_in = DefinedPlace::Known(self.cur_namespace());
761            let info = NameInfo::new(kind, rename, defined_in, self.cur_block_id(), 1);
762            self.define_name(String::from(name), info);
763            RenameKind::Let
764        }
765    }
766
767    fn convert_ident(&mut self, name: String, loc: PyLocation) -> Identifier {
768        let shadowing = self.shadowing;
769        let name = escape_name(name);
770        let cur_namespace = self.cur_namespace();
771        let cur_block_id = self.cur_block_id();
772        let cont = if let Some(name_info) = self.get_mut_name(&name) {
773            let different_namespace = name_info.defined_in != cur_namespace;
774            if cur_block_id != 0 {
775                // current is <module>?
776                name_info.add_referrer(cur_namespace);
777            }
778            if different_namespace {
779                name
780            } else {
781                let name = name_info
782                    .rename
783                    .as_ref()
784                    .map_or_else(|| &name, |renamed| renamed);
785                if name_info.defined_times > 1 {
786                    if shadowing == ShadowingMode::Invisible {
787                        // HACK: add zero-width characters as postfix
788                        format!("{name}{}", "\0".repeat(name_info.defined_times))
789                    } else {
790                        format!("{name}__{}", name_info.defined_times)
791                    }
792                } else {
793                    name.clone()
794                }
795            }
796        } else {
797            let defined_in = if self.cur_namespace() == "<module>" {
798                DefinedPlace::Known(self.cur_namespace())
799            } else {
800                DefinedPlace::Unknown
801            };
802            let mut info = NameInfo::new(NameKind::Variable, None, defined_in, cur_block_id, 0);
803            info.add_referrer(cur_namespace);
804            self.declare_name(name.clone(), info);
805            name
806        };
807        let token = Token::new(
808            TokenKind::Symbol,
809            cont,
810            loc.row.get(),
811            loc.column.to_zero_indexed(),
812        );
813        let name = VarName::new(token);
814        let dot = Token::new(
815            TokenKind::Dot,
816            ".",
817            loc.row.get(),
818            loc.column.to_zero_indexed(),
819        );
820        Identifier::new(VisModifierSpec::Public(dot.loc()), name)
821    }
822
823    // TODO: module member mangling
824    fn convert_attr_ident(&mut self, name: String, loc: PyLocation) -> Identifier {
825        let token = Token::new(
826            TokenKind::Symbol,
827            name,
828            loc.row.get(),
829            loc.column.to_zero_indexed(),
830        );
831        let name = VarName::new(token);
832        let dot = Token::new(
833            TokenKind::Dot,
834            ".",
835            loc.row.get(),
836            loc.column.to_zero_indexed(),
837        );
838        Identifier::new(VisModifierSpec::Public(dot.loc()), name)
839    }
840
841    // Duplicate param names will result in an error at the parser. So we don't need to check it here.
842    fn convert_param_pattern(&mut self, arg: String, loc: PyLocation) -> ParamPattern {
843        self.register_name_info(&arg, NameKind::Variable);
844        let ident = self.convert_ident(arg, loc);
845        ParamPattern::VarName(ident.name)
846    }
847
848    fn get_cur_scope_t_spec(&self) -> Option<&PyTypeSpec> {
849        if self.contexts.len() == 2 {
850            let func_name = self.cur_name();
851            self.pyi_types.get_type(func_name)
852        } else {
853            let class = self.parent_name();
854            let func_name = self.cur_name();
855            self.pyi_types.get_class_member_type(class, func_name)
856        }
857    }
858
859    fn convert_nd_param(&mut self, param: Arg) -> NonDefaultParamSignature {
860        let pat = self.convert_param_pattern(param.arg.to_string(), param.location());
861        let t_spec = param
862            .annotation
863            .or_else(|| {
864                let PyTypeSpec::Func(func) = self.get_cur_scope_t_spec()? else {
865                    return None;
866                };
867                func.args
868                    .args
869                    .iter()
870                    .chain(&func.args.kwonlyargs)
871                    .find(|arg| arg.def.arg == param.arg)
872                    .and_then(|arg| arg.def.annotation.clone())
873            })
874            .map(|anot| {
875                (
876                    self.convert_type_spec(*anot.clone()),
877                    self.convert_expr(*anot),
878                )
879            })
880            .map(|(t_spec, expr)| {
881                let as_op = Token::new(
882                    TokenKind::As,
883                    "as",
884                    t_spec.ln_begin().unwrap_or(0),
885                    t_spec.col_begin().unwrap_or(0),
886                );
887                TypeSpecWithOp::new(as_op, t_spec, expr)
888            });
889        NonDefaultParamSignature::new(pat, t_spec)
890    }
891
892    fn convert_default_param(&mut self, kw: Arg, default: py_ast::Expr) -> DefaultParamSignature {
893        let sig = self.convert_nd_param(kw);
894        let default = self.convert_expr(default);
895        DefaultParamSignature::new(sig, default)
896    }
897
898    fn convert_params(&mut self, params: Arguments) -> Params {
899        #[allow(clippy::type_complexity)]
900        fn split_args(
901            params: Arguments,
902        ) -> (Vec<Arg>, Option<Arg>, Vec<(Arg, py_ast::Expr)>, Option<Arg>) {
903            let mut args = Vec::new();
904            let mut with_defaults = Vec::new();
905            let var_args = params.vararg.map(|x| *x);
906            let kw_args = params.kwarg.map(|x| *x);
907            for arg in params
908                .posonlyargs
909                .into_iter()
910                .chain(params.args.into_iter())
911                .chain(params.kwonlyargs.into_iter())
912            {
913                if let Some(default) = arg.default {
914                    with_defaults.push((arg.def, *default));
915                } else {
916                    args.push(arg.def);
917                }
918            }
919            (args, var_args, with_defaults, kw_args)
920        }
921        let (non_defaults, var_args, defaults, kw_args) = split_args(params);
922        let non_defaults = non_defaults
923            .into_iter()
924            .map(|p| self.convert_nd_param(p))
925            .collect();
926        let var_params = var_args.map(|p| self.convert_nd_param(p));
927        let defaults = defaults
928            .into_iter()
929            .map(|(kw, default)| self.convert_default_param(kw, default))
930            .collect();
931        let kw_var_params = kw_args.map(|p| self.convert_nd_param(p));
932        Params::new(non_defaults, var_params, defaults, kw_var_params, None)
933    }
934
935    fn convert_for_param(&mut self, name: String, loc: PyLocation) -> NonDefaultParamSignature {
936        let pat = self.convert_param_pattern(name, loc);
937        let t_spec = None;
938        NonDefaultParamSignature::new(pat, t_spec)
939    }
940
941    fn param_pattern_to_var(pat: ParamPattern) -> VarPattern {
942        match pat {
943            ParamPattern::VarName(name) => VarPattern::Ident(Identifier::new(
944                VisModifierSpec::Public(ErgLocation::Unknown),
945                name,
946            )),
947            ParamPattern::Discard(token) => VarPattern::Discard(token),
948            other => todo!("{other}"),
949        }
950    }
951
952    /// (i, j) => $1 (i = $1[0]; j = $1[1])
953    fn convert_opt_expr_to_param(
954        &mut self,
955        expr: Option<py_ast::Expr>,
956    ) -> (NonDefaultParamSignature, Vec<Expr>) {
957        if let Some(expr) = expr {
958            self.convert_expr_to_param(expr)
959        } else {
960            let token = Token::new(TokenKind::UBar, "_", 0, 0);
961            (
962                NonDefaultParamSignature::new(ParamPattern::Discard(token), None),
963                vec![],
964            )
965        }
966    }
967
968    fn convert_expr_to_param(
969        &mut self,
970        expr: py_ast::Expr,
971    ) -> (NonDefaultParamSignature, Vec<Expr>) {
972        match expr {
973            py_ast::Expr::Name(expr) => (
974                self.convert_for_param(expr.id.to_string(), expr.location()),
975                vec![],
976            ),
977            py_ast::Expr::Tuple(expr) => {
978                let loc = expr.location();
979                let tmp = FRESH_GEN.fresh_varname();
980                let tmp_name = VarName::from_str_and_line(tmp, expr.location().row.get());
981                let tmp_expr = Expr::Accessor(Accessor::Ident(Identifier::new(
982                    VisModifierSpec::Public(ErgLocation::Unknown),
983                    tmp_name.clone(),
984                )));
985                let mut block = vec![];
986                for (i, elem) in expr.elts.into_iter().enumerate() {
987                    let index = Literal::new(Token::new(
988                        TokenKind::NatLit,
989                        i.to_string(),
990                        elem.location().row.get(),
991                        elem.location().column.to_zero_indexed(),
992                    ));
993                    let (param, mut blocks) = self.convert_expr_to_param(elem);
994                    let sig = Signature::Var(VarSignature::new(
995                        Self::param_pattern_to_var(param.pat),
996                        param.t_spec,
997                    ));
998                    let method = tmp_expr
999                        .clone()
1000                        .attr_expr(self.convert_ident("__getitem__".to_string(), loc));
1001                    let tuple_acc = method.call1(Expr::Literal(index));
1002                    let body = DefBody::new(EQUAL, Block::new(vec![tuple_acc]), DefId(0));
1003                    let def = Expr::Def(Def::new(sig, body));
1004                    block.push(def);
1005                    block.append(&mut blocks);
1006                }
1007                let pat = ParamPattern::VarName(tmp_name);
1008                (NonDefaultParamSignature::new(pat, None), block)
1009            }
1010            other => {
1011                let token = Token::new(
1012                    TokenKind::UBar,
1013                    "_",
1014                    other.location().row.get(),
1015                    other.location().column.to_zero_indexed(),
1016                );
1017                (
1018                    NonDefaultParamSignature::new(ParamPattern::Discard(token), None),
1019                    vec![],
1020                )
1021            }
1022        }
1023    }
1024
1025    fn convert_for_body(&mut self, lhs: Option<py_ast::Expr>, body: Suite) -> Lambda {
1026        let (param, block) = self.convert_opt_expr_to_param(lhs);
1027        let params = Params::new(vec![param], None, vec![], None, None);
1028        self.block_id_counter += 1;
1029        self.blocks.push(BlockInfo {
1030            id: self.block_id_counter,
1031            kind: BlockKind::For,
1032        });
1033        let body = body
1034            .into_iter()
1035            .map(|stmt| self.convert_statement(stmt, true))
1036            .collect::<Vec<_>>();
1037        self.blocks.pop();
1038        let body = block.into_iter().chain(body).collect();
1039        let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
1040        let op = Token::from_str(TokenKind::FuncArrow, "->");
1041        Lambda::new(sig, op, Block::new(body), DefId(0))
1042    }
1043
1044    fn convert_ident_type_spec(&mut self, name: String, range: PySourceRange) -> TypeSpec {
1045        let loc = pyloc_to_ergloc(range);
1046        let global = ConstExpr::Accessor(ConstAccessor::Local(Identifier::private_with_loc(
1047            "global".into(),
1048            loc,
1049        )));
1050        let obj = ConstExpr::Accessor(ConstAccessor::Local(Identifier::private_with_loc(
1051            "Obj".into(),
1052            loc,
1053        )));
1054        match &name[..] {
1055            "dict" => {
1056                let kv = ConstKeyValue::new(obj.clone(), obj.clone());
1057                let (l, r) = Self::gen_enclosure_tokens(TokenKind::LSqBr, range);
1058                let dict = ConstDict::new(l, r, vec![kv]);
1059                TypeSpec::poly(
1060                    global.attr(Identifier::private_with_loc("Dict!".into(), loc)),
1061                    ConstArgs::single(ConstExpr::Dict(dict)),
1062                )
1063            }
1064            "set" => TypeSpec::poly(
1065                global.attr(Identifier::private_with_loc("Set!".into(), loc)),
1066                ConstArgs::single(obj),
1067            ),
1068            "tuple" => TypeSpec::poly(
1069                global.attr(Identifier::private_with_loc("HomogenousTuple".into(), loc)),
1070                ConstArgs::single(obj),
1071            ),
1072            // Iterable[T] => Iterable(T), Iterable => Iterable(Obj)
1073            global_unary_collections!() => TypeSpec::poly(
1074                global.attr(Identifier::private_with_loc(name.into(), loc)),
1075                ConstArgs::single(obj),
1076            ),
1077            // MutableSequence[T] => Sequence!(T), MutableSequence => Sequence!(Obj)
1078            global_mutable_unary_collections!() => TypeSpec::poly(
1079                global.attr(Identifier::private_with_loc(
1080                    format!("{}!", name.trim_start_matches("Mutable")).into(),
1081                    loc,
1082                )),
1083                ConstArgs::single(obj),
1084            ),
1085            // Mapping => Mapping(Obj, Obj)
1086            global_binary_collections!() => TypeSpec::poly(
1087                global.attr(Identifier::private_with_loc(name.into(), loc)),
1088                ConstArgs::pos_only(
1089                    vec![ConstPosArg::new(obj.clone()), ConstPosArg::new(obj)],
1090                    None,
1091                ),
1092            ),
1093            _ => TypeSpec::mono(self.convert_ident(name, range.start)),
1094        }
1095    }
1096
1097    fn gen_dummy_type_spec(loc: PyLocation) -> TypeSpec {
1098        TypeSpec::Infer(Token::new(
1099            TokenKind::UBar,
1100            "_",
1101            loc.row.get(),
1102            loc.column.to_zero_indexed(),
1103        ))
1104    }
1105
1106    fn convert_const_expr(&mut self, expr: ConstExpr) -> ConstExpr {
1107        match expr {
1108            ConstExpr::UnaryOp(un) if un.op.is(TokenKind::Mutate) => *un.expr,
1109            ConstExpr::App(app)
1110                if app
1111                    .attr_name
1112                    .as_ref()
1113                    .is_some_and(|n| n.inspect() == "__getitem__") =>
1114            {
1115                let obj = self.convert_const_expr(*app.obj);
1116                let mut args = app.args.map(&mut |arg| self.convert_const_expr(arg));
1117                if args.pos_args.is_empty() {
1118                    return ConstExpr::App(ConstApp::new(obj, app.attr_name, args));
1119                }
1120                let mut args = match args.pos_args.remove(0).expr {
1121                    ConstExpr::Tuple(tuple) => tuple.elems,
1122                    other => {
1123                        args.pos_args.insert(0, ConstPosArg::new(other));
1124                        args
1125                    }
1126                };
1127                match obj.local_name() {
1128                    Some("Union") => {
1129                        if args.pos_args.len() >= 2 {
1130                            let first = args.pos_args.remove(0).expr;
1131                            let or_op = Token::dummy(TokenKind::OrOp, "or");
1132                            args.pos_args.into_iter().fold(first, |acc, expr| {
1133                                ConstExpr::BinOp(ConstBinOp::new(or_op.clone(), acc, expr.expr))
1134                            })
1135                        } else if args.pos_args.len() == 1 {
1136                            args.pos_args.remove(0).expr
1137                        } else {
1138                            ConstExpr::App(ConstApp::new(obj, app.attr_name, args))
1139                        }
1140                    }
1141                    Some("GenericDict" | "Dict") => {
1142                        if args.pos_args.len() == 2 {
1143                            let key = args.pos_args.remove(0).expr;
1144                            let value = args.pos_args.remove(0).expr;
1145                            let key_value = ConstKeyValue::new(key, value);
1146                            ConstExpr::Dict(ConstDict::new(
1147                                Token::DUMMY,
1148                                Token::DUMMY,
1149                                vec![key_value],
1150                            ))
1151                        } else {
1152                            ConstExpr::App(ConstApp::new(obj, app.attr_name, args))
1153                        }
1154                    }
1155                    Some("GenericList" | "List") => {
1156                        if args.pos_args.len() == 2 {
1157                            let elem = args.pos_args.remove(0).expr;
1158                            let len = args.pos_args.remove(0).expr;
1159                            let l_brace = Token::dummy(TokenKind::LSqBr, "[");
1160                            let r_brace = Token::dummy(TokenKind::RSqBr, "]");
1161                            ConstExpr::List(ConstList::WithLength(ConstListWithLength::new(
1162                                l_brace, r_brace, elem, len,
1163                            )))
1164                        } else {
1165                            let obj = ConstExpr::Accessor(ConstAccessor::Local(
1166                                Identifier::private("List".into()),
1167                            ));
1168                            ConstExpr::App(ConstApp::new(obj, None, args))
1169                        }
1170                    }
1171                    Some("GenericTuple" | "Tuple") => {
1172                        if args.pos_args.get(1).is_some_and(|arg| matches!(&arg.expr, ConstExpr::Lit(l) if l.is(TokenKind::EllipsisLit))) {
1173                            let ty = args.pos_args.remove(0).expr;
1174                            let obj = ConstExpr::Accessor(ConstAccessor::Local(
1175                                Identifier::private("HomogenousTuple".into()),
1176                            ));
1177                            let args = ConstArgs::single(ty);
1178                            ConstExpr::App(ConstApp::new(obj, None, args))
1179                        } else {
1180                            let obj = ConstExpr::Accessor(ConstAccessor::Local(
1181                                Identifier::private("Tuple".into()),
1182                            ));
1183                            let range = ergloc_to_pyloc(args.loc());
1184                            let (l, r) = Self::gen_enclosure_tokens(TokenKind::LSqBr, range);
1185                            let list = ConstList::Normal(ConstNormalList::new(l, r, args, None));
1186                            let args = ConstArgs::single(ConstExpr::List(list));
1187                            ConstExpr::App(ConstApp::new(obj, None, args))
1188                        }
1189                    }
1190                    Some("Optional") => {
1191                        let arg = args.pos_args.remove(0).expr;
1192                        let none = ConstExpr::Accessor(ConstAccessor::Local(Identifier::private(
1193                            "NoneType".into(),
1194                        )));
1195                        let or_op = Token::dummy(TokenKind::OrOp, "or");
1196                        ConstExpr::BinOp(ConstBinOp::new(or_op, arg, none))
1197                    }
1198                    Some("Literal") => {
1199                        let set = ConstNormalSet::new(Token::DUMMY, Token::DUMMY, args);
1200                        ConstExpr::Set(ConstSet::Normal(set))
1201                    }
1202                    Some("Callable") => {
1203                        let params = if args.pos_args.is_empty() {
1204                            self.errs.push(CompileError::syntax_error(
1205                                self.cfg.input.clone(),
1206                                line!() as usize,
1207                                args.loc(),
1208                                self.cur_namespace(),
1209                                "`Callable` takes an input type list and a return type".into(),
1210                                None,
1211                            ));
1212                            ConstArgs::empty()
1213                        } else {
1214                            match args.pos_args.remove(0).expr {
1215                                ConstExpr::List(ConstList::Normal(list)) => list.elems,
1216                                other => {
1217                                    args.pos_args.insert(0, ConstPosArg::new(other));
1218                                    args.clone()
1219                                }
1220                            }
1221                        };
1222                        let non_defaults = params
1223                            .pos_args
1224                            .into_iter()
1225                            .map(|param| {
1226                                let expr = match param.expr.downgrade() {
1227                                    Expr::Literal(lit) if lit.is(TokenKind::NoneLit) => {
1228                                        Expr::Accessor(Accessor::Ident(Identifier::private(
1229                                            "NoneType".into(),
1230                                        )))
1231                                    }
1232                                    other => other,
1233                                };
1234                                let ty = Parser::expr_to_type_spec(expr.clone())
1235                                    .unwrap_or(TypeSpec::mono(Identifier::private("Any".into())));
1236                                let discard = Token::dummy(TokenKind::UBar, "_");
1237                                let t_spec = TypeSpecWithOp::new(
1238                                    Token::dummy(TokenKind::Colon, ":"),
1239                                    ty,
1240                                    expr,
1241                                );
1242                                NonDefaultParamSignature::new(
1243                                    ParamPattern::Discard(discard),
1244                                    Some(t_spec),
1245                                )
1246                            })
1247                            .collect();
1248                        let params = Params::new(non_defaults, None, vec![], None, None);
1249                        let ret = if args.pos_args.is_empty() {
1250                            self.errs.push(CompileError::syntax_error(
1251                                self.cfg.input.clone(),
1252                                line!() as usize,
1253                                args.loc(),
1254                                self.cur_namespace(),
1255                                "Expected a return type".into(),
1256                                None,
1257                            ));
1258                            ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Any".into())))
1259                        } else {
1260                            match args.pos_args.remove(0).expr {
1261                                ConstExpr::Lit(lit) if lit.is(TokenKind::NoneLit) => {
1262                                    ConstExpr::Accessor(ConstAccessor::Local(Identifier::private(
1263                                        "NoneType".into(),
1264                                    )))
1265                                }
1266                                other => other,
1267                            }
1268                        };
1269                        let op = Token::dummy(TokenKind::ProcArrow, "=>");
1270                        let body = ConstBlock::new(vec![ret]);
1271                        let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
1272                        ConstExpr::Lambda(ConstLambda::new(sig, op, body, DefId(0)))
1273                    }
1274                    _ => ConstExpr::App(ConstApp::new(obj, app.attr_name, args)),
1275                }
1276            }
1277            _ => expr.map(&mut |expr| self.convert_const_expr(expr)),
1278        }
1279    }
1280
1281    fn convert_expr_to_const(&mut self, expr: py_ast::Expr) -> Option<ConstExpr> {
1282        let expr = self.convert_expr(expr);
1283        match Parser::validate_const_expr(expr) {
1284            Ok(expr) => Some(self.convert_const_expr(expr)),
1285            Err(err) => {
1286                let err =
1287                    CompileError::new(err.into(), self.cfg.input.clone(), self.cur_namespace());
1288                self.errs.push(err);
1289                None
1290            }
1291        }
1292    }
1293
1294    // TODO:
1295    fn convert_compound_type_spec(&mut self, name: String, args: py_ast::Expr) -> TypeSpec {
1296        match &name[..] {
1297            "Union" => {
1298                let py_ast::Expr::Tuple(mut tuple) = args else {
1299                    let err = CompileError::syntax_error(
1300                        self.cfg.input.clone(),
1301                        line!() as usize,
1302                        pyloc_to_ergloc(args.range()),
1303                        self.cur_namespace(),
1304                        "`Union` takes at least 2 types".into(),
1305                        None,
1306                    );
1307                    self.errs.push(err);
1308                    return Self::gen_dummy_type_spec(args.location());
1309                };
1310                let lhs = self.convert_type_spec(tuple.elts.remove(0));
1311                if tuple.elts.is_empty() {
1312                    return lhs;
1313                }
1314                let rhs = self.convert_type_spec(tuple.elts.remove(0));
1315                let mut union = TypeSpec::or(lhs, rhs);
1316                for elem in tuple.elts {
1317                    let t = self.convert_type_spec(elem);
1318                    union = TypeSpec::or(union, t);
1319                }
1320                union
1321            }
1322            "Optional" => {
1323                let loc = args.location();
1324                let t = self.convert_type_spec(args);
1325                let ident = Identifier::private_with_line("NoneType".into(), loc.row.get());
1326                let none = TypeSpec::mono(ident);
1327                TypeSpec::or(t, none)
1328            }
1329            "Literal" => {
1330                let py_ast::Expr::Tuple(tuple) = args else {
1331                    return Self::gen_dummy_type_spec(args.location());
1332                };
1333                let mut elems = vec![];
1334                for elem in tuple.elts {
1335                    if let Some(expr) = self.convert_expr_to_const(elem) {
1336                        elems.push(ConstPosArg::new(expr));
1337                    }
1338                }
1339                let elems = ConstArgs::new(elems, None, vec![], None, None);
1340                TypeSpec::Enum(elems)
1341            }
1342            // TODO: Currently, these types are simply interpreted as inner types
1343            "Final" | "Required" | "NotRequired" | "ReadOnly" => self.convert_type_spec(args),
1344            // TODO: distinguish from collections.abc.Callable
1345            "Callable" => {
1346                let mut tuple = match args {
1347                    py_ast::Expr::Tuple(tuple) if tuple.elts.len() == 2 => tuple,
1348                    _ => {
1349                        let err = CompileError::syntax_error(
1350                            self.cfg.input.clone(),
1351                            line!() as usize,
1352                            pyloc_to_ergloc(args.range()),
1353                            self.cur_namespace(),
1354                            "`Callable` takes an input type list and a return type".into(),
1355                            None,
1356                        );
1357                        self.errs.push(err);
1358                        return Self::gen_dummy_type_spec(args.location());
1359                    }
1360                };
1361                let params = tuple.elts.remove(0);
1362                let mut non_defaults = vec![];
1363                match params {
1364                    py_ast::Expr::List(list) => {
1365                        for param in list.elts.into_iter() {
1366                            let t_spec = self.convert_type_spec(param);
1367                            non_defaults.push(ParamTySpec::anonymous(t_spec));
1368                        }
1369                    }
1370                    other => {
1371                        let err = CompileError::syntax_error(
1372                            self.cfg.input.clone(),
1373                            line!() as usize,
1374                            pyloc_to_ergloc(other.range()),
1375                            self.cur_namespace(),
1376                            "Expected a list of parameters".into(),
1377                            None,
1378                        );
1379                        self.errs.push(err);
1380                    }
1381                }
1382                let ret = self.convert_type_spec(tuple.elts.remove(0));
1383                TypeSpec::Subr(SubrTypeSpec::new(
1384                    TypeBoundSpecs::empty(),
1385                    None,
1386                    non_defaults,
1387                    None,
1388                    vec![],
1389                    None,
1390                    ARROW,
1391                    ret,
1392                ))
1393            }
1394            "Iterable" | "Iterator" | "Collection" | "Container" | "Sequence"
1395            | "MutableSequence" => {
1396                let elem_t = match self.convert_expr_to_const(args) {
1397                    Some(elem_t) => elem_t,
1398                    None => {
1399                        ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1400                    }
1401                };
1402                let elem_t = ConstPosArg::new(elem_t);
1403                let global =
1404                    ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
1405                let acc = ConstAccessor::Attr(ConstAttribute::new(
1406                    global,
1407                    Identifier::private(escape_name(name).into()),
1408                ));
1409                TypeSpec::poly(acc, ConstArgs::pos_only(vec![elem_t], None))
1410            }
1411            "Mapping" | "MutableMapping" => {
1412                let mut tuple = match args {
1413                    py_ast::Expr::Tuple(tuple) if tuple.elts.len() == 2 => tuple,
1414                    _ => {
1415                        let err = CompileError::syntax_error(
1416                            self.cfg.input.clone(),
1417                            line!() as usize,
1418                            pyloc_to_ergloc(args.range()),
1419                            self.cur_namespace(),
1420                            "`Mapping` takes 2 types".into(),
1421                            None,
1422                        );
1423                        self.errs.push(err);
1424                        return Self::gen_dummy_type_spec(args.location());
1425                    }
1426                };
1427                let key_t = match self.convert_expr_to_const(tuple.elts.remove(0)) {
1428                    Some(key_t) => key_t,
1429                    None => {
1430                        ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1431                    }
1432                };
1433                let key_t = ConstPosArg::new(key_t);
1434                let value_t = match self.convert_expr_to_const(tuple.elts.remove(0)) {
1435                    Some(value_t) => value_t,
1436                    None => {
1437                        ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1438                    }
1439                };
1440                let value_t = ConstPosArg::new(value_t);
1441                let global =
1442                    ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
1443                let acc = ConstAccessor::Attr(ConstAttribute::new(
1444                    global,
1445                    Identifier::private(escape_name(name).into()),
1446                ));
1447                TypeSpec::poly(acc, ConstArgs::pos_only(vec![key_t, value_t], None))
1448            }
1449            "List" | "list" => {
1450                let len = ConstExpr::Accessor(ConstAccessor::Local(Identifier::private_with_loc(
1451                    "_".into(),
1452                    pyloc_to_ergloc(args.range()),
1453                )));
1454                let elem_t = match self.convert_expr_to_const(args) {
1455                    Some(elem_t) => elem_t,
1456                    None => {
1457                        ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1458                    }
1459                };
1460                let elem_t = ConstPosArg::new(elem_t);
1461                let len = ConstPosArg::new(len);
1462                let global =
1463                    ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
1464                let acc = ConstAccessor::Attr(ConstAttribute::new(
1465                    global,
1466                    Identifier::private("List!".into()),
1467                ));
1468                TypeSpec::poly(
1469                    acc,
1470                    ConstArgs::new(vec![elem_t, len], None, vec![], None, None),
1471                )
1472            }
1473            "Dict" | "dict" => {
1474                let mut tuple = match args {
1475                    py_ast::Expr::Tuple(tuple) if tuple.elts.len() == 2 => tuple,
1476                    _ => {
1477                        let err = CompileError::syntax_error(
1478                            self.cfg.input.clone(),
1479                            line!() as usize,
1480                            pyloc_to_ergloc(args.range()),
1481                            self.cur_namespace(),
1482                            "`dict` takes 2 types".into(),
1483                            None,
1484                        );
1485                        self.errs.push(err);
1486                        return Self::gen_dummy_type_spec(args.location());
1487                    }
1488                };
1489                let (l_brace, r_brace) = Self::gen_enclosure_tokens(TokenKind::LBrace, tuple.range);
1490                let key_t = match self.convert_expr_to_const(tuple.elts.remove(0)) {
1491                    Some(key_t) => key_t,
1492                    None => {
1493                        ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1494                    }
1495                };
1496                let val_t = match self.convert_expr_to_const(tuple.elts.remove(0)) {
1497                    Some(val_t) => val_t,
1498                    None => {
1499                        ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1500                    }
1501                };
1502                let dict = ConstPosArg::new(ConstExpr::Dict(ConstDict::new(
1503                    l_brace,
1504                    r_brace,
1505                    vec![ConstKeyValue::new(key_t, val_t)],
1506                )));
1507                let global =
1508                    ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
1509                let acc = ConstAccessor::Attr(ConstAttribute::new(
1510                    global,
1511                    Identifier::private("Dict!".into()),
1512                ));
1513                TypeSpec::poly(acc, ConstArgs::new(vec![dict], None, vec![], None, None))
1514            }
1515            "Tuple" | "tuple" => {
1516                let py_ast::Expr::Tuple(mut tuple) = args else {
1517                    return Self::gen_dummy_type_spec(args.location());
1518                };
1519                // tuple[T, ...] == HomogenousTuple T
1520                if tuple.elts.get(1).is_some_and(|ex| matches!(ex, py_ast::Expr::Constant(c) if matches!(c.value, py_ast::Constant::Ellipsis))) {
1521                    let acc = ConstAccessor::local(Token::symbol("HomogenousTuple"));
1522                    let ty = tuple.elts.remove(0);
1523                    let args = ConstArgs::single(self.convert_expr_to_const(ty).unwrap());
1524                    return TypeSpec::poly(acc, args);
1525                }
1526                let tys = tuple
1527                    .elts
1528                    .into_iter()
1529                    .map(|elem| self.convert_type_spec(elem))
1530                    .collect();
1531                let (l, r) = Self::gen_enclosure_tokens(TokenKind::LParen, tuple.range);
1532                let tuple = TupleTypeSpec::new(Some((l.loc(), r.loc())), tys);
1533                TypeSpec::Tuple(tuple)
1534            }
1535            "Set" | "set" => {
1536                let elem_t = match self.convert_expr_to_const(args) {
1537                    Some(elem_t) => elem_t,
1538                    None => {
1539                        ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("Obj".into())))
1540                    }
1541                };
1542                let elem_t = ConstPosArg::new(elem_t);
1543                let global =
1544                    ConstExpr::Accessor(ConstAccessor::Local(Identifier::private("global".into())));
1545                let acc = ConstAccessor::Attr(ConstAttribute::new(
1546                    global,
1547                    Identifier::private("Set!".into()),
1548                ));
1549                TypeSpec::poly(acc, ConstArgs::pos_only(vec![elem_t], None))
1550            }
1551            _ => Self::gen_dummy_type_spec(args.location()),
1552        }
1553    }
1554
1555    fn convert_type_spec(&mut self, expr: py_ast::Expr) -> TypeSpec {
1556        match expr {
1557            py_ast::Expr::Name(name) => {
1558                self.contexts
1559                    .last_mut()
1560                    .unwrap()
1561                    .appeared_type_names
1562                    .insert(name.id.to_string());
1563                self.convert_ident_type_spec(name.id.to_string(), name.range)
1564            }
1565            py_ast::Expr::Constant(cons) => {
1566                if cons.value.is_none() {
1567                    self.convert_ident_type_spec("NoneType".into(), cons.range)
1568                } else if let Some(name) = cons.value.as_str() {
1569                    self.convert_ident_type_spec(name.into(), cons.range)
1570                } else {
1571                    let err = CompileError::syntax_error(
1572                        self.cfg.input.clone(),
1573                        line!() as usize,
1574                        pyloc_to_ergloc(cons.range()),
1575                        self.cur_namespace(),
1576                        format!("{:?} is not a type", cons.value),
1577                        None,
1578                    );
1579                    self.errs.push(err);
1580                    Self::gen_dummy_type_spec(cons.location())
1581                }
1582            }
1583            py_ast::Expr::Attribute(attr) => {
1584                let namespace = Box::new(self.convert_expr(*attr.value));
1585                let t = self.convert_ident(attr.attr.to_string(), attr_name_loc(&namespace));
1586                if namespace
1587                    .full_name()
1588                    .is_some_and(|n| n == "typing" || n == "collections.abc")
1589                {
1590                    match &t.inspect()[..] {
1591                        global_unary_collections!()
1592                        | global_mutable_unary_collections!()
1593                        | global_binary_collections!() => {
1594                            return self.convert_ident_type_spec(attr.attr.to_string(), attr.range)
1595                        }
1596                        "Any" => return TypeSpec::PreDeclTy(PreDeclTypeSpec::Mono(t)),
1597                        _ => {}
1598                    }
1599                }
1600                let predecl = PreDeclTypeSpec::Attr { namespace, t };
1601                TypeSpec::PreDeclTy(predecl)
1602            }
1603            // value[slice]
1604            py_ast::Expr::Subscript(subs) => match *subs.value {
1605                py_ast::Expr::Name(name) => {
1606                    self.convert_compound_type_spec(name.id.to_string(), *subs.slice)
1607                }
1608                py_ast::Expr::Attribute(attr) => {
1609                    let loc = attr.location();
1610                    match accessor_name(*attr.value).as_ref().map(|s| &s[..]) {
1611                        Some("typing" | "collections.abc") => {
1612                            self.convert_compound_type_spec(attr.attr.to_string(), *subs.slice)
1613                        }
1614                        other => {
1615                            log!(err "unknown: {other:?}");
1616                            Self::gen_dummy_type_spec(loc)
1617                        }
1618                    }
1619                }
1620                other => {
1621                    log!(err "unknown: {other:?}");
1622                    Self::gen_dummy_type_spec(other.location())
1623                }
1624            },
1625            py_ast::Expr::BinOp(bin) => {
1626                let loc = bin.location();
1627                match bin.op {
1628                    // A | B
1629                    Operator::BitOr => {
1630                        let lhs = self.convert_type_spec(*bin.left);
1631                        let rhs = self.convert_type_spec(*bin.right);
1632                        TypeSpec::or(lhs, rhs)
1633                    }
1634                    _ => Self::gen_dummy_type_spec(loc),
1635                }
1636            }
1637            other => {
1638                log!(err "unknown: {other:?}");
1639                Self::gen_dummy_type_spec(other.location())
1640            }
1641        }
1642    }
1643
1644    fn gen_enclosure_tokens(l_kind: TokenKind, expr_range: PySourceRange) -> (Token, Token) {
1645        let (l_cont, r_cont, r_kind) = match l_kind {
1646            TokenKind::LBrace => ("{", "}", TokenKind::RBrace),
1647            TokenKind::LParen => ("(", ")", TokenKind::RParen),
1648            TokenKind::LSqBr => ("[", "]", TokenKind::RSqBr),
1649            _ => unreachable!(),
1650        };
1651        let (line_end, c_end) = (
1652            expr_range.end.unwrap_or(expr_range.start).row.get(),
1653            expr_range
1654                .end
1655                .unwrap_or(expr_range.start)
1656                .column
1657                .to_zero_indexed(),
1658        );
1659        let l_brace = Token::new(
1660            l_kind,
1661            l_cont,
1662            expr_range.start.row.get(),
1663            expr_range.start.column.to_zero_indexed(),
1664        );
1665        let r_brace = Token::new(r_kind, r_cont, line_end, c_end);
1666        (l_brace, r_brace)
1667    }
1668
1669    fn mutate_expr(expr: Expr) -> Expr {
1670        let mut_op = Token::new(
1671            TokenKind::Mutate,
1672            "!",
1673            expr.ln_begin().unwrap_or(0),
1674            expr.col_begin().unwrap_or(0),
1675        );
1676        Expr::UnaryOp(UnaryOp::new(mut_op, expr))
1677    }
1678
1679    fn convert_const(&mut self, const_: ExprConstant) -> Expr {
1680        let loc = const_.location();
1681        match const_.value {
1682            py_ast::Constant::Int(i) => {
1683                let kind = if i >= 0.into() {
1684                    TokenKind::NatLit
1685                } else {
1686                    TokenKind::IntLit
1687                };
1688                let token = Token::new(
1689                    kind,
1690                    i.to_string(),
1691                    loc.row.get(),
1692                    loc.column.to_zero_indexed(),
1693                );
1694                Expr::Literal(Literal::new(token))
1695            }
1696            py_ast::Constant::Float(f) => {
1697                let token = Token::new(
1698                    TokenKind::RatioLit,
1699                    f.to_string(),
1700                    const_.location().row.get(),
1701                    const_.location().column.to_zero_indexed(),
1702                );
1703                Expr::Literal(Literal::new(token))
1704            }
1705            py_ast::Constant::Complex { real: _, imag: _ } => Expr::Dummy(Dummy::new(None, vec![])),
1706            py_ast::Constant::Str(value) => {
1707                let kind = if const_
1708                    .range
1709                    .end
1710                    .is_some_and(|end| end.row != const_.range.start.row)
1711                {
1712                    TokenKind::DocComment
1713                } else {
1714                    TokenKind::StrLit
1715                };
1716                let value = format!("\"{value}\"");
1717                // column - 2 because of the quotes
1718                let token = Token::new(kind, value, loc.row.get(), loc.column.to_zero_indexed());
1719                Expr::Literal(Literal::new(token))
1720            }
1721            py_ast::Constant::Bool(b) => {
1722                let cont = if b { "True" } else { "False" };
1723                Expr::Literal(Literal::new(Token::new(
1724                    TokenKind::BoolLit,
1725                    cont,
1726                    loc.row.get(),
1727                    loc.column.to_zero_indexed(),
1728                )))
1729            }
1730            py_ast::Constant::None => Expr::Literal(Literal::new(Token::new(
1731                TokenKind::NoneLit,
1732                "None",
1733                const_.location().row.get(),
1734                const_.location().column.to_zero_indexed(),
1735            ))),
1736            py_ast::Constant::Ellipsis => Expr::Literal(Literal::new(Token::new(
1737                TokenKind::EllipsisLit,
1738                "...",
1739                const_.location().row.get(),
1740                const_.location().column.to_zero_indexed(),
1741            ))),
1742            // Bytes, Tuple
1743            other => {
1744                log!(err "unknown: {other:?}");
1745                Expr::Dummy(Dummy::new(None, vec![]))
1746            }
1747        }
1748    }
1749
1750    fn convert_expr(&mut self, expr: py_ast::Expr) -> Expr {
1751        match expr {
1752            py_ast::Expr::Constant(const_) => self.convert_const(const_),
1753            py_ast::Expr::Name(name) => {
1754                let ident = self.convert_ident(name.id.to_string(), name.location());
1755                Expr::Accessor(Accessor::Ident(ident))
1756            }
1757            py_ast::Expr::Attribute(attr) => {
1758                let value = self.convert_expr(*attr.value);
1759                let name = self.convert_attr_ident(attr.attr.to_string(), attr_name_loc(&value));
1760                value.attr_expr(name)
1761            }
1762            py_ast::Expr::IfExp(if_) => {
1763                let loc = if_.location();
1764                let block = self.convert_expr(*if_.body);
1765                let params = Params::new(vec![], None, vec![], None, None);
1766                let sig = LambdaSignature::new(params.clone(), None, TypeBoundSpecs::empty());
1767                let body = Lambda::new(sig, Token::DUMMY, Block::new(vec![block]), DefId(0));
1768                let test = self.convert_expr(*if_.test);
1769                let if_ident = self.convert_ident("if".to_string(), loc);
1770                let if_acc = Expr::Accessor(Accessor::Ident(if_ident));
1771                let else_block = self.convert_expr(*if_.orelse);
1772                let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
1773                let else_body =
1774                    Lambda::new(sig, Token::DUMMY, Block::new(vec![else_block]), DefId(0));
1775                let args = Args::pos_only(
1776                    vec![
1777                        PosArg::new(test),
1778                        PosArg::new(Expr::Lambda(body)),
1779                        PosArg::new(Expr::Lambda(else_body)),
1780                    ],
1781                    None,
1782                );
1783                if_acc.call_expr(args)
1784            }
1785            py_ast::Expr::Call(call) => {
1786                let loc = call.location();
1787                let end_loc = call.end_location();
1788                let function = self.convert_expr(*call.func);
1789                let (pos_args, var_args): (Vec<_>, _) = call
1790                    .args
1791                    .into_iter()
1792                    .partition(|arg| !arg.is_starred_expr());
1793                let pos_args = pos_args
1794                    .into_iter()
1795                    .map(|ex| PosArg::new(self.convert_expr(ex)))
1796                    .collect::<Vec<_>>();
1797                let var_args = var_args
1798                    .into_iter()
1799                    .map(|ex| {
1800                        let py_ast::Expr::Starred(star) = ex else {
1801                            unreachable!()
1802                        };
1803                        PosArg::new(self.convert_expr(*star.value))
1804                    })
1805                    .next();
1806                let (kw_args, kw_var): (Vec<_>, _) =
1807                    call.keywords.into_iter().partition(|kw| kw.arg.is_some());
1808                let kw_args = kw_args
1809                    .into_iter()
1810                    .map(|Keyword { arg, value, range }| {
1811                        let name = Token::symbol_with_loc(
1812                            arg.unwrap().to_string(),
1813                            pyloc_to_ergloc(range),
1814                        );
1815                        let ex = self.convert_expr(value);
1816                        KwArg::new(name, None, ex)
1817                    })
1818                    .collect();
1819                let kw_var = kw_var
1820                    .into_iter()
1821                    .map(|Keyword { value, .. }| PosArg::new(self.convert_expr(value)))
1822                    .next();
1823                let last_col = end_loc.map_or_else(
1824                    || {
1825                        pos_args
1826                            .last()
1827                            .and_then(|last| last.col_end())
1828                            .unwrap_or(function.col_end().unwrap_or(0) + 1)
1829                    },
1830                    |loc| loc.column.to_zero_indexed().saturating_sub(1),
1831                );
1832                let paren = {
1833                    let lp = Token::new(
1834                        TokenKind::LParen,
1835                        "(",
1836                        loc.row.get(),
1837                        function.col_end().unwrap_or(0),
1838                    );
1839                    let rp = Token::new(TokenKind::RParen, ")", loc.row.get(), last_col);
1840                    (lp.loc(), rp.loc())
1841                };
1842                let args = Args::new(pos_args, var_args, kw_args, kw_var, Some(paren));
1843                function.call_expr(args)
1844            }
1845            py_ast::Expr::BinOp(bin) => {
1846                let lhs = self.convert_expr(*bin.left);
1847                let rhs = self.convert_expr(*bin.right);
1848                let op = op_to_token(bin.op);
1849                Expr::BinOp(BinOp::new(op, lhs, rhs))
1850            }
1851            py_ast::Expr::UnaryOp(un) => {
1852                let rhs = self.convert_expr(*un.operand);
1853                let (kind, cont) = match un.op {
1854                    UnOp::UAdd => (TokenKind::PrePlus, "+"),
1855                    UnOp::USub => (TokenKind::PreMinus, "-"),
1856                    UnOp::Invert => (TokenKind::PreBitNot, "~"),
1857                    UnOp::Not => return Expr::Call(Identifier::public("not".into()).call1(rhs)),
1858                };
1859                let op = Token::from_str(kind, cont);
1860                Expr::UnaryOp(UnaryOp::new(op, rhs))
1861            }
1862            // TODO
1863            py_ast::Expr::BoolOp(mut boole) => {
1864                let lhs = self.convert_expr(boole.values.remove(0));
1865                let rhs = self.convert_expr(boole.values.remove(0));
1866                let (kind, cont) = match boole.op {
1867                    BoolOp::And => (TokenKind::AndOp, "and"),
1868                    BoolOp::Or => (TokenKind::OrOp, "or"),
1869                };
1870                let op = Token::from_str(kind, cont);
1871                Expr::BinOp(BinOp::new(op, lhs, rhs))
1872            }
1873            // TODO: multiple CmpOps
1874            py_ast::Expr::Compare(mut cmp) => {
1875                let lhs = self.convert_expr(*cmp.left);
1876                let rhs = self.convert_expr(cmp.comparators.remove(0));
1877                let (kind, cont) = match cmp.ops.remove(0) {
1878                    CmpOp::Eq => (TokenKind::DblEq, "=="),
1879                    CmpOp::NotEq => (TokenKind::NotEq, "!="),
1880                    CmpOp::Lt => (TokenKind::Less, "<"),
1881                    CmpOp::LtE => (TokenKind::LessEq, "<="),
1882                    CmpOp::Gt => (TokenKind::Gre, ">"),
1883                    CmpOp::GtE => (TokenKind::GreEq, ">="),
1884                    CmpOp::Is => (TokenKind::IsOp, "is!"),
1885                    CmpOp::IsNot => (TokenKind::IsNotOp, "isnot!"),
1886                    CmpOp::In => (TokenKind::InOp, "in"),
1887                    CmpOp::NotIn => (TokenKind::NotInOp, "notin"),
1888                };
1889                let op = Token::from_str(kind, cont);
1890                Expr::BinOp(BinOp::new(op, lhs, rhs))
1891            }
1892            py_ast::Expr::Lambda(lambda) => {
1893                self.grow("<lambda>".to_string(), BlockKind::Function);
1894                let params = self.convert_params(*lambda.args);
1895                let body = vec![self.convert_expr(*lambda.body)];
1896                self.pop();
1897                let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
1898                let op = Token::from_str(TokenKind::FuncArrow, "->");
1899                Expr::Lambda(Lambda::new(sig, op, Block::new(body), DefId(0)))
1900            }
1901            py_ast::Expr::List(list) => {
1902                let (l_sqbr, r_sqbr) = Self::gen_enclosure_tokens(TokenKind::LSqBr, list.range);
1903                let elements = list
1904                    .elts
1905                    .into_iter()
1906                    .map(|ex| PosArg::new(self.convert_expr(ex)))
1907                    .collect::<Vec<_>>();
1908                let elems = Args::pos_only(elements, None);
1909                let arr = Expr::List(List::Normal(NormalList::new(l_sqbr, r_sqbr, elems)));
1910                Self::mutate_expr(arr)
1911            }
1912            py_ast::Expr::ListComp(comp) => {
1913                let (l_sqbr, r_sqbr) = Self::gen_enclosure_tokens(TokenKind::LSqBr, comp.range);
1914                let layout = self.convert_expr(*comp.elt);
1915                let generator = comp.generators.into_iter().next().unwrap();
1916                let target = self.convert_expr(generator.target);
1917                let Expr::Accessor(Accessor::Ident(ident)) = target else {
1918                    log!(err "unimplemented: {target}");
1919                    let loc = pyloc_to_ergloc(comp.range);
1920                    return Expr::Dummy(Dummy::new(Some(loc), vec![]));
1921                };
1922                let iter = self.convert_expr(generator.iter);
1923                let guard = generator
1924                    .ifs
1925                    .into_iter()
1926                    .next()
1927                    .map(|ex| self.convert_expr(ex));
1928                let generators = vec![(ident, iter)];
1929                let arr = Expr::List(List::Comprehension(ListComprehension::new(
1930                    l_sqbr,
1931                    r_sqbr,
1932                    Some(layout),
1933                    generators,
1934                    guard,
1935                )));
1936                Self::mutate_expr(arr)
1937            }
1938            py_ast::Expr::Set(set) => {
1939                let (l_brace, r_brace) = Self::gen_enclosure_tokens(TokenKind::LBrace, set.range);
1940                let elements = set
1941                    .elts
1942                    .into_iter()
1943                    .map(|ex| PosArg::new(self.convert_expr(ex)))
1944                    .collect::<Vec<_>>();
1945                let elems = Args::pos_only(elements, None);
1946                let set = Expr::Set(Set::Normal(NormalSet::new(l_brace, r_brace, elems)));
1947                Self::mutate_expr(set)
1948            }
1949            py_ast::Expr::SetComp(comp) => {
1950                let (l_brace, r_brace) = Self::gen_enclosure_tokens(TokenKind::LBrace, comp.range);
1951                let layout = self.convert_expr(*comp.elt);
1952                let generator = comp.generators.into_iter().next().unwrap();
1953                let target = self.convert_expr(generator.target);
1954                let Expr::Accessor(Accessor::Ident(ident)) = target else {
1955                    log!(err "unimplemented: {target}");
1956                    let loc = pyloc_to_ergloc(comp.range);
1957                    return Expr::Dummy(Dummy::new(Some(loc), vec![]));
1958                };
1959                let iter = self.convert_expr(generator.iter);
1960                let guard = generator
1961                    .ifs
1962                    .into_iter()
1963                    .next()
1964                    .map(|ex| self.convert_expr(ex));
1965                let generators = vec![(ident, iter)];
1966                let set = Expr::Set(Set::Comprehension(SetComprehension::new(
1967                    l_brace,
1968                    r_brace,
1969                    Some(layout),
1970                    generators,
1971                    guard,
1972                )));
1973                Self::mutate_expr(set)
1974            }
1975            py_ast::Expr::Dict(dict) => {
1976                let (l_brace, r_brace) = Self::gen_enclosure_tokens(TokenKind::LBrace, dict.range);
1977                let kvs = dict
1978                    .keys
1979                    .into_iter()
1980                    .zip(dict.values)
1981                    .map(|(k, v)| {
1982                        KeyValue::new(
1983                            k.map(|k| self.convert_expr(k))
1984                                .unwrap_or(Expr::Dummy(Dummy::new(None, vec![]))),
1985                            self.convert_expr(v),
1986                        )
1987                    })
1988                    .collect::<Vec<_>>();
1989                let dict = Expr::Dict(Dict::Normal(NormalDict::new(l_brace, r_brace, kvs)));
1990                Self::mutate_expr(dict)
1991            }
1992            py_ast::Expr::DictComp(comp) => {
1993                let (l_brace, r_brace) = Self::gen_enclosure_tokens(TokenKind::LBrace, comp.range);
1994                let key = self.convert_expr(*comp.key);
1995                let value = self.convert_expr(*comp.value);
1996                let kv = KeyValue::new(key, value);
1997                let generator = comp.generators.into_iter().next().unwrap();
1998                let target = self.convert_expr(generator.target);
1999                let Expr::Accessor(Accessor::Ident(ident)) = target else {
2000                    log!(err "unimplemented: {target}");
2001                    let loc = pyloc_to_ergloc(comp.range);
2002                    return Expr::Dummy(Dummy::new(Some(loc), vec![]));
2003                };
2004                let iter = self.convert_expr(generator.iter);
2005                let guard = generator
2006                    .ifs
2007                    .into_iter()
2008                    .next()
2009                    .map(|ex| self.convert_expr(ex));
2010                let generators = vec![(ident, iter)];
2011                let dict = Expr::Dict(Dict::Comprehension(DictComprehension::new(
2012                    l_brace, r_brace, kv, generators, guard,
2013                )));
2014                Self::mutate_expr(dict)
2015            }
2016            py_ast::Expr::Tuple(tuple) => {
2017                let (l, r) = Self::gen_enclosure_tokens(TokenKind::LParen, tuple.range);
2018                let elements = tuple
2019                    .elts
2020                    .into_iter()
2021                    .map(|ex| PosArg::new(self.convert_expr(ex)))
2022                    .collect::<Vec<_>>();
2023                let elems = Args::pos_only(elements, Some((l.loc(), r.loc())));
2024                Expr::Tuple(Tuple::Normal(NormalTuple::new(elems)))
2025            }
2026            py_ast::Expr::Subscript(subs) => {
2027                let obj = self.convert_expr(*subs.value);
2028                // List[T] => List!(T)
2029                if obj.get_name().is_some_and(|n| self.is_type_name(n)) {
2030                    let obj = if obj.get_name().is_some_and(|n| n == "List") {
2031                        let global = self.convert_ident("global".to_string(), subs.range.start);
2032                        Expr::from(global).attr_expr(Identifier::private("List!".into()))
2033                    } else if obj.get_name().is_some_and(|n| n == "Set") {
2034                        let global = self.convert_ident("global".to_string(), subs.range.start);
2035                        Expr::from(global).attr_expr(Identifier::private("Set!".into()))
2036                    } else {
2037                        obj
2038                    };
2039                    return obj.call1(self.convert_expr(*subs.slice));
2040                }
2041                let method = obj.attr_expr(
2042                    self.convert_ident("__getitem__".to_string(), subs.slice.location()),
2043                );
2044                method.call1(self.convert_expr(*subs.slice))
2045            }
2046            // [:] == [slice(None)]
2047            // [start:] == [slice(start, None)]
2048            // [:stop] == [slice(stop)]
2049            // [start:stop] == [slice(start, stop)]
2050            // [start:stop:step] == [slice(start, stop, step)]
2051            py_ast::Expr::Slice(slice) => {
2052                let loc = slice.location();
2053                let start = slice.lower.map(|ex| self.convert_expr(*ex));
2054                let stop = slice.upper.map(|ex| self.convert_expr(*ex));
2055                let step = slice.step.map(|ex| self.convert_expr(*ex));
2056                let mut args = Args::empty();
2057                if let Some(start) = start {
2058                    args.push_pos(PosArg::new(start));
2059                }
2060                if let Some(stop) = stop {
2061                    args.push_pos(PosArg::new(stop));
2062                }
2063                if let Some(step) = step {
2064                    args.push_pos(PosArg::new(step));
2065                }
2066                if args.is_empty() {
2067                    args.push_pos(PosArg::new(Expr::Literal(Literal::new(Token::new(
2068                        TokenKind::NoneLit,
2069                        "None",
2070                        loc.row.get(),
2071                        loc.column.to_zero_indexed(),
2072                    )))));
2073                }
2074                let slice = self.convert_ident("slice".to_string(), loc);
2075                slice.call(args).into()
2076            }
2077            py_ast::Expr::JoinedStr(string) => {
2078                if string.values.is_empty() {
2079                    let loc = string.location();
2080                    let stringify = self.convert_ident("str".to_string(), loc);
2081                    return stringify.call(Args::empty()).into();
2082                } else if string.values.len() == 1 {
2083                    let loc = string.location();
2084                    let mut values = string.values;
2085                    let expr = self.convert_expr(values.remove(0));
2086                    let stringify = self.convert_ident("str".to_string(), loc);
2087                    return stringify.call1(expr).into();
2088                }
2089                let mut values = vec![];
2090                for value in string.values {
2091                    match value {
2092                        py_ast::Expr::Constant(cons) => {
2093                            let cons = self.convert_const(cons);
2094                            values.push(cons);
2095                        }
2096                        py_ast::Expr::FormattedValue(form) => {
2097                            let loc = form.location();
2098                            let expr = self.convert_expr(*form.value);
2099                            let stringify = self.convert_ident("str".to_string(), loc);
2100                            values.push(stringify.call1(expr).into());
2101                        }
2102                        _ => {}
2103                    }
2104                }
2105                let fst = values.remove(0);
2106                values.into_iter().fold(fst, |acc, expr| {
2107                    let plus = Token::dummy(TokenKind::Plus, "+");
2108                    Expr::BinOp(BinOp::new(plus, acc, expr))
2109                })
2110            }
2111            py_ast::Expr::FormattedValue(form) => {
2112                let loc = form.location();
2113                let expr = self.convert_expr(*form.value);
2114                let stringify = self.convert_ident("str".to_string(), loc);
2115                stringify.call1(expr).into()
2116            }
2117            py_ast::Expr::NamedExpr(named) => {
2118                let loc = named.location();
2119                let target = self.convert_expr(*named.target);
2120                let target_pat = match &target {
2121                    Expr::Accessor(Accessor::Ident(ident)) => VarPattern::Ident(ident.clone()),
2122                    _ => {
2123                        log!(err "unimplemented: {:?}", target);
2124                        VarPattern::Ident(Identifier::private("_".into()))
2125                    }
2126                };
2127                let value = self.convert_expr(*named.value);
2128                let assign = Token::new(
2129                    TokenKind::Assign,
2130                    "=",
2131                    loc.row.get(),
2132                    loc.column.to_zero_indexed(),
2133                );
2134                let def = Def::new(
2135                    Signature::Var(VarSignature::new(target_pat, None)),
2136                    DefBody::new(assign, Block::new(vec![value]), DefId(0)),
2137                );
2138                Expr::Compound(Compound::new(vec![Expr::Def(def), target]))
2139            }
2140            py_ast::Expr::Yield(_) => {
2141                self.cur_context_mut().return_kind = ReturnKind::Yield;
2142                log!(err "unimplemented: {:?}", expr);
2143                Expr::Dummy(Dummy::new(None, vec![]))
2144            }
2145            _other => {
2146                log!(err "unimplemented: {:?}", _other);
2147                Expr::Dummy(Dummy::new(None, vec![]))
2148            }
2149        }
2150    }
2151
2152    fn convert_block(&mut self, block: Suite, kind: BlockKind) -> Block {
2153        let mut new_block = Vec::new();
2154        let len = block.len();
2155        self.block_id_counter += 1;
2156        self.blocks.push(BlockInfo {
2157            id: self.block_id_counter,
2158            kind,
2159        });
2160        for (i, stmt) in block.into_iter().enumerate() {
2161            let is_last = i == len - 1;
2162            new_block.push(self.convert_statement(stmt, is_last && kind.is_function()));
2163        }
2164        self.blocks.pop();
2165        Block::new(new_block)
2166    }
2167
2168    #[allow(clippy::result_large_err)]
2169    fn check_init_sig(&self, sig: &Signature) -> Result<(), (bool, CompileError)> {
2170        match sig {
2171            Signature::Subr(subr) => {
2172                if let Some(first) = subr.params.non_defaults.first() {
2173                    if first.inspect().map(|s| &s[..]) == Some("self") {
2174                        return Ok(());
2175                    }
2176                }
2177                Err((
2178                    true,
2179                    self_not_found_error(self.cfg.input.clone(), subr.loc(), self.cur_namespace()),
2180                ))
2181            }
2182            Signature::Var(var) => Err((
2183                false,
2184                init_var_error(self.cfg.input.clone(), var.loc(), self.cur_namespace()),
2185            )),
2186        }
2187    }
2188
2189    // ```python
2190    // def __init__(self, x: Int, y: Int, z):
2191    //     self.x = x
2192    //     self.y = y
2193    //     if True:
2194    //         self.set_z(z)
2195    //
2196    // def set_z(self, z):
2197    //     self.z = z
2198    // ```
2199    // ↓
2200    // methods: {"set_z"}
2201    #[allow(clippy::only_used_in_recursion)]
2202    fn collect_called_methods(&self, expr: &Expr, methods: &mut HashSet<String>) {
2203        expr.traverse(&mut |ex| {
2204            if let Expr::Call(call) = ex {
2205                match call.obj.as_ref() {
2206                    Expr::Accessor(Accessor::Ident(ident)) if ident.inspect() == "self" => {
2207                        if let Some(method_ident) = &call.attr_name {
2208                            methods.insert(method_ident.inspect().to_string());
2209                        } else {
2210                            self.collect_called_methods(&call.obj, methods);
2211                        }
2212                    }
2213                    _ => self.collect_called_methods(ex, methods),
2214                }
2215            } else {
2216                self.collect_called_methods(ex, methods);
2217            }
2218        });
2219    }
2220
2221    // def __init__(self, x: Int, y: Int, z):
2222    //     self.x = x
2223    //     self.y = y
2224    //     self.z = z
2225    // ↓
2226    // requirement : {x: Int, y: Int, z: Any}
2227    // returns     : .__call__(x: Int, y: Int, z: Obj): Self = .unreachable()
2228    fn extract_init(
2229        &mut self,
2230        base_type: &mut Option<Expr>,
2231        init_def: Def,
2232        attrs: &[ClassAttr],
2233        pre_check: bool,
2234    ) -> Option<Def> {
2235        if let Err((continuable, err)) = self.check_init_sig(&init_def.sig) {
2236            if pre_check {
2237                self.errs.push(err);
2238            }
2239            if !continuable {
2240                return None;
2241            }
2242        }
2243        let l_brace = Token::new(
2244            TokenKind::LBrace,
2245            "{",
2246            init_def.ln_begin().unwrap_or(0),
2247            init_def.col_begin().unwrap_or(0),
2248        );
2249        let r_brace = Token::new(
2250            TokenKind::RBrace,
2251            "}",
2252            init_def.ln_end().unwrap_or(0),
2253            init_def.col_end().unwrap_or(0),
2254        );
2255        let expr = Expr::Def(init_def.clone());
2256        let Signature::Subr(sig) = init_def.sig else {
2257            unreachable!()
2258        };
2259        let mut fields = vec![];
2260        self.extract_instance_attrs(&sig, &init_def.body.block, &mut fields);
2261        let mut method_names = HashSet::new();
2262        self.collect_called_methods(&expr, &mut method_names);
2263        for class_attr in attrs {
2264            if let ClassAttr::Def(def) = class_attr {
2265                if let Signature::Subr(sig) = &def.sig {
2266                    if method_names.contains(&sig.ident.inspect()[..]) {
2267                        self.extract_instance_attrs(sig, &def.body.block, &mut fields);
2268                    }
2269                }
2270            }
2271        }
2272        if let Some(Expr::Record(Record::Normal(rec))) = base_type.as_mut() {
2273            let no_exist_fields = fields
2274                .into_iter()
2275                .filter(|field| {
2276                    rec.attrs
2277                        .iter()
2278                        .all(|rec_field| rec_field.sig.ident() != field.sig.ident())
2279                })
2280                .collect::<Vec<_>>();
2281            rec.attrs.extend(no_exist_fields);
2282        } else {
2283            let record = Record::Normal(NormalRecord::new(
2284                l_brace,
2285                r_brace,
2286                RecordAttrs::new(fields),
2287            ));
2288            *base_type = Some(Expr::Record(record));
2289        }
2290        let call_ident = Identifier::new(
2291            VisModifierSpec::Public(ErgLocation::Unknown),
2292            VarName::from_static("__call__"),
2293        );
2294        let class_ident = Identifier::public_with_line(
2295            DOT,
2296            self.cur_name().to_string().into(),
2297            sig.ln_begin().unwrap_or(0),
2298        );
2299        let class_ident_expr = Expr::Accessor(Accessor::Ident(class_ident.clone()));
2300        let class_spec = TypeSpecWithOp::new(COLON, TypeSpec::mono(class_ident), class_ident_expr);
2301        let mut params = sig.params.clone();
2302        if params
2303            .non_defaults
2304            .first()
2305            .is_some_and(|param| param.inspect().map(|s| &s[..]) == Some("self"))
2306        {
2307            params.non_defaults.remove(0);
2308        }
2309        let sig = Signature::Subr(SubrSignature::new(
2310            set! { Decorator(Expr::static_local("Override")) },
2311            call_ident,
2312            TypeBoundSpecs::empty(),
2313            params,
2314            Some(class_spec),
2315        ));
2316        let unreachable_acc = Identifier::new(
2317            VisModifierSpec::Public(ErgLocation::Unknown),
2318            VarName::from_static("exit"),
2319        );
2320        let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty());
2321        let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0));
2322        let def = Def::new(sig, body);
2323        Some(def)
2324    }
2325
2326    fn extract_instance_attrs(&self, sig: &SubrSignature, block: &Block, fields: &mut Vec<Def>) {
2327        for chunk in block.iter() {
2328            if let Expr::ReDef(redef) = chunk {
2329                let Accessor::Attr(attr) = &redef.attr else {
2330                    continue;
2331                };
2332                // if `self.foo == ...`
2333                if attr.obj.get_name().map(|s| &s[..]) == Some("self")
2334                    && fields
2335                        .iter()
2336                        .all(|field| field.sig.ident().unwrap() != &attr.ident)
2337                {
2338                    // get attribute types
2339                    let typ = if let Some(t_spec_op) = sig
2340                        .params
2341                        .non_defaults
2342                        .iter()
2343                        .find(|&param| param.inspect() == Some(attr.ident.inspect()))
2344                        .and_then(|param| param.t_spec.as_ref())
2345                        .or_else(|| {
2346                            sig.params
2347                                .defaults
2348                                .iter()
2349                                .find(|&param| param.inspect() == Some(attr.ident.inspect()))
2350                                .and_then(|param| param.sig.t_spec.as_ref())
2351                        }) {
2352                        *t_spec_op.t_spec_as_expr.clone()
2353                    } else if let Some(typ) =
2354                        redef.t_spec.clone().map(|t_spec| t_spec.t_spec_as_expr)
2355                    {
2356                        *typ
2357                    } else {
2358                        Expr::from(Accessor::Ident(Identifier::private_with_line(
2359                            "Any".into(),
2360                            attr.obj.ln_begin().unwrap_or(0),
2361                        )))
2362                    };
2363                    let sig = Signature::Var(VarSignature::new(
2364                        VarPattern::Ident(attr.ident.clone()),
2365                        None,
2366                    ));
2367                    let body = DefBody::new(EQUAL, Block::new(vec![typ]), DefId(0));
2368                    let field_type_def = Def::new(sig, body);
2369                    fields.push(field_type_def);
2370                }
2371            }
2372        }
2373    }
2374
2375    fn gen_default_init(&self, line: usize) -> Def {
2376        let call_ident = Identifier::new(
2377            VisModifierSpec::Public(ErgLocation::Unknown),
2378            VarName::from_static("__call__"),
2379        );
2380        let params = Params::empty();
2381        let class_ident =
2382            Identifier::public_with_line(DOT, self.cur_name().to_string().into(), line as u32);
2383        let class_ident_expr = Expr::Accessor(Accessor::Ident(class_ident.clone()));
2384        let class_spec = TypeSpecWithOp::new(COLON, TypeSpec::mono(class_ident), class_ident_expr);
2385        let sig = Signature::Subr(SubrSignature::new(
2386            set! { Decorator(Expr::static_local("Override")) },
2387            call_ident,
2388            TypeBoundSpecs::empty(),
2389            params,
2390            Some(class_spec),
2391        ));
2392        let unreachable_acc = Identifier::new(
2393            VisModifierSpec::Public(ErgLocation::Unknown),
2394            VarName::from_static("exit"),
2395        );
2396        let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty());
2397        let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0));
2398        Def::new(sig, body)
2399    }
2400
2401    fn extract_method(
2402        &mut self,
2403        body: Vec<py_ast::Stmt>,
2404        inherit: bool,
2405        class_name: Expr,
2406    ) -> (Option<Expr>, ClassAttrs) {
2407        let mut base_type = None;
2408        let mut attrs = vec![];
2409        let mut call_params_len = None;
2410        for stmt in body {
2411            match self.convert_statement(stmt, true) {
2412                Expr::Def(mut def) => {
2413                    if inherit {
2414                        if let Signature::Subr(subr) = &mut def.sig {
2415                            subr.decorators
2416                                .insert(Decorator(Expr::static_local("Override")));
2417                        }
2418                    }
2419                    if def.sig.decorators().is_some_and(|decos| {
2420                        decos.iter().any(|deco| {
2421                            deco.expr()
2422                                .get_name()
2423                                .is_some_and(|name| name == "property")
2424                        })
2425                    }) {
2426                        // class Foo:
2427                        //     @property
2428                        //     def foo(self): ...
2429                        // ↓
2430                        // class Foo:
2431                        //     def foo_(self): ...
2432                        //     foo = Foo(*[]).foo_()
2433                        let mut args = Args::empty();
2434                        if call_params_len.as_ref().is_some_and(|&len| len >= 1) {
2435                            args.set_var_args(PosArg::new(Expr::List(List::Normal(
2436                                NormalList::new(
2437                                    Token::dummy(TokenKind::LSqBr, "["),
2438                                    Token::dummy(TokenKind::RSqBr, "]"),
2439                                    Args::empty(),
2440                                ),
2441                            ))));
2442                        }
2443                        let instance = class_name.clone().call(args);
2444                        let name = def.sig.ident().unwrap().clone();
2445                        def.sig
2446                            .ident_mut()
2447                            .unwrap()
2448                            .name
2449                            .rename(format!("{} ", name.inspect()).into());
2450                        let escaped = def.sig.ident().unwrap().clone();
2451                        let call = Expr::Call(instance).method_call_expr(escaped, Args::empty());
2452                        let t_spec = def.sig.t_spec_op_mut().cloned();
2453                        let sig =
2454                            Signature::Var(VarSignature::new(VarPattern::Ident(name), t_spec));
2455                        let var_def =
2456                            Def::new(sig, DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)));
2457                        attrs.push(ClassAttr::Def(def));
2458                        attrs.push(ClassAttr::Def(var_def));
2459                    } else if def
2460                        .sig
2461                        .ident()
2462                        .is_some_and(|id| &id.inspect()[..] == "__init__")
2463                    {
2464                        // We will generate `__init__` and determine the shape of the class at the end
2465                        // Here we just extract the signature
2466                        if let Some(call_def) =
2467                            self.extract_init(&mut base_type, def.clone(), &attrs, true)
2468                        {
2469                            if let Some(params) = call_def.sig.params() {
2470                                call_params_len = Some(params.len());
2471                            }
2472                            attrs.push(ClassAttr::Def(def));
2473                        }
2474                    } else {
2475                        attrs.push(ClassAttr::Def(def));
2476                    }
2477                }
2478                Expr::TypeAscription(type_asc) => {
2479                    let sig = match type_asc.expr.as_ref() {
2480                        Expr::Accessor(Accessor::Ident(ident)) => Signature::Var(
2481                            VarSignature::new(VarPattern::Ident(ident.clone()), None),
2482                        ),
2483                        other => {
2484                            log!(err "{other}");
2485                            continue;
2486                        }
2487                    };
2488                    let expr = *type_asc.t_spec.t_spec_as_expr;
2489                    let body = DefBody::new(EQUAL, Block::new(vec![expr]), DefId(0));
2490                    let def = Def::new(sig, body);
2491                    match &mut base_type {
2492                        Some(Expr::Record(Record::Normal(NormalRecord { attrs, .. }))) => {
2493                            attrs.push(def);
2494                        }
2495                        None => {
2496                            let l_brace = Token::new(
2497                                TokenKind::LBrace,
2498                                "{",
2499                                def.ln_begin().unwrap_or(0),
2500                                def.col_begin().unwrap_or(0),
2501                            );
2502                            let r_brace = Token::new(
2503                                TokenKind::RBrace,
2504                                "}",
2505                                def.ln_end().unwrap_or(0),
2506                                def.col_end().unwrap_or(0),
2507                            );
2508                            let rec = Expr::Record(Record::Normal(NormalRecord::new(
2509                                l_brace,
2510                                r_brace,
2511                                RecordAttrs::new(vec![def]),
2512                            )));
2513                            base_type = Some(rec);
2514                        }
2515                        _ => {}
2516                    }
2517                    // attrs.push(ClassAttr::Decl(type_asc))
2518                }
2519                _other => {} // TODO:
2520            }
2521        }
2522        let mut init = None;
2523        for (i, attr) in attrs.iter().enumerate() {
2524            if let ClassAttr::Def(def) = attr {
2525                if def
2526                    .sig
2527                    .ident()
2528                    .is_some_and(|id| &id.inspect()[..] == "__init__")
2529                {
2530                    if let Some(def) = self.extract_init(&mut base_type, def.clone(), &attrs, false)
2531                    {
2532                        init = Some((i, def));
2533                    }
2534                }
2535            }
2536        }
2537        if let Some((i, def)) = init {
2538            attrs.remove(i);
2539            attrs.insert(0, ClassAttr::Def(def));
2540        } else if !inherit {
2541            attrs.insert(0, ClassAttr::Def(self.gen_default_init(0)));
2542        }
2543        (base_type, ClassAttrs::new(attrs))
2544    }
2545
2546    fn extract_method_list(
2547        &mut self,
2548        ident: Identifier,
2549        body: Vec<py_ast::Stmt>,
2550        base: Option<py_ast::Expr>,
2551    ) -> (Option<Expr>, Vec<Methods>) {
2552        let inherit = base.is_some();
2553        let class = if let Some(base) = base {
2554            let base_spec = self.convert_type_spec(base.clone());
2555            let expr = self.convert_expr(base);
2556            let loc = expr.loc();
2557            let base = TypeSpecWithOp::new(COLON, base_spec, expr);
2558            let args = TypeAppArgs::new(loc, TypeAppArgsKind::SubtypeOf(Box::new(base)), loc);
2559            TypeSpec::type_app(TypeSpec::mono(ident.clone()), args)
2560        } else {
2561            TypeSpec::mono(ident.clone())
2562        };
2563        let class_as_expr = Expr::Accessor(Accessor::Ident(ident));
2564        let (base_type, attrs) = self.extract_method(body, inherit, class_as_expr.clone());
2565        self.block_id_counter += 1;
2566        let methods = Methods::new(
2567            DefId(self.block_id_counter),
2568            class,
2569            class_as_expr,
2570            VisModifierSpec::Public(ErgLocation::Unknown),
2571            attrs,
2572        );
2573        (base_type, vec![methods])
2574    }
2575
2576    fn get_type_bounds(&mut self, type_params: Vec<TypeParam>) -> TypeBoundSpecs {
2577        let mut bounds = TypeBoundSpecs::empty();
2578        if type_params.is_empty() {
2579            for ty in self.cur_appeared_type_names() {
2580                let name = VarName::from_str(ty.clone().into());
2581                let op = Token::dummy(TokenKind::SubtypeOf, "<:");
2582                if let Some(tv_info) = self.get_type_var(ty) {
2583                    let bound = if let Some(bound) = &tv_info.bound {
2584                        let t_spec = Parser::expr_to_type_spec(bound.clone())
2585                            .unwrap_or(TypeSpec::Infer(name.token().clone()));
2586                        let spec = TypeSpecWithOp::new(op, t_spec, bound.clone());
2587                        TypeBoundSpec::non_default(name, spec)
2588                    } else if !tv_info.constraints.is_empty() {
2589                        let op = Token::dummy(TokenKind::Colon, ":");
2590                        let mut elems = vec![];
2591                        for constraint in tv_info.constraints.iter() {
2592                            if let Ok(expr) = Parser::validate_const_expr(constraint.clone()) {
2593                                elems.push(ConstPosArg::new(expr));
2594                            }
2595                        }
2596                        let t_spec = TypeSpec::Enum(ConstArgs::pos_only(elems, None));
2597                        let elems = Args::pos_only(
2598                            tv_info
2599                                .constraints
2600                                .iter()
2601                                .cloned()
2602                                .map(PosArg::new)
2603                                .collect(),
2604                            None,
2605                        );
2606                        let expr = Expr::Set(Set::Normal(NormalSet::new(
2607                            Token::DUMMY,
2608                            Token::DUMMY,
2609                            elems,
2610                        )));
2611                        let spec = TypeSpecWithOp::new(op, t_spec, expr);
2612                        TypeBoundSpec::non_default(name, spec)
2613                    } else {
2614                        TypeBoundSpec::Omitted(name)
2615                    };
2616                    bounds.push(bound);
2617                }
2618            }
2619        }
2620        for tp in type_params {
2621            // TODO:
2622            let Some(tv) = tp.as_type_var() else {
2623                continue;
2624            };
2625            let name = VarName::from_str(tv.name.to_string().into());
2626            let spec = if let Some(bound) = &tv.bound {
2627                let op = Token::dummy(TokenKind::SubtypeOf, "<:");
2628                let spec = self.convert_type_spec(*bound.clone());
2629                let expr = self.convert_expr(*bound.clone());
2630                let spec = TypeSpecWithOp::new(op, spec, expr);
2631                TypeBoundSpec::non_default(name, spec)
2632            } else {
2633                TypeBoundSpec::Omitted(name)
2634            };
2635            bounds.push(spec);
2636        }
2637        bounds
2638    }
2639
2640    fn convert_funcdef(&mut self, func_def: py_ast::StmtFunctionDef, is_async: bool) -> Expr {
2641        let name = func_def.name.to_string();
2642        let params = *func_def.args;
2643        let returns = func_def.returns.map(|x| *x);
2644        // if reassigning of a function referenced by other functions is occurred, it is an error
2645        if self.get_name(&name).is_some_and(|info| {
2646            info.defined_times > 0
2647                && info.defined_in == DefinedPlace::Known(self.cur_namespace())
2648                && !info.referenced.difference(&set! {name.clone()}).is_empty()
2649        }) {
2650            let err = reassign_func_error(
2651                self.cfg.input.clone(),
2652                pyloc_to_ergloc(func_def.range),
2653                self.cur_namespace(),
2654                &name,
2655            );
2656            self.errs.push(err);
2657            Expr::Dummy(Dummy::new(None, vec![]))
2658        } else {
2659            let loc = func_def.range.start;
2660            let decos = func_def
2661                .decorator_list
2662                .into_iter()
2663                .map(|ex| Decorator(self.convert_expr(ex)))
2664                .collect::<HashSet<_>>();
2665            self.register_name_info(&name, NameKind::Function);
2666            let func_name_loc = PyLocation {
2667                row: loc.row,
2668                column: loc.column.saturating_add(4),
2669            };
2670            let ident = self.convert_ident(name, func_name_loc);
2671            let kind = if is_async {
2672                BlockKind::AsyncFunction
2673            } else {
2674                BlockKind::Function
2675            };
2676            self.grow(ident.inspect().to_string(), kind);
2677            let params = self.convert_params(params);
2678            let return_t = returns
2679                .or_else(|| {
2680                    let PyTypeSpec::Func(func) = self.get_cur_scope_t_spec()? else {
2681                        return None;
2682                    };
2683                    func.returns.clone()
2684                })
2685                .map(|ret| {
2686                    let t_spec = self.convert_type_spec(ret.clone());
2687                    let colon = Token::new(
2688                        TokenKind::Colon,
2689                        ":",
2690                        t_spec.ln_begin().unwrap_or(0),
2691                        t_spec.col_begin().unwrap_or(0),
2692                    );
2693                    TypeSpecWithOp::new(colon, t_spec, self.convert_expr(ret))
2694                });
2695            let type_params = if !func_def.type_params.is_empty() {
2696                func_def.type_params
2697            } else {
2698                self.get_cur_scope_t_spec()
2699                    .and_then(|ty| {
2700                        if let PyTypeSpec::Func(func) = ty {
2701                            (!func.type_params.is_empty()).then(|| func.type_params.clone())
2702                        } else {
2703                            None
2704                        }
2705                    })
2706                    .unwrap_or(func_def.type_params)
2707            };
2708            let bounds = self.get_type_bounds(type_params);
2709            let mut sig =
2710                Signature::Subr(SubrSignature::new(decos, ident, bounds, params, return_t));
2711            let block = self.convert_block(func_def.body, BlockKind::Function);
2712            if self.cur_context().return_kind.is_none() {
2713                let Signature::Subr(subr) = &mut sig else {
2714                    unreachable!()
2715                };
2716                if subr.return_t_spec.is_none() {
2717                    let none = TypeSpecWithOp::new(
2718                        Token::dummy(TokenKind::Colon, ":"),
2719                        TypeSpec::mono(Identifier::private("NoneType".into())),
2720                        Expr::static_local("NoneType"),
2721                    );
2722                    subr.return_t_spec = Some(Box::new(none));
2723                }
2724            }
2725            let body = DefBody::new(EQUAL, block, DefId(0));
2726            let def = Def::new(sig, body);
2727            self.pop();
2728            Expr::Def(def)
2729        }
2730    }
2731
2732    /// ```python
2733    /// class Foo: pass
2734    /// ```
2735    /// ↓
2736    /// ```erg
2737    /// Foo = Inheritable Class()
2738    /// ```
2739    /// ```python
2740    /// class Foo(Bar): pass
2741    /// ```
2742    /// ↓
2743    /// ```erg
2744    /// Foo = Inherit Bar
2745    /// ```
2746    fn convert_classdef(&mut self, class_def: py_ast::StmtClassDef) -> Expr {
2747        let loc = class_def.location();
2748        let name = class_def.name.to_string();
2749        let _decos = class_def
2750            .decorator_list
2751            .into_iter()
2752            .map(|deco| self.convert_expr(deco))
2753            .collect::<Vec<_>>();
2754        let inherit = class_def.bases.first().cloned();
2755        let is_inherit = inherit.is_some();
2756        let mut bases = class_def
2757            .bases
2758            .into_iter()
2759            .map(|base| self.convert_expr(base))
2760            .collect::<Vec<_>>();
2761        self.register_name_info(&name, NameKind::Class);
2762        let class_name_loc = PyLocation {
2763            row: loc.row,
2764            column: loc.column.saturating_add(6),
2765        };
2766        let ident = self.convert_ident(name, class_name_loc);
2767        let sig = Signature::Var(VarSignature::new(VarPattern::Ident(ident.clone()), None));
2768        self.grow(ident.inspect().to_string(), BlockKind::Class);
2769        let (base_type, methods) = self.extract_method_list(ident, class_def.body, inherit);
2770        let classdef = if is_inherit {
2771            // TODO: multiple inheritance
2772            let pos_args = vec![PosArg::new(bases.remove(0))];
2773            let mut args = Args::pos_only(pos_args, None);
2774            if let Some(rec @ Expr::Record(_)) = base_type {
2775                args.push_kw(KwArg::new(Token::symbol("Additional"), None, rec));
2776            }
2777            let inherit_acc = Expr::Accessor(Accessor::Ident(
2778                self.convert_ident("Inherit".to_string(), loc),
2779            ));
2780            let inherit_call = inherit_acc.call_expr(args);
2781            let body = DefBody::new(EQUAL, Block::new(vec![inherit_call]), DefId(0));
2782            let def = Def::new(sig, body);
2783            ClassDef::new(def, methods)
2784        } else {
2785            let pos_args = if let Some(base) = base_type {
2786                vec![PosArg::new(base)]
2787            } else {
2788                vec![]
2789            };
2790            let args = Args::pos_only(pos_args, None);
2791            let class_acc = Expr::Accessor(Accessor::Ident(
2792                self.convert_ident("Class".to_string(), loc),
2793            ));
2794            let class_call = class_acc.call_expr(args);
2795            let inheritable_acc = Expr::Accessor(Accessor::Ident(
2796                self.convert_ident("Inheritable".to_string(), loc),
2797            ));
2798            let inheritable_call = inheritable_acc.call1(class_call);
2799            let body = DefBody::new(EQUAL, Block::new(vec![inheritable_call]), DefId(0));
2800            let def = Def::new(sig, body);
2801            ClassDef::new(def, methods)
2802        };
2803        self.pop();
2804        Expr::ClassDef(classdef)
2805    }
2806
2807    fn convert_for(&mut self, for_: py_ast::StmtFor) -> Expr {
2808        let loc = for_.location();
2809        let iter = self.convert_expr(*for_.iter);
2810        let if_block_id = self.block_id_counter + 1;
2811        let block = self.convert_for_body(Some(*for_.target), for_.body);
2812        let for_ident = self.convert_ident("for".to_string(), loc);
2813        let for_acc = Expr::Accessor(Accessor::Ident(for_ident));
2814        if for_.orelse.is_empty() {
2815            for_acc.call2(iter, Expr::Lambda(block))
2816        } else {
2817            let else_block = self.convert_block(for_.orelse, BlockKind::Else { if_block_id });
2818            let params = Params::empty();
2819            let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
2820            let op = Token::from_str(TokenKind::FuncArrow, "->");
2821            let else_block = Lambda::new(sig, op, else_block, DefId(0));
2822            let args = Args::pos_only(
2823                vec![
2824                    PosArg::new(iter),
2825                    PosArg::new(Expr::Lambda(block)),
2826                    PosArg::new(Expr::Lambda(else_block)),
2827                ],
2828                None,
2829            );
2830            for_acc.call_expr(args)
2831        }
2832    }
2833
2834    fn get_t_spec(&self, name: &str) -> Option<&PyTypeSpec> {
2835        if self.contexts.len() == 1 {
2836            self.pyi_types.get_type(name)
2837        } else {
2838            let class = self.cur_name();
2839            self.pyi_types.get_class_member_type(class, name)
2840        }
2841    }
2842
2843    fn get_assign_t_spec(
2844        &mut self,
2845        name: &py_ast::ExprName,
2846        expr: &Expr,
2847    ) -> Option<TypeSpecWithOp> {
2848        expr.ln_end()
2849            .and_then(|i| {
2850                i.checked_sub(1)
2851                    .and_then(|line| self.comments.get_type(line))
2852            })
2853            .cloned()
2854            .or_else(|| {
2855                let type_spec = self.get_t_spec(&name.id)?;
2856                let PyTypeSpec::Var(expr) = type_spec else {
2857                    return None;
2858                };
2859                Some(expr.clone())
2860            })
2861            .map(|mut expr| {
2862                // The range of `expr` is not correct, so we need to change it
2863                if let py_ast::Expr::Subscript(sub) = &mut expr {
2864                    sub.range = name.range;
2865                    *sub.slice.range_mut() = name.range;
2866                    *sub.value.range_mut() = name.range;
2867                } else {
2868                    *expr.range_mut() = name.range;
2869                }
2870                let t_as_expr = self.convert_expr(expr.clone());
2871                TypeSpecWithOp::new(AS, self.convert_type_spec(expr), t_as_expr)
2872            })
2873    }
2874
2875    fn convert_statement(&mut self, stmt: Stmt, dont_call_return: bool) -> Expr {
2876        match stmt {
2877            py_ast::Stmt::Expr(stmt) => self.convert_expr(*stmt.value),
2878            // type-annotated assignment
2879            py_ast::Stmt::AnnAssign(ann_assign) => {
2880                let anot = self.convert_expr(*ann_assign.annotation.clone());
2881                let t_spec = self.convert_type_spec(*ann_assign.annotation);
2882                let as_op = Token::new(
2883                    TokenKind::As,
2884                    "as",
2885                    t_spec.ln_begin().unwrap_or(0),
2886                    t_spec.col_begin().unwrap_or(0),
2887                );
2888                let t_spec = TypeSpecWithOp::new(as_op, t_spec, anot);
2889                match *ann_assign.target {
2890                    py_ast::Expr::Name(name) => {
2891                        if let Some(value) = ann_assign.value {
2892                            let expr = self.convert_expr(*value);
2893                            // must register after convert_expr because value may be contain name (e.g. i = i + 1)
2894                            let rename =
2895                                self.register_name_info(name.id.as_str(), NameKind::Variable);
2896                            let ident = self.convert_ident(name.id.to_string(), name.location());
2897                            match rename {
2898                                RenameKind::Let => {
2899                                    let block = Block::new(vec![expr]);
2900                                    let body = DefBody::new(EQUAL, block, DefId(0));
2901                                    let sig = Signature::Var(VarSignature::new(
2902                                        VarPattern::Ident(ident),
2903                                        Some(t_spec),
2904                                    ));
2905                                    let def = Def::new(sig, body);
2906                                    Expr::Def(def)
2907                                }
2908                                RenameKind::Phi => {
2909                                    let block = Block::new(vec![expr]);
2910                                    let body = DefBody::new(EQUAL, block, DefId(0));
2911                                    let sig = Signature::Var(VarSignature::new(
2912                                        VarPattern::Phi(ident),
2913                                        Some(t_spec),
2914                                    ));
2915                                    let def = Def::new(sig, body);
2916                                    Expr::Def(def)
2917                                }
2918                                RenameKind::Redef => {
2919                                    let redef =
2920                                        ReDef::new(Accessor::Ident(ident), Some(t_spec), expr);
2921                                    Expr::ReDef(redef)
2922                                }
2923                            }
2924                        } else {
2925                            // no registration because it's just a type ascription
2926                            let ident = self.convert_ident(name.id.to_string(), name.location());
2927                            let tasc =
2928                                TypeAscription::new(Expr::Accessor(Accessor::Ident(ident)), t_spec);
2929                            Expr::TypeAscription(tasc)
2930                        }
2931                    }
2932                    py_ast::Expr::Attribute(attr) => {
2933                        let value = self.convert_expr(*attr.value);
2934                        let ident =
2935                            self.convert_attr_ident(attr.attr.to_string(), attr_name_loc(&value));
2936                        let attr = value.attr(ident);
2937                        if let Some(value) = ann_assign.value {
2938                            let expr = self.convert_expr(*value);
2939                            let redef = ReDef::new(attr, Some(t_spec), expr);
2940                            Expr::ReDef(redef)
2941                        } else {
2942                            let tasc = TypeAscription::new(Expr::Accessor(attr), t_spec);
2943                            Expr::TypeAscription(tasc)
2944                        }
2945                    }
2946                    _other => Expr::Dummy(Dummy::new(None, vec![])),
2947                }
2948            }
2949            py_ast::Stmt::Assign(mut assign) => {
2950                if assign.targets.len() == 1 {
2951                    let lhs = assign.targets.remove(0);
2952                    match lhs {
2953                        py_ast::Expr::Name(name) => {
2954                            let expr = self.convert_expr(*assign.value);
2955                            if let Expr::Call(call) = &expr {
2956                                if let Some("TypeVar") = call.obj.get_name().map(|s| &s[..]) {
2957                                    let arg = if let Some(Expr::Literal(lit)) =
2958                                        call.args.get_left_or_key("arg")
2959                                    {
2960                                        lit.token.content.trim_matches('\"').to_string()
2961                                    } else {
2962                                        name.id.to_string()
2963                                    };
2964                                    let mut constraints = vec![];
2965                                    let mut nth = 1;
2966                                    while let Some(constr) = call.args.get_nth(nth) {
2967                                        constraints.push(constr.clone());
2968                                        nth += 1;
2969                                    }
2970                                    if constraints.len() == 1 {
2971                                        let err = CompileError::syntax_error(
2972                                            self.cfg.input.clone(),
2973                                            line!() as usize,
2974                                            call.args.get_nth(1).unwrap().loc(),
2975                                            self.cur_namespace(),
2976                                            "TypeVar must have at least two constrained types"
2977                                                .into(),
2978                                            None,
2979                                        );
2980                                        self.errs.push(err);
2981                                    }
2982                                    let bound = call.args.get_with_key("bound").cloned();
2983                                    let info = TypeVarInfo::new(arg, constraints, bound);
2984                                    self.define_type_var(name.id.to_string(), info);
2985                                }
2986                            }
2987                            let rename = self.register_name_info(&name.id, NameKind::Variable);
2988                            let ident = self.convert_ident(name.id.to_string(), name.location());
2989                            let t_spec = self.get_assign_t_spec(&name, &expr);
2990                            match rename {
2991                                RenameKind::Let => {
2992                                    let block = Block::new(vec![expr]);
2993                                    let body = DefBody::new(EQUAL, block, DefId(0));
2994                                    let sig = Signature::Var(VarSignature::new(
2995                                        VarPattern::Ident(ident),
2996                                        t_spec,
2997                                    ));
2998                                    let def = Def::new(sig, body);
2999                                    Expr::Def(def)
3000                                }
3001                                RenameKind::Phi => {
3002                                    let block = Block::new(vec![expr]);
3003                                    let body = DefBody::new(EQUAL, block, DefId(0));
3004                                    let sig = Signature::Var(VarSignature::new(
3005                                        VarPattern::Phi(ident),
3006                                        t_spec,
3007                                    ));
3008                                    let def = Def::new(sig, body);
3009                                    Expr::Def(def)
3010                                }
3011                                RenameKind::Redef => {
3012                                    let redef = ReDef::new(Accessor::Ident(ident), t_spec, expr);
3013                                    Expr::ReDef(redef)
3014                                }
3015                            }
3016                        }
3017                        py_ast::Expr::Attribute(attr) => {
3018                            let value = self.convert_expr(*attr.value);
3019                            let ident = self
3020                                .convert_attr_ident(attr.attr.to_string(), attr_name_loc(&value));
3021                            let attr = value.attr(ident);
3022                            let expr = self.convert_expr(*assign.value);
3023                            let adef = ReDef::new(attr, None, expr);
3024                            Expr::ReDef(adef)
3025                        }
3026                        py_ast::Expr::Tuple(tuple) => {
3027                            let tmp = FRESH_GEN.fresh_varname();
3028                            let tmp_name =
3029                                VarName::from_str_and_line(tmp, tuple.location().row.get());
3030                            let tmp_ident = Identifier::new(
3031                                VisModifierSpec::Public(ErgLocation::Unknown),
3032                                tmp_name,
3033                            );
3034                            let tmp_expr = Expr::Accessor(Accessor::Ident(tmp_ident.clone()));
3035                            let sig = Signature::Var(VarSignature::new(
3036                                VarPattern::Ident(tmp_ident),
3037                                None,
3038                            ));
3039                            let body = DefBody::new(
3040                                EQUAL,
3041                                Block::new(vec![self.convert_expr(*assign.value)]),
3042                                DefId(0),
3043                            );
3044                            let tmp_def = Expr::Def(Def::new(sig, body));
3045                            let mut defs = vec![tmp_def];
3046                            for (i, elem) in tuple.elts.into_iter().enumerate() {
3047                                let loc = elem.location();
3048                                let index = Literal::new(Token::new(
3049                                    TokenKind::NatLit,
3050                                    i.to_string(),
3051                                    loc.row.get(),
3052                                    loc.column.to_zero_indexed(),
3053                                ));
3054                                let (param, mut blocks) =
3055                                    self.convert_opt_expr_to_param(Some(elem));
3056                                let sig = Signature::Var(VarSignature::new(
3057                                    Self::param_pattern_to_var(param.pat),
3058                                    param.t_spec,
3059                                ));
3060                                let method = tmp_expr
3061                                    .clone()
3062                                    .attr_expr(self.convert_ident("__getitem__".to_string(), loc));
3063                                let tuple_acc = method.call1(Expr::Literal(index));
3064                                let body =
3065                                    DefBody::new(EQUAL, Block::new(vec![tuple_acc]), DefId(0));
3066                                let def = Expr::Def(Def::new(sig, body));
3067                                defs.push(def);
3068                                defs.append(&mut blocks);
3069                            }
3070                            Expr::Dummy(Dummy::new(None, defs))
3071                        }
3072                        // a[b] = x
3073                        // => a.__setitem__(b, x)
3074                        py_ast::Expr::Subscript(subs) => {
3075                            let a = self.convert_expr(*subs.value);
3076                            let slice_loc = subs.slice.location();
3077                            let b = self.convert_expr(*subs.slice);
3078                            let x = self.convert_expr(*assign.value);
3079                            let method = a.attr_expr(
3080                                self.convert_ident("__setitem__".to_string(), slice_loc),
3081                            );
3082                            method.call2(b, x)
3083                        }
3084                        other => {
3085                            log!(err "{other:?} as LHS");
3086                            Expr::Dummy(Dummy::new(None, vec![]))
3087                        }
3088                    }
3089                } else {
3090                    let value = self.convert_expr(*assign.value);
3091                    let mut defs = vec![];
3092                    for target in assign.targets {
3093                        match target {
3094                            py_ast::Expr::Name(name) => {
3095                                let body =
3096                                    DefBody::new(EQUAL, Block::new(vec![value.clone()]), DefId(0));
3097                                let rename = self.register_name_info(&name.id, NameKind::Variable);
3098                                let ident =
3099                                    self.convert_ident(name.id.to_string(), name.location());
3100                                match rename {
3101                                    RenameKind::Let => {
3102                                        let sig = Signature::Var(VarSignature::new(
3103                                            VarPattern::Ident(ident),
3104                                            None,
3105                                        ));
3106                                        let def = Def::new(sig, body);
3107                                        defs.push(Expr::Def(def));
3108                                    }
3109                                    RenameKind::Phi => {
3110                                        let sig = Signature::Var(VarSignature::new(
3111                                            VarPattern::Phi(ident),
3112                                            None,
3113                                        ));
3114                                        let def = Def::new(sig, body);
3115                                        defs.push(Expr::Def(def));
3116                                    }
3117                                    RenameKind::Redef => {
3118                                        let redef =
3119                                            ReDef::new(Accessor::Ident(ident), None, value.clone());
3120                                        defs.push(Expr::ReDef(redef));
3121                                    }
3122                                }
3123                            }
3124                            _other => {
3125                                defs.push(Expr::Dummy(Dummy::new(None, vec![])));
3126                            }
3127                        }
3128                    }
3129                    Expr::Dummy(Dummy::new(None, defs))
3130                }
3131            }
3132            py_ast::Stmt::AugAssign(aug_assign) => {
3133                let op = op_to_token(aug_assign.op);
3134                match *aug_assign.target {
3135                    py_ast::Expr::Name(name) => {
3136                        let val = self.convert_expr(*aug_assign.value);
3137                        let prev_ident = self.convert_ident(name.id.to_string(), name.location());
3138                        if self
3139                            .get_name(name.id.as_str())
3140                            .is_some_and(|info| info.defined_block_id == self.cur_block_id())
3141                        {
3142                            self.register_name_info(&name.id, NameKind::Variable);
3143                            let ident = self.convert_ident(name.id.to_string(), name.location());
3144                            let bin =
3145                                BinOp::new(op, Expr::Accessor(Accessor::Ident(prev_ident)), val);
3146                            let sig =
3147                                Signature::Var(VarSignature::new(VarPattern::Ident(ident), None));
3148                            let block = Block::new(vec![Expr::BinOp(bin)]);
3149                            let body = DefBody::new(EQUAL, block, DefId(0));
3150                            let def = Def::new(sig, body);
3151                            Expr::Def(def)
3152                        } else {
3153                            let ident = self.convert_ident(name.id.to_string(), name.location());
3154                            let bin =
3155                                BinOp::new(op, Expr::Accessor(Accessor::Ident(prev_ident)), val);
3156                            let redef = ReDef::new(Accessor::Ident(ident), None, Expr::BinOp(bin));
3157                            Expr::ReDef(redef)
3158                        }
3159                    }
3160                    py_ast::Expr::Attribute(attr) => {
3161                        let assign_value = self.convert_expr(*aug_assign.value);
3162                        let attr_value = self.convert_expr(*attr.value);
3163                        let ident = self
3164                            .convert_attr_ident(attr.attr.to_string(), attr_name_loc(&attr_value));
3165                        let attr = attr_value.attr(ident);
3166                        let bin = BinOp::new(op, Expr::Accessor(attr.clone()), assign_value);
3167                        let redef = ReDef::new(attr, None, Expr::BinOp(bin));
3168                        Expr::ReDef(redef)
3169                    }
3170                    other => {
3171                        log!(err "{other:?} as LHS");
3172                        Expr::Dummy(Dummy::new(None, vec![]))
3173                    }
3174                }
3175            }
3176            py_ast::Stmt::FunctionDef(func_def) => self.convert_funcdef(func_def, false),
3177            py_ast::Stmt::AsyncFunctionDef(func_def) => {
3178                let py_ast::StmtAsyncFunctionDef {
3179                    name,
3180                    args,
3181                    body,
3182                    decorator_list,
3183                    returns,
3184                    type_params,
3185                    range,
3186                    type_comment,
3187                } = func_def;
3188                let func_def = py_ast::StmtFunctionDef {
3189                    name,
3190                    args,
3191                    body,
3192                    decorator_list,
3193                    returns,
3194                    type_params,
3195                    range,
3196                    type_comment,
3197                };
3198                self.convert_funcdef(func_def, true)
3199            }
3200            py_ast::Stmt::ClassDef(class_def) => self.convert_classdef(class_def),
3201            py_ast::Stmt::For(for_) => self.convert_for(for_),
3202            py_ast::Stmt::AsyncFor(for_) => {
3203                let py_ast::StmtAsyncFor {
3204                    target,
3205                    iter,
3206                    body,
3207                    orelse,
3208                    range,
3209                    type_comment,
3210                } = for_;
3211                let for_ = py_ast::StmtFor {
3212                    target,
3213                    iter,
3214                    body,
3215                    orelse,
3216                    range,
3217                    type_comment,
3218                };
3219                self.convert_for(for_)
3220            }
3221            py_ast::Stmt::While(while_) => {
3222                let loc = while_.location();
3223                let test = self.convert_expr(*while_.test);
3224                let params = Params::empty();
3225                let empty_sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
3226                let if_block_id = self.block_id_counter + 1;
3227                let block = self.convert_block(while_.body, BlockKind::While);
3228                let body = Lambda::new(empty_sig, Token::DUMMY, block, DefId(0));
3229                let while_ident = self.convert_ident("while".to_string(), loc);
3230                let while_acc = Expr::Accessor(Accessor::Ident(while_ident));
3231                if while_.orelse.is_empty() {
3232                    while_acc.call2(test, Expr::Lambda(body))
3233                } else {
3234                    let else_block =
3235                        self.convert_block(while_.orelse, BlockKind::Else { if_block_id });
3236                    let params = Params::empty();
3237                    let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
3238                    let op = Token::from_str(TokenKind::FuncArrow, "->");
3239                    let else_body = Lambda::new(sig, op, else_block, DefId(0));
3240                    let args = Args::pos_only(
3241                        vec![
3242                            PosArg::new(test),
3243                            PosArg::new(Expr::Lambda(body)),
3244                            PosArg::new(Expr::Lambda(else_body)),
3245                        ],
3246                        None,
3247                    );
3248                    while_acc.call_expr(args)
3249                }
3250            }
3251            py_ast::Stmt::If(if_) => {
3252                let loc = if_.location();
3253                let if_block_id = self.block_id_counter + 1;
3254                let block = self.convert_block(if_.body, BlockKind::If);
3255                let params = Params::empty();
3256                let sig = LambdaSignature::new(params.clone(), None, TypeBoundSpecs::empty());
3257                let body = Lambda::new(sig, Token::DUMMY, block, DefId(0));
3258                let test = self.convert_expr(*if_.test);
3259                let if_ident = self.convert_ident("if".to_string(), loc);
3260                let if_acc = Expr::Accessor(Accessor::Ident(if_ident));
3261                if !if_.orelse.is_empty() {
3262                    let else_block =
3263                        self.convert_block(if_.orelse, BlockKind::Else { if_block_id });
3264                    let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
3265                    let else_body = Lambda::new(sig, Token::DUMMY, else_block, DefId(0));
3266                    let args = Args::pos_only(
3267                        vec![
3268                            PosArg::new(test),
3269                            PosArg::new(Expr::Lambda(body)),
3270                            PosArg::new(Expr::Lambda(else_body)),
3271                        ],
3272                        None,
3273                    );
3274                    if_acc.call_expr(args)
3275                } else {
3276                    if_acc.call2(test, Expr::Lambda(body))
3277                }
3278            }
3279            py_ast::Stmt::Return(return_) => {
3280                self.cur_context_mut().return_kind = ReturnKind::Return;
3281                let loc = return_.location();
3282                let value = return_
3283                    .value
3284                    .map(|val| self.convert_expr(*val))
3285                    .unwrap_or_else(|| Expr::Tuple(Tuple::Normal(NormalTuple::new(Args::empty()))));
3286                if dont_call_return {
3287                    value
3288                } else {
3289                    let func_acc = Expr::Accessor(Accessor::Ident(
3290                        self.convert_ident(self.cur_name().to_string(), loc),
3291                    ));
3292                    let return_acc = self.convert_ident("return".to_string(), loc);
3293                    let return_acc = Expr::Accessor(Accessor::attr(func_acc, return_acc));
3294                    return_acc.call1(value)
3295                }
3296            }
3297            py_ast::Stmt::Assert(assert) => {
3298                let loc = assert.location();
3299                let test = self.convert_expr(*assert.test);
3300                let args = if let Some(msg) = assert.msg {
3301                    let msg = self.convert_expr(*msg);
3302                    Args::pos_only(vec![PosArg::new(test), PosArg::new(msg)], None)
3303                } else {
3304                    Args::pos_only(vec![PosArg::new(test)], None)
3305                };
3306                let assert_acc = Expr::Accessor(Accessor::Ident(
3307                    self.convert_ident("assert".to_string(), loc),
3308                ));
3309                assert_acc.call_expr(args)
3310            }
3311            py_ast::Stmt::Import(import) => {
3312                let import_loc = import.location();
3313                let mut imports = vec![];
3314                for name in import.names {
3315                    let import_acc = Expr::Accessor(Accessor::Ident(
3316                        self.convert_ident("__import__".to_string(), import_loc),
3317                    ));
3318                    let sym = if name.asname.is_some() {
3319                        name.name.replace('.', "/")
3320                    } else {
3321                        name.name.split('.').next().unwrap().to_string()
3322                    };
3323                    let mod_name = Expr::Literal(Literal::new(quoted_symbol(
3324                        &sym,
3325                        name.location().row.get(),
3326                        name.location().column.to_zero_indexed(),
3327                    )));
3328                    let call = import_acc.call1(mod_name);
3329                    let name_loc = name.location();
3330                    let def = if let Some(alias) = name.asname {
3331                        self.register_name_info(&alias, NameKind::Variable);
3332                        let var = VarSignature::new(
3333                            VarPattern::Ident(self.convert_ident(alias.to_string(), name_loc)),
3334                            None,
3335                        );
3336                        Def::new(
3337                            Signature::Var(var),
3338                            DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)),
3339                        )
3340                    } else {
3341                        let top_module = name.name.split('.').next().unwrap();
3342                        self.register_name_info(top_module, NameKind::Variable);
3343                        let var = VarSignature::new(
3344                            VarPattern::Ident(
3345                                self.convert_ident(top_module.to_string(), name.location()),
3346                            ),
3347                            None,
3348                        );
3349                        Def::new(
3350                            Signature::Var(var),
3351                            DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)),
3352                        )
3353                    };
3354                    imports.push(Expr::Def(def));
3355                }
3356                Expr::Dummy(Dummy::new(None, imports))
3357            }
3358            // from module import foo, bar
3359            py_ast::Stmt::ImportFrom(import_from) => {
3360                let mut loc = import_from.location();
3361                loc.column = loc.column.saturating_add(5);
3362                self.convert_from_import(import_from.module, import_from.names, loc)
3363            }
3364            py_ast::Stmt::Try(try_) => {
3365                let if_block_id = self.block_id_counter + 1;
3366                let mut chunks = self.convert_block(try_.body, BlockKind::Try);
3367                for py_ast::ExceptHandler::ExceptHandler(handler) in try_.handlers {
3368                    let mut block =
3369                        self.convert_block(handler.body, BlockKind::Else { if_block_id });
3370                    if let Some(name) = handler.name {
3371                        let ident = self.convert_ident(name.to_string(), handler.range.start);
3372                        let t_spec = if let Some(type_) = handler.type_ {
3373                            let t_spec = self.convert_type_spec(*type_.clone());
3374                            let as_expr = self.convert_expr(*type_.clone());
3375                            let as_op = Token::new(
3376                                TokenKind::As,
3377                                "as",
3378                                t_spec.ln_begin().unwrap_or(0),
3379                                t_spec.col_begin().unwrap_or(0),
3380                            );
3381                            let t_spec = TypeSpecWithOp::new(as_op, t_spec, as_expr);
3382                            Some(t_spec)
3383                        } else {
3384                            None
3385                        };
3386                        let var = VarSignature::new(VarPattern::Ident(ident), t_spec);
3387                        let unreachable_acc = Identifier::new(
3388                            VisModifierSpec::Public(ErgLocation::Unknown),
3389                            VarName::from_static("exit"),
3390                        );
3391                        let body = Expr::Accessor(Accessor::Ident(unreachable_acc))
3392                            .call_expr(Args::empty());
3393                        let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0));
3394                        let def = Def::new(Signature::Var(var), body);
3395                        block.insert(0, Expr::Def(def));
3396                    }
3397                    chunks.extend(block);
3398                }
3399                let dummy = chunks
3400                    .into_iter()
3401                    .chain(self.convert_block(try_.orelse, BlockKind::Else { if_block_id }))
3402                    .chain(self.convert_block(try_.finalbody, BlockKind::Else { if_block_id }))
3403                    .collect();
3404                Expr::Dummy(Dummy::new(None, dummy))
3405            }
3406            py_ast::Stmt::With(mut with) => {
3407                let loc = with.location();
3408                let item = with.items.remove(0);
3409                let context_expr = self.convert_expr(item.context_expr);
3410                let body = self.convert_for_body(item.optional_vars.map(|x| *x), with.body);
3411                let with_ident = self.convert_ident("with".to_string(), loc);
3412                let with_acc = Expr::Accessor(Accessor::Ident(with_ident));
3413                with_acc.call2(context_expr, Expr::Lambda(body))
3414            }
3415            py_ast::Stmt::AsyncWith(mut with) => {
3416                let loc = with.location();
3417                let item = with.items.remove(0);
3418                let context_expr = self.convert_expr(item.context_expr);
3419                let body = self.convert_for_body(item.optional_vars.map(|x| *x), with.body);
3420                let with_ident = self.convert_ident("with".to_string(), loc);
3421                let with_acc = Expr::Accessor(Accessor::Ident(with_ident));
3422                with_acc.call2(context_expr, Expr::Lambda(body))
3423            }
3424            _other => {
3425                log!(err "unimplemented: {:?}", _other);
3426                Expr::Dummy(Dummy::new(None, vec![]))
3427            }
3428        }
3429    }
3430
3431    fn convert_glob_import(&mut self, location: PyLocation, module: String) -> Expr {
3432        let import_acc = Expr::Accessor(Accessor::Ident(
3433            self.convert_ident("__import__".to_string(), location),
3434        ));
3435        let sym = if module == "." { "__init__" } else { &module };
3436        let mod_name = Expr::Literal(Literal::new(quoted_symbol(
3437            sym,
3438            location.row.get(),
3439            location.column.to_zero_indexed(),
3440        )));
3441        let call = import_acc.clone().call1(mod_name);
3442        let var = VarSignature::new(VarPattern::Glob(Token::DUMMY), None);
3443        Expr::Def(Def::new(
3444            Signature::Var(var),
3445            DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)),
3446        ))
3447    }
3448
3449    /**
3450    ```erg
3451    from foo import bar # if bar, baz are modules
3452    # ↓
3453    .foo = import "foo"
3454    .bar = import "foo/bar"
3455    .baz = import "foo/baz"
3456
3457    from foo import bar, baz # if bar, baz are not modules
3458    # ↓
3459    {.bar; .baz} = import "foo"
3460
3461    from . import bar, baz # if bar, baz are modules
3462    # ↓
3463    .bar = import "./bar"
3464    .baz = import "./baz"
3465
3466    from . import bar, baz # if bar, baz are not modules
3467    # ↓
3468    {.bar; .baz} = import "__init__"
3469    ```
3470    */
3471    fn convert_from_import(
3472        &mut self,
3473        module: Option<py_ast::Identifier>,
3474        names: Vec<Alias>,
3475        location: PyLocation,
3476    ) -> Expr {
3477        let import_acc = Expr::Accessor(Accessor::Ident(
3478            self.convert_ident("__import__".to_string(), location),
3479        ));
3480        let module = module
3481            .map(|s| s.replace('.', "/"))
3482            .unwrap_or_else(|| ".".to_string());
3483        let module_path = Path::new(&module);
3484        let sym = if module == "." { "__init__" } else { &module };
3485        let mod_name = Expr::Literal(Literal::new(quoted_symbol(
3486            sym,
3487            location.row.get(),
3488            location.column.to_zero_indexed(),
3489        )));
3490        let call = import_acc.clone().call1(mod_name);
3491        let mut exprs = vec![];
3492        let mut imports = vec![];
3493        if names.len() == 1 && names[0].name.as_str() == "*" {
3494            return self.convert_glob_import(location, module);
3495        }
3496        let names_range = PySourceRange {
3497            start: names[0].location(),
3498            end: names[names.len() - 1].end_location(),
3499        };
3500        for name in names {
3501            let name_path = self
3502                .cfg
3503                .input
3504                .resolve_py(&module_path.join(name.name.as_str()));
3505            let true_name = self.convert_ident(name.name.to_string(), name.location());
3506            let as_loc = name.location();
3507            let alias = if let Some(alias) = name.asname {
3508                self.register_name_info(&alias, NameKind::Variable);
3509                let ident = self.convert_ident(alias.to_string(), as_loc);
3510                VarSignature::new(VarPattern::Ident(ident), None)
3511            } else {
3512                self.register_name_info(&name.name, NameKind::Variable);
3513                let ident = self.convert_ident(name.name.to_string(), name.location());
3514                VarSignature::new(VarPattern::Ident(ident), None)
3515            };
3516            // from foo import bar, baz (if bar, baz is a module) ==> bar = import "foo/bar"; baz = import "foo/baz"
3517            if let Ok(mut path) = name_path {
3518                if path.ends_with("__init__.py") {
3519                    path.pop();
3520                }
3521                let mod_name = path.file_name().unwrap_or_default();
3522                if name.name.as_str() == mod_name.to_string_lossy().trim_end_matches(".py") {
3523                    let sym = format!("{module}/{}", name.name);
3524                    let mod_name = Expr::Literal(Literal::new(quoted_symbol(
3525                        &sym,
3526                        location.row.get(),
3527                        location.column.to_zero_indexed(),
3528                    )));
3529                    let call = import_acc.clone().call1(mod_name);
3530                    let def = Def::new(
3531                        Signature::Var(alias),
3532                        DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)),
3533                    );
3534                    exprs.push(Expr::Def(def));
3535                } else {
3536                    // name.name: Foo, file_name: foo.py
3537                    imports.push(VarRecordAttr::new(true_name, alias));
3538                }
3539            } else {
3540                imports.push(VarRecordAttr::new(true_name, alias));
3541            }
3542        }
3543        let no_import = imports.is_empty();
3544        let attrs = VarRecordAttrs::new(imports);
3545        let braces = pyloc_to_ergloc(names_range);
3546        let pat = VarRecordPattern::new(braces, attrs);
3547        let var = VarSignature::new(VarPattern::Record(pat), None);
3548        let def = Expr::Def(Def::new(
3549            Signature::Var(var),
3550            DefBody::new(EQUAL, Block::new(vec![call]), DefId(0)),
3551        ));
3552        if no_import {
3553            Expr::Dummy(Dummy::new(None, exprs))
3554        } else if exprs.is_empty() {
3555            def
3556        } else {
3557            exprs.push(def);
3558            Expr::Dummy(Dummy::new(None, exprs))
3559        }
3560    }
3561
3562    pub fn convert_program(mut self, program: ModModule) -> IncompleteArtifact<Module> {
3563        let program = program
3564            .body
3565            .into_iter()
3566            .map(|stmt| self.convert_statement(stmt, true))
3567            .collect();
3568        let module = Desugarer::new().desugar(Module::new(program));
3569        IncompleteArtifact::new(Some(module), self.errs, self.warns)
3570    }
3571}