diff --git a/typechecker/src/build_source.rs b/typechecker/src/build_source.rs index 005f492b..ae484c52 100644 --- a/typechecker/src/build_source.rs +++ b/typechecker/src/build_source.rs @@ -29,7 +29,7 @@ impl BuildSource { } pub fn get_module_name(path: &Path) -> String { - path.to_str().unwrap_or_default().replace(['/', '\\'], ".") + path.to_str().unwrap().replace(['/', '\\'], ".") } // impl Into for BuildSource { diff --git a/typechecker/src/semantic_analyzer.rs b/typechecker/src/semantic_analyzer.rs index d9e544e4..d572d44b 100644 --- a/typechecker/src/semantic_analyzer.rs +++ b/typechecker/src/semantic_analyzer.rs @@ -608,7 +608,8 @@ impl TraversalVisitor for SemanticAnalyzer { self.symbol_table.exit_scope(); - let class_declaration = Declaration::Class(Class::new(c.clone(), methods)); + let class_declaration = + Declaration::Class(Class::new(c.clone(), methods, self.file.path())); let flags = SymbolFlags::empty(); self.create_symbol(c.name.clone(), class_declaration, flags); } diff --git a/typechecker/src/symbol_table.rs b/typechecker/src/symbol_table.rs index ca6a6c75..adbaf042 100644 --- a/typechecker/src/symbol_table.rs +++ b/typechecker/src/symbol_table.rs @@ -203,11 +203,11 @@ pub struct Class { } impl Class { - pub fn new(class_node: ast::ClassDef, methods: Vec) -> Self { + pub fn new(class_node: ast::ClassDef, methods: Vec, file_path: PathBuf) -> Self { Class { name: class_node.name.clone(), declaration_path: DeclarationPath { - module_name: PathBuf::new(), + module_name: file_path, node: Node { start: class_node.node.start, end: class_node.node.end, diff --git a/typechecker/src/type_check/.type_evaluator.rs.rustfmt b/typechecker/src/type_check/.type_evaluator.rs.rustfmt new file mode 100644 index 00000000..2aa1a8b8 --- /dev/null +++ b/typechecker/src/type_check/.type_evaluator.rs.rustfmt @@ -0,0 +1,1452 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +use core::panic; +use std::{fmt::format, path::Path}; + +use enderpy_python_parser as parser; +use enderpy_python_parser::ast; + +use miette::{bail, Result}; +use parser::ast::{Expression, GetNode, Statement}; + +use super::{ + builtins, + types::{CallableType, LiteralValue, PythonType}, +}; +use crate::{ + ast_visitor::TraversalVisitor, + ast_visitor_generic::TraversalVisitorImmutGeneric, + diagnostic::Position, + nodes::EnderpyFile, + semantic_analyzer::get_member_access_info, + symbol_table::{self, Class, Declaration, LookupSymbolRequest, SymbolTable, SymbolTableNode}, + type_check::types::ClassType, +}; + +const LITERAL_TYPE_PARAMETER_MSG: &str = "Type arguments for 'Literal' must be None, a literal value (int, bool, str, or bytes), or an enum value"; +// TODO: this is not the right message there are other types like Dict that are +// allowed as parameters +const UNION_TYPE_PARAMETER_MSG: &str = "Type arguments for 'Union' must be names or literal values"; + +const SPECIAL_FORM: &str = "_SpecialForm"; +pub struct TypeEvaluator { + // TODO: make this a reference to the symbol table in the checker + pub symbol_table: SymbolTable, + pub imported_symbol_tables: Vec, +} + +pub struct TypeEvalError { + pub message: String, + pub position: usize, +} + +/// Struct for evaluating the type of an expression +impl TypeEvaluator { + /// Entry point function to get type of an expression. The expression passed + /// to this function must not be annotations, for example if you want to + /// get the type of a variable declaration you should pass the value of + /// the declaration to this function. To get the type of an annotation + /// expression use get_type_from_annotation + pub fn get_type(&self, expr: &ast::Expression) -> Result { + log::debug!("get_type: {:#?}", expr); + let r = match expr { + ast::Expression::Constant(c) => { + let typ = match &c.value { + // We should consider constants are not literals unless they are explicitly + // declared as such https://peps.python.org/pep-0586/#type-inference + ast::ConstantValue::Int(_) => self.get_builtin_type("int").expect("typeshed"), + ast::ConstantValue::Float(_) => { + self.get_builtin_type("float").expect("typeshed") + } + ast::ConstantValue::Str(_) => self.get_builtin_type("str").expect("typeshed"), + ast::ConstantValue::Bool(_) => self.get_builtin_type("bool").expect("typeshed"), + ast::ConstantValue::None => PythonType::None, + _ => PythonType::Unknown, + }; + Ok(typ) + } + ast::Expression::Name(n) => { + if let Some(t) = self.get_builtin_type(&n.id) { + return Ok(t); + } + self.infer_type_from_symbol_table(&n.id, Some(n.node.start)) + } + ast::Expression::Call(call) => { + let called_name = *call.func.clone(); + let f_type = self.get_type(&called_name)?; + log::debug!("f_type: {:?}", f_type); + Ok(f_type) + } + ast::Expression::List(l) => { + let final_elm_type = self.get_sequence_type_from_elements(&l.elements); + let class_type = match self.get_builtin_type(builtins::LIST_TYPE) { + Some(builtin_type) => match builtin_type { + PythonType::Class(c) => c.details, + _ => panic!("List type is not a class"), + }, + None => return Ok(PythonType::Unknown), + }; + Ok(PythonType::Class(ClassType::new( + class_type, + vec![final_elm_type], + ))) + } + ast::Expression::Tuple(t) => { + let elm_type = self.get_sequence_type_from_elements(&t.elements); + let class_type = match self.get_builtin_type(builtins::TUPLE_TYPE) { + Some(builtin_type) => match builtin_type { + PythonType::Class(c) => c.details, + _ => panic!("Tuple type is not a class"), + }, + None => return Ok(PythonType::Unknown), + }; + + Ok(PythonType::Class(ClassType::new( + class_type, + vec![elm_type], + ))) + } + ast::Expression::Dict(d) => { + let key_type = self.get_sequence_type_from_elements(&d.keys); + let value_type = self.get_sequence_type_from_elements(&d.values); + let class_type = match self.get_builtin_type(builtins::DICT_TYPE) { + Some(builtin_type) => match builtin_type { + PythonType::Class(c) => c.details, + _ => panic!("Dict type is not a class"), + }, + None => return Ok(PythonType::Unknown), + }; + Ok(PythonType::Class(ClassType::new( + class_type, + vec![key_type, value_type], + ))) + } + ast::Expression::Set(s) => { + let elm_type = self.get_sequence_type_from_elements(&s.elements); + let class_type = match self.get_builtin_type(builtins::SET_TYPE) { + Some(builtin_type) => match builtin_type { + PythonType::Class(c) => c.details, + _ => panic!("Dict type is not a class"), + }, + None => return Ok(PythonType::Unknown), + }; + Ok(PythonType::Class(ClassType::new( + class_type, + vec![elm_type], + ))) + } + ast::Expression::BoolOp(_) => Ok(self.get_builtin_type("bool").expect("typeshed")), + ast::Expression::UnaryOp(u) => match u.op { + ast::UnaryOperator::Not => Ok(self.get_builtin_type("bool").expect("typeshed")), + ast::UnaryOperator::Invert => match self.get_type(&u.operand)? { + // TODO: dummy + PythonType::Class(_) => Ok(PythonType::Unknown), + _ => bail!( + "cannot invert type {}", + self.get_type(&u.operand)?.to_string() + ), + }, + _ => self.get_type(&u.operand), + }, + ast::Expression::NamedExpr(e) => self.get_type(&e.value), + ast::Expression::Yield(a) => { + let yield_type = match a.value { + Some(ref v) => self.get_type(v)?, + None => PythonType::None, + }; + let builtin_type = self.get_builtin_type(builtins::ITER_TYPE); + todo!() + } + ast::Expression::YieldFrom(yf) => { + let yield_type = match *yf.value.clone() { + ast::Expression::List(l) => self.get_sequence_type_from_elements(&l.elements), + _ => panic!("TODO: infer type from yield from"), + }; + todo!() + } + ast::Expression::Starred(s) => Ok(PythonType::Unknown), + ast::Expression::Generator(g) => { + // This is not correct + // let mut comp_targets: HashMap = HashMap::new(); + // for gens in &g.generators { + // match *gens.target.clone() { + // ast::Expression::Name(n) => { + // comp_targets.insert(n.id, self.get_type(&gens.iter)); + // } + // _ => panic!("comprehension target must be a name, or does it?"), + // } + // } + + Ok(PythonType::Unknown) + } + ast::Expression::ListComp(_) => Ok(PythonType::Unknown), + ast::Expression::SetComp(_) => Ok(PythonType::Unknown), + ast::Expression::DictComp(_) => Ok(PythonType::Unknown), + /* + When attribute is accessed there are multilple cases: + + 1. Accessing an attribute of a class inside the class through self + ``` + class A: + def __init__(self): + self.a = 1 + def get_a(self): + return self.a + + # or a class method + @class_method + def class_method(cls): + return cls.a + ``` + + 2. Accessing an attribute of a class outside the class + ``` + class A: + def __init__(self): + self.a = 1 + a = A() + print(a.a) + ``` + */ + ast::Expression::Attribute(a) => { + // Case 1 + log::debug!("Attribute access {:#?}", a); + if get_member_access_info(&self.symbol_table, &a.value).is_some() { + let enclosing_parent_class = self.symbol_table.get_enclosing_class_scope(); + if let Some(enclosing_parent_class) = enclosing_parent_class { + let symbol_table_node = self + .symbol_table + .lookup_attribute(&a.attr, enclosing_parent_class); + let res = match symbol_table_node { + Some(node) => self.get_symbol_node_type(node, None), + None => panic!("cannot find symbol table node for attribute access"), + }; + + log::debug!("attribute access result: {:?}", res); + + return res; + } + } + + // Case 2 + // First find the type of the attribute and then find the value in the scope of the attribute + + let value_type = match self.get_type(&a.value) { + Ok(t) => t, + Err(e) => { + log::debug!("error getting type of attribute value: {:?}", e); + return Ok(PythonType::Unknown); + } + }; + log::debug!("looking up attribute in type: {:?}", value_type); + match value_type { + PythonType::Class(c) => { + let class_scope = self.get_scope_of(&c); + log::debug!("class scope for the attribute: {:#?}", class_scope); + let symbol_table_node = + self.symbol_table.lookup_attribute(&a.attr, class_scope); + log::debug!("found symbol table node: {:#?}", symbol_table_node); + let result = match symbol_table_node { + Some(node) => self.get_symbol_node_type(node, None), + None => Ok(PythonType::Unknown), + }; + + log::debug!("attribute access result: {:?}", result); + result + } + _ => Ok(PythonType::Unknown), + } + } + ast::Expression::BinOp(b) => Ok(self.bin_op_result_type( + &self.get_type(&b.left)?, + &self.get_type(&b.right)?, + &b.op, + )), + ast::Expression::Subscript(s) => { + let value_type = &self.get_type(&s.value)?; + // This only handles container types and TODO + Ok(value_type.clone()) + } + ast::Expression::Slice(_) => Ok(PythonType::Unknown), + ast::Expression::Await(_) => Ok(PythonType::Unknown), + ast::Expression::Compare(_) => Ok(self.get_builtin_type("str").expect("typeshed")), + ast::Expression::Lambda(_) => Ok(PythonType::Unknown), + ast::Expression::IfExp(_) => Ok(PythonType::Unknown), + ast::Expression::JoinedStr(_) => Ok(self.get_builtin_type("str").expect("typeshed")), + ast::Expression::FormattedValue(f) => self.get_type(&f.value), + }; + + log::debug!("get_type for expression: {:#?} => {:?}", expr, r); + + r + } + + // This function tries to find the python type from an annotation expression + // If the annotation is invalid it returns unknown type + pub fn get_type_from_annotation(&self, type_annotation: &ast::Expression) -> PythonType { + log::debug!("Getting type from annotation: {:?}", type_annotation); + let expr_type = match type_annotation { + // TODO: implement + Expression::Name(name) => { + if builtins::ALL_BUILTINS.contains(&name.id.as_str()) { + return self.get_builtin_type(&name.id).expect("typeshed"); + }; + + PythonType::Unknown + } + Expression::Constant(c) => { + if let ast::ConstantValue::None = c.value { + PythonType::None + // Illegal type annotation should report an error + } else { + PythonType::Unknown + } + } + Expression::Subscript(s) => { + // This is a generic type + let typ = self.get_class_declaration(&s.value, &self.symbol_table); + match typ { + Some(typ) => { + if typ.special { + return match typ.name.as_str() { + "Literal" => self.handle_literal_type(s), + "Union" => { + // try to convert subscript value into tuple and send the tuple + // items as parameters to union type + let union_parameters = match *s.slice.clone() { + Expression::Tuple(t) => t.elements, + _ => todo!(), + }; + self.handle_union_type(union_parameters) + } + _ => todo!(), + }; + } + let type_parameters = vec![self.get_type_from_annotation(&s.slice)]; + PythonType::Class(ClassType { + details: typ, + type_parameters, + }) + } + // Illegal type annotation? Trying to subscript a non class type + None => PythonType::Unknown, + } + } + Expression::BinOp(b) => { + match b.op { + // Union type + ast::BinaryOperator::BitOr => { + // flatten the bit or expression if the left and right are also bit or + let union_parameters = self.flatten_bit_or(b); + self.handle_union_type(union_parameters) + } + // TODO: check if other binary operators are allowed + _ => todo!(), + } + } + _ => PythonType::Unknown, + }; + + expr_type + } + + fn infer_type_from_symbol_table( + &self, + name: &str, + position: Option, + ) -> Result { + let lookup_request = LookupSymbolRequest { + name: name.to_string(), + position, + }; + let result = match self.symbol_table.lookup_in_scope(lookup_request) { + Some(symbol) => self.get_symbol_node_type(symbol, position), + None => Ok(PythonType::Unknown), + }; + log::debug!("infer_type_from_symbol_table: {:?} => {:?}", name, result); + result + } + + /// Get the type of a symbol node based on declarations + fn get_symbol_node_type( + &self, + symbol: &SymbolTableNode, + position: Option, + ) -> Result { + let decl = match position { + Some(position) => symbol.declaration_until_position(position), + None => Some(symbol.last_declaration()), + }; + + log::debug!("found {} declaration: {:#?}", symbol, decl); + let result = match decl { + Some(decl) => match decl { + Declaration::Variable(v) => { + if let Some(type_annotation) = &v.type_annotation { + Ok(self.get_type_from_annotation(type_annotation)) + } else if let Some(source) = &v.inferred_type_source { + self.get_type(source) + } else { + Ok(PythonType::Unknown) + } + } + Declaration::Function(f) => { + let annotated_return_type = + if let Some(type_annotation) = f.function_node.returns.clone() { + self.get_type_from_annotation(&type_annotation) + } else { + let inferred_return_type = self.infer_function_return_type(f); + log::debug!("inferred_return_type: {:?}", inferred_return_type); + inferred_return_type + }; + + let arguments = f.function_node.args.clone(); + let name = f.function_node.name.clone(); + + Ok(PythonType::Callable(Box::new(CallableType { + name, + arguments, + return_type: annotated_return_type, + }))) + } + Declaration::Parameter(p) => { + if let Some(type_annotation) = &p.type_annotation { + log::debug!("parameter type annotation: {:?}", type_annotation); + + Ok(self.get_type_from_annotation(type_annotation)) + } else if let Some(default) = &p.default_value { + self.get_type(default) + } else { + Ok(PythonType::Any) + } + } + Declaration::Alias(_) => Ok(PythonType::Unknown), + Declaration::TypeParameter(_) => Ok(PythonType::Unknown), + Declaration::TypeAlias(_) => Ok(PythonType::Unknown), + Declaration::Class(c) => Ok(PythonType::Class(ClassType::new(c.clone(), vec![]))), + }, + None => Ok(PythonType::Any), + }; + + log::debug!( + "evaluated type based on declaration: {} => {:?}", + symbol, + result + ); + result + } + + fn get_sequence_type_from_elements(&self, elements: &Vec) -> PythonType { + let mut prev_elm_type = PythonType::Unknown; + for elm in elements { + let elm_type = self.get_type(elm).unwrap_or(PythonType::Unknown); + if prev_elm_type == PythonType::Unknown { + prev_elm_type = elm_type; + } else if prev_elm_type != elm_type { + prev_elm_type = PythonType::Unknown; + break; + } + } + prev_elm_type + } + + fn infer_function_return_type(&self, f: &crate::symbol_table::Function) -> PythonType { + if !f.is_abstract() && !f.raise_statements.is_empty() { + return PythonType::Never; + } + if !f.yield_statements.is_empty() { + let mut yield_types = vec![]; + for yield_statement in &f.yield_statements { + if let Some(value) = &yield_statement.value { + yield_types.push(self.get_type(value).unwrap_or(PythonType::Unknown)); + } + } + if yield_types.len() == 1 { + todo!() + // return PythonType::Class(super::types::ClassType { + // name: builtins::ITER_TYPE.to_string(), + // args: vec![yield_types[0].clone()], + // }); + } else { + // TODO: Union type + return PythonType::Unknown; + } + } + if f.return_statements.is_empty() { + PythonType::None + } else { + let mut return_types = vec![]; + for return_statement in &f.return_statements { + if let Some(value) = &return_statement.value { + return_types.push(self.get_type(value).unwrap_or(PythonType::Unknown)); + } + } + if return_types.len() == 1 { + return_types[0].clone() + } else { + // TODO: Union type + PythonType::Unknown + } + } + } + + /// Retrieves a pythoh type that is present in the builtin scope + fn get_builtin_type(&self, name: &str) -> Option { + log::debug!("Getting builtin type: {}", name); + // typeshed has a function class which is not supposed to be there. + // https://github.com/python/typeshed/issues/2999 + if name == "function" { + return None; + } + let bulitins_symbol_table = match self + .imported_symbol_tables + .iter() + .find(|symbol_table| symbol_table.file_path.ends_with("stdlib/builtins.pyi")) + { + Some(symbol_table) => symbol_table, + None => { + let all_symbol_table_names = self + .imported_symbol_tables + .iter() + .map(|symbol_table| symbol_table.module_name.clone()) + .collect::>(); + panic!( + "Builtin symbol table not found in {:?}", + all_symbol_table_names + ); + } + }; + let builtin_symbol = bulitins_symbol_table.lookup_in_scope(LookupSymbolRequest { + name: name.to_string(), + position: None, + }); + return match builtin_symbol { + None => { + log::debug!("builtin type {} not found", name); + None + } + Some(node) => { + // get the declaration with type class + node.declarations.iter().find_map(|decl| match decl { + Declaration::Class(c) => { + Some(PythonType::Class(ClassType::new(c.clone(), vec![]))) + } + Declaration::Function(f) => { + let arguments = f.function_node.args.clone(); + let name = f.function_node.name.clone(); + Some(PythonType::Callable(Box::new(CallableType { + name, + arguments, + return_type: f + .function_node + .returns + .clone() + .map_or(PythonType::Unknown, |type_annotation| { + self.get_type_from_annotation(&type_annotation) + }), + }))) + } + _ => None, + }) + } + }; + } + + /// This function flattens a chain of bit or expressions + /// For example: a | b | c | d + /// will be flattened to [a, b, c, d] + fn flatten_bit_or(&self, b: &ast::BinOp) -> Vec { + let mut union_parameters = vec![]; + let mut current_expr = b.left.clone(); + + while let Expression::BinOp(inner_binop) = *current_expr.clone() { + if let ast::BinaryOperator::BitOr = inner_binop.op { + union_parameters.push(*inner_binop.right.clone()); + current_expr = inner_binop.left; + } else { + union_parameters.push(*current_expr.clone()); + break; + } + } + + union_parameters.push(*current_expr.clone()); + + current_expr = b.right.clone(); + + while let Expression::BinOp(inner_binop) = *current_expr.clone() { + if let ast::BinaryOperator::BitOr = inner_binop.op { + union_parameters.push(*inner_binop.right.clone()); + current_expr = inner_binop.left; + } else { + union_parameters.push(*current_expr.clone()); + break; + } + } + + union_parameters.push(*current_expr.clone()); + union_parameters + } + + /// https://peps.python.org/pep-0484/#union-types + /// expressions are the parameters of the union type + /// in case of t1 | t2 | t3, expressions are [t1, t2, t3] + /// and in case of Union[t1, t2, t3], expressions are [t1, t2, t3] + fn handle_union_type(&self, expressions: Vec) -> PythonType { + log::debug!("Handling union type with members: {:?}", expressions); + let mut types = vec![]; + for expr in expressions { + let t = self.get_type_from_annotation(&expr); + if self.is_valid_union_parameter(&t) { + log::debug!("Union type parameter: {:?}", t); + types.push(t); + } + } + + // If we don't have any types in the union type, it means that all the + // parameters were invalid So we return unknown type + if types.is_empty() { + return PythonType::Unknown; + } + + PythonType::MultiValue(types) + } + + /// TODO: Need to complete this when types are more complete + /// Check if a type can be used as a parameter for a union type + fn is_valid_union_parameter(&self, python_type: &PythonType) -> bool { + true + } + + // https://peps.python.org/pep-0586 + fn handle_literal_type(&self, s: &ast::Subscript) -> PythonType { + // Only simple parameters are allowed for literal type: + // https://peps.python.org/pep-0586/#legal-and-illegal-parameterizations + let value = self.get_literal_value_from_param(&s.slice.clone()); + if value.len() > 1 { + todo!("MultiValue literal type is not supported yet") + } + + PythonType::KnownValue(super::types::KnownValue { + literal_value: value.last().unwrap().clone(), + }) + } + + /// Write a function that takes in an expression which is a parameter to a + /// literal type and returns the LiteralValue of the parameter. + /// Literal values might contain a tuple, that's why the return type is a + /// vector. + pub fn get_literal_value_from_param(&self, expr: &Expression) -> Vec { + log::debug!("Getting literal value from param: {:?}", expr); + let val = match expr { + Expression::Constant(c) => { + match c.value.clone() { + ast::ConstantValue::Bool(b) => LiteralValue::Bool(b), + ast::ConstantValue::Int(i) => LiteralValue::Int(i), + ast::ConstantValue::Float(f) => LiteralValue::Float(f), + ast::ConstantValue::Str(s) => LiteralValue::Str(s), + ast::ConstantValue::Bytes(b) => LiteralValue::Bytes(b), + ast::ConstantValue::None => LiteralValue::None, + // Tuple is illegal if it has parentheses, otherwise it's allowed and the output + // a multiValued type Currently even mypy does not support + // this, who am I to do it? https://mypy-play.net/?mypy=latest&python=3.10&gist=0df0421d5c85f3b75f65a51cae8616ce + ast::ConstantValue::Tuple(t) => { + if t.len() == 1 { + match t[0].value.clone() { + ast::ConstantValue::Bool(b) => LiteralValue::Bool(b), + ast::ConstantValue::Int(i) => LiteralValue::Int(i), + ast::ConstantValue::Float(f) => LiteralValue::Float(f), + ast::ConstantValue::Str(s) => LiteralValue::Str(s), + ast::ConstantValue::Bytes(b) => LiteralValue::Bytes(b), + ast::ConstantValue::None => LiteralValue::None, + _ => panic!("Tuple type with illegal parameter"), + } + } else { + let literal_values = t + .iter() + .map(|c| match c.value.clone() { + ast::ConstantValue::Bool(b) => LiteralValue::Bool(b), + ast::ConstantValue::Int(i) => LiteralValue::Int(i), + ast::ConstantValue::Float(f) => LiteralValue::Float(f), + ast::ConstantValue::Str(s) => LiteralValue::Str(s), + ast::ConstantValue::Bytes(b) => LiteralValue::Bytes(b), + ast::ConstantValue::None => LiteralValue::None, + _ => panic!("Tuple type with illegal parameter"), + }) + .collect(); + return literal_values; + } + } + // Illegal parameter + ast::ConstantValue::Ellipsis => { + panic!("Literal type with ellipsis value is not supported") + } + ast::ConstantValue::Complex { real, imaginary } => { + panic!("Literal type with complex value is not supported") + } + } + } + // Only can be enum values + Expression::Attribute(a) => { + let value = match *a.value.clone() { + Expression::Name(n) => n.id, + _ => panic!("Literal type with attribute value can only be a name"), + }; + LiteralValue::Str(value) + } + Expression::Subscript(s) => { + match *s.value.clone() { + Expression::Name(n) => { + if !self.is_literal(n.id.clone()) { + panic!("{}", LITERAL_TYPE_PARAMETER_MSG) + } + // When there is a literal inside a literal we flatten it + return self.get_literal_value_from_param(&s.slice); + } + _ => panic!("{}", LITERAL_TYPE_PARAMETER_MSG), + }; + } + // Illegal parameter + _ => { + panic!("Literal type with illegal parameter, can only be a constant value or enum") + } + }; + + vec![val] + } + + pub fn type_equal(&self, t1: &PythonType, t2: &PythonType) -> bool { + t1.type_equal(t2) + } + + pub fn bin_op_result_type( + &self, + t1: &PythonType, + t2: &PythonType, + op: &ast::BinaryOperator, + ) -> PythonType { + // Dummy + t1.clone() + } + + pub fn is_literal(&self, name: String) -> bool { + name.as_str() == "Literal" + } + + fn is_union(&self, clone: String) -> bool { + clone.as_str() == "Union" + } + + pub fn is_subscriptable(&self, t: &PythonType) -> bool { + if let PythonType::Class(c) = t { + let class_name = c.details.name.as_str(); + return matches!(class_name, builtins::LIST_TYPE) + || matches!(class_name, builtins::TUPLE_TYPE) + || matches!(class_name, builtins::DICT_TYPE) + || matches!(class_name, builtins::SET_TYPE); + } + + false + } + + /// The expression is assumed to be used in type annotation context. + /// So some expressions are not allowed, for example a function call + fn get_class_declaration( + &self, + expression: &Expression, + symbol_table: &SymbolTable, + ) -> Option { + log::debug!( + "following symbol table until finding class for {:?}", + expression + ); + match expression { + // This is a Generic type with a param: Container[type, ...] + // name here is something like list or List or Literal or user defined class + Expression::Name(n) => { + // if it's not a builtin we want to get the class declaration + // form symbol table and find where this class + + if let Some(builtin_type) = self.get_builtin_type(&n.id) { + match builtin_type { + PythonType::Class(c) => return Some(c.details), + _ => panic!("Builtin type is not a class"), + } + } + + let mut declaration = match symbol_table.lookup_in_scope(LookupSymbolRequest { + name: n.id.clone(), + position: Some(n.node.start), + }) { + Some(s) => s.last_declaration(), + None => return None, + }; + + // Follow symbols until we find a class declaration + loop { + log::debug!("container_decl: {:?}", declaration); + match declaration { + Declaration::Class(c) => { + return Some(c.clone()); + } + Declaration::Alias(a) => { + declaration = match self.resolve_alias(a) { + Some(decl) => decl.last_declaration(), + None => panic!("Alias {:?} not found", a), + }; + log::debug!("alias resolved to: {:?}", declaration); + } + // This is only valid if we are in a pyi file. + // In other contexts a variable declaration cannot be pointing to a class + Declaration::Variable(v) => { + let found_in_symbol_table = self + .get_symbol_table_of(&v.declaration_path.module_name) + .expect("Variable declaration not found in symbol table"); + // if not in a pyi file panic + if !found_in_symbol_table.is_pyi() { + panic!("Variable declaration cannot be pointing to a class") + } + + let pointing_class = match &v.type_annotation { + Some(annotation) => { + let class = self + .get_class_declaration(annotation, found_in_symbol_table)?; + if class.name == SPECIAL_FORM { + return Some(Class::new_special(n.id.clone(), class)); + } + Some(class) + } + None => { + todo!("Variable declaration without type annotation") + } + }; + + let class_def = match pointing_class { + None => return None, + Some(ref pointing_class) => pointing_class, + }; + + return Some(class_def.clone()); + } + _ => return None, + } + } + } + // Allowed but TODO + Expression::Attribute(_) => todo!(), + Expression::Subscript(_) => todo!(), + Expression::Slice(_) => todo!(), + _ => panic!( + "Expression {:?} is not allowed in type annotation", + expression + ), + } + } + + // Follows Alias declaration and resolves it to a class declaration + // It searches through imported symbol tables for the module alias imports + // and resolves the alias to the class declaration + // TODO: refactor all liases and not only classes + fn resolve_alias(&self, a: &symbol_table::Alias) -> Option<&symbol_table::SymbolTableNode> { + log::debug!("resolving alias: {:?}", a); + let class_name = match a.symbol_name { + Some(ref name) => name.clone(), + None => panic!("Alias {:?} has no symbol name", a.import_node), + }; + + let resolved_path = match a.import_result.resolved_paths.last() { + Some(path) => path, + None => panic!("Alias {:?} has no resolved path available are", a), + }; + + let symbol_table_with_alias_def = self.get_symbol_table_of(resolved_path); + return symbol_table_with_alias_def?.lookup_in_scope(LookupSymbolRequest { + name: class_name.clone(), + position: None, + }); + } + + fn get_symbol_table_of(&self, path: &Path) -> Option<&SymbolTable> { + let symbol_table = self + .imported_symbol_tables + .iter() + .find(|symbol_table| symbol_table.file_path == path); + symbol_table + } + + fn get_scope_of(&self, c: &ClassType) -> &symbol_table::SymbolTableScope { + let symbol_table = self + .imported_symbol_tables + .iter() + .find(|symbol_table| { + symbol_table + .file_path + .ends_with(&c.details.declaration_path.module_name) + }) + .unwrap_or_else(|| { + panic!( + "Declaration path not found: {:?}", + c.details.declaration_path, + ) + }); + symbol_table + .get_scope(&c.details.declaration_path.node) + .unwrap_or_else(|| panic!("Scope not found for: {:?}", c.details.declaration_path)) + } +} + +impl TraversalVisitorImmutGeneric for TypeEvaluator { + fn visit_stmt(&self, s: &ast::Statement) -> PythonType { + // map all statements and call visit + match s { + ast::Statement::ExpressionStatement(e) => self.visit_expr(e), + ast::Statement::Import(i) => self.visit_import(i), + ast::Statement::ImportFrom(i) => self.visit_import_from(i), + ast::Statement::AssignStatement(a) => self.visit_assign(a), + ast::Statement::AnnAssignStatement(a) => self.visit_ann_assign(a), + ast::Statement::AugAssignStatement(a) => self.visit_aug_assign(a), + ast::Statement::Assert(a) => self.visit_assert(a), + ast::Statement::Pass(p) => self.visit_pass(p), + ast::Statement::Delete(d) => self.visit_delete(d), + ast::Statement::Return(r) => self.visit_return(r), + ast::Statement::Raise(r) => self.visit_raise(r), + ast::Statement::Break(b) => self.visit_break(b), + ast::Statement::Continue(c) => self.visit_continue(c), + ast::Statement::Global(g) => self.visit_global(g), + ast::Statement::Nonlocal(n) => self.visit_nonlocal(n), + ast::Statement::IfStatement(i) => self.visit_if(i), + ast::Statement::WhileStatement(w) => self.visit_while(w), + ast::Statement::ForStatement(f) => self.visit_for(f), + ast::Statement::WithStatement(w) => self.visit_with(w), + ast::Statement::TryStatement(t) => self.visit_try(t), + ast::Statement::TryStarStatement(t) => self.visit_try_star(t), + ast::Statement::FunctionDef(f) => self.visit_function_def(f), + ast::Statement::ClassDef(c) => self.visit_class_def(c), + ast::Statement::Match(m) => self.visit_match(m), + Statement::AsyncForStatement(f) => self.visit_async_for(f), + Statement::AsyncWithStatement(w) => self.visit_async_with(w), + Statement::AsyncFunctionDef(f) => self.visit_async_function_def(f), + Statement::TypeAlias(a) => self.visit_type_alias(a), + } + } + + fn visit_expr(&self, e: &ast::Expression) -> PythonType { + match e { + ast::Expression::Constant(c) => self.visit_constant(c), + ast::Expression::List(l) => self.visit_list(l), + ast::Expression::Tuple(t) => self.visit_tuple(t), + ast::Expression::Dict(d) => self.visit_dict(d), + ast::Expression::Set(s) => self.visit_set(s), + ast::Expression::Name(n) => self.visit_name(n), + ast::Expression::BoolOp(b) => self.visit_bool_op(b), + ast::Expression::UnaryOp(u) => self.visit_unary_op(u), + ast::Expression::BinOp(b) => self.visit_bin_op(b), + ast::Expression::NamedExpr(n) => self.visit_named_expr(n), + ast::Expression::Yield(y) => self.visit_yield(y), + ast::Expression::YieldFrom(y) => self.visit_yield_from(y), + ast::Expression::Starred(s) => self.visit_starred(s), + ast::Expression::Generator(g) => self.visit_generator(g), + ast::Expression::ListComp(l) => self.visit_list_comp(l), + ast::Expression::SetComp(s) => self.visit_set_comp(s), + ast::Expression::DictComp(d) => self.visit_dict_comp(d), + ast::Expression::Attribute(a) => self.visit_attribute(a), + ast::Expression::Subscript(s) => self.visit_subscript(s), + ast::Expression::Slice(s) => self.visit_slice(s), + ast::Expression::Call(c) => self.visit_call(c), + ast::Expression::Await(a) => self.visit_await(a), + ast::Expression::Compare(c) => self.visit_compare(c), + ast::Expression::Lambda(l) => self.visit_lambda(l), + ast::Expression::IfExp(i) => self.visit_if_exp(i), + ast::Expression::JoinedStr(j) => self.visit_joined_str(j), + ast::Expression::FormattedValue(f) => self.visit_formatted_value(f), + } + } + + fn visit_import(&self, _i: &ast::Import) -> PythonType { + PythonType::Unknown + } + + fn visit_import_from(&self, _i: &ast::ImportFrom) -> PythonType { + PythonType::Unknown + } + + fn visit_if(&self, i: &parser::ast::If) -> PythonType { + PythonType::Unknown + } + + fn visit_while(&self, w: &parser::ast::While) -> PythonType { + PythonType::Unknown + } + + fn visit_for(&self, f: &parser::ast::For) -> PythonType { + PythonType::Unknown + } + + fn visit_with(&self, w: &parser::ast::With) -> PythonType { + PythonType::Unknown + } + + fn visit_try(&self, t: &parser::ast::Try) -> PythonType { + PythonType::Unknown + } + + fn visit_try_star(&self, t: &parser::ast::TryStar) -> PythonType { + PythonType::Unknown + } + + fn visit_function_def(&self, f: &parser::ast::FunctionDef) -> PythonType { + PythonType::Any + } + + fn visit_class_def(&self, c: &parser::ast::ClassDef) -> PythonType { + PythonType::Unknown + } + + fn visit_match(&self, m: &parser::ast::Match) -> PythonType { + PythonType::Unknown + } + + fn visit_constant(&self, _c: &ast::Constant) -> PythonType { + PythonType::Unknown + } + + fn visit_list(&self, _l: &ast::List) -> PythonType { + PythonType::Unknown + } + + fn visit_tuple(&self, _t: &ast::Tuple) -> PythonType { + PythonType::Unknown + } + + fn visit_dict(&self, _d: &ast::Dict) -> PythonType { + PythonType::Unknown + } + + fn visit_set(&self, _s: &ast::Set) -> PythonType { + PythonType::Unknown + } + + fn visit_name(&self, _n: &ast::Name) -> PythonType { + PythonType::Unknown + } + + fn visit_bool_op(&self, _b: &ast::BoolOperation) -> PythonType { + PythonType::Unknown + } + + fn visit_unary_op(&self, _u: &ast::UnaryOperation) -> PythonType { + PythonType::Unknown + } + + fn visit_bin_op(&self, _b: &ast::BinOp) -> PythonType { + PythonType::Unknown + } + + fn visit_named_expr(&self, _n: &ast::NamedExpression) -> PythonType { + PythonType::Unknown + } + + fn visit_yield(&self, _y: &ast::Yield) -> PythonType { + PythonType::Unknown + } + + fn visit_yield_from(&self, _y: &ast::YieldFrom) -> PythonType { + PythonType::Unknown + } + + fn visit_starred(&self, _s: &ast::Starred) -> PythonType { + PythonType::Unknown + } + + fn visit_generator(&self, _g: &ast::Generator) -> PythonType { + PythonType::Unknown + } + + fn visit_list_comp(&self, _l: &ast::ListComp) -> PythonType { + PythonType::Unknown + } + + fn visit_set_comp(&self, _s: &ast::SetComp) -> PythonType { + PythonType::Unknown + } + + fn visit_dict_comp(&self, _d: &ast::DictComp) -> PythonType { + PythonType::Unknown + } + + fn visit_attribute(&self, _a: &ast::Attribute) -> PythonType { + PythonType::Unknown + } + + fn visit_subscript(&self, _s: &ast::Subscript) -> PythonType { + PythonType::Unknown + } + + fn visit_slice(&self, _s: &ast::Slice) -> PythonType { + PythonType::Unknown + } + + fn visit_call(&self, _c: &ast::Call) -> PythonType { + PythonType::Unknown + } + + fn visit_await(&self, _a: &ast::Await) -> PythonType { + PythonType::Unknown + } + + fn visit_compare(&self, _c: &ast::Compare) -> PythonType { + PythonType::Unknown + } + + fn visit_lambda(&self, _l: &ast::Lambda) -> PythonType { + PythonType::Unknown + } + + fn visit_if_exp(&self, _i: &ast::IfExp) -> PythonType { + PythonType::Unknown + } + + fn visit_joined_str(&self, _j: &ast::JoinedStr) -> PythonType { + PythonType::Unknown + } + + fn visit_formatted_value(&self, _f: &ast::FormattedValue) -> PythonType { + PythonType::Unknown + } + + fn visit_alias(&self, _a: &ast::Alias) -> PythonType { + PythonType::Unknown + } + + fn visit_assign(&self, _a: &ast::Assign) -> PythonType { + PythonType::Unknown + } + + fn visit_ann_assign(&self, _a: &ast::AnnAssign) -> PythonType { + PythonType::Unknown + } + + fn visit_aug_assign(&self, _a: &ast::AugAssign) -> PythonType { + PythonType::Unknown + } + + fn visit_assert(&self, _a: &ast::Assert) -> PythonType { + PythonType::Unknown + } + + fn visit_pass(&self, _p: &ast::Pass) -> PythonType { + PythonType::Unknown + } + + fn visit_delete(&self, _d: &ast::Delete) -> PythonType { + PythonType::Unknown + } + + fn visit_return(&self, _r: &ast::Return) -> PythonType { + PythonType::Unknown + } + + fn visit_raise(&self, _r: &ast::Raise) -> PythonType { + PythonType::Unknown + } + + fn visit_break(&self, _b: &ast::Break) -> PythonType { + PythonType::Unknown + } + + fn visit_continue(&self, _c: &ast::Continue) -> PythonType { + PythonType::Unknown + } + + fn visit_global(&self, _g: &ast::Global) -> PythonType { + PythonType::Unknown + } + + fn visit_nonlocal(&self, _n: &ast::Nonlocal) -> PythonType { + PythonType::Unknown + } +} + +/// visits the ast and calls get_type on each expression and saves that type in +/// the types hashmap the key is the position of the expression in the source: +/// (line, start, end) +struct DumpTypes { + pub type_eval: TypeEvaluator, + pub types: Vec, + pub enderpy_file: EnderpyFile, +} + +#[derive(Debug, Clone)] +struct SnapshtType { + pub position: Position, + pub symbol_text: String, + pub typ: PythonType, +} + +impl DumpTypes { + pub fn new(enderpy_file: EnderpyFile, type_eval: TypeEvaluator) -> Self { + Self { + types: vec![], + type_eval, + enderpy_file, + } + } + + pub fn enderpy_file(&self) -> &EnderpyFile { + &self.enderpy_file + } + + /// This function is called on every expression in the ast + pub fn save_type(&mut self, expr: &ast::Expression) { + let typ = self.type_eval.get_type(expr).unwrap_or(PythonType::Unknown); + log::debug!("save_type: {:#?} => {:#?}", expr, typ); + let symbol_text = + self.enderpy_file().source()[expr.get_node().start..expr.get_node().end].to_string(); + let position = self.enderpy_file().get_position(expr.get_node().start); + let typ = SnapshtType { + position, + symbol_text, + typ, + }; + self.types.push(typ); + } + + // TODO: move type annotation tests to its own file + pub fn save_type_annotation(&mut self, expr: &ast::Expression) { + let typ = self.type_eval.get_type_from_annotation(expr); + log::debug!("save_type: {:?} => {:?}", expr, typ); + let symbol_text = + self.enderpy_file().source()[expr.get_node().start..expr.get_node().end].to_string(); + let typ = SnapshtType { + position: self.enderpy_file().get_position(expr.get_node().start), + symbol_text, + typ, + }; + self.types.push(typ); + } + + fn visit_module(&mut self) { + let body = self.enderpy_file().body.clone(); + for statement in body.iter() { + self.visit_stmt(statement); + } + } +} + +/// Traverse the ast and call call save_type on each expression +impl TraversalVisitor for DumpTypes { + fn visit_stmt(&mut self, s: &ast::Statement) { + // map all statements and call visit + match s { + ast::Statement::ExpressionStatement(e) => self.visit_expr(e), + ast::Statement::Import(i) => {} + ast::Statement::ImportFrom(i) => {} + ast::Statement::AssignStatement(a) => { + self.save_type(&a.value); + } + ast::Statement::AnnAssignStatement(a) => { + if let Some(v) = a.value.as_ref() { + self.save_type(v); + } + + self.save_type_annotation(&a.annotation) + } + ast::Statement::AugAssignStatement(a) => (), + ast::Statement::Assert(a) => (), + ast::Statement::Pass(p) => (), + ast::Statement::Delete(d) => (), + ast::Statement::Return(r) => { + if let Some(r) = r.value.as_ref() { + self.visit_expr(r); + self.save_type(r); + } + } + ast::Statement::Raise(r) => { + if let Some(r) = r.exc.as_ref() { + self.save_type(r); + } + if let Some(r) = r.cause.as_ref() { + self.save_type(r); + } + } + ast::Statement::Break(b) => (), + ast::Statement::Continue(c) => (), + ast::Statement::Global(g) => (), + ast::Statement::Nonlocal(n) => (), + ast::Statement::IfStatement(i) => (), + ast::Statement::WhileStatement(w) => (), + ast::Statement::ForStatement(f) => (), + ast::Statement::WithStatement(w) => (), + ast::Statement::TryStatement(t) => (), + ast::Statement::TryStarStatement(t) => (), + ast::Statement::FunctionDef(f) => { + // This is duplicated + self.type_eval.symbol_table.set_scope(f.node.start); + for stmt in &f.body { + self.visit_stmt(stmt); + } + + self.type_eval.symbol_table.revert_scope(); + } + ast::Statement::ClassDef(c) => { + self.type_eval.symbol_table.set_scope(c.node.start); + for stmt in &c.body { + self.visit_stmt(stmt); + } + self.type_eval.symbol_table.revert_scope(); + } + ast::Statement::Match(m) => (), + Statement::AsyncForStatement(f) => (), + Statement::AsyncWithStatement(w) => (), + Statement::AsyncFunctionDef(f) => { + self.type_eval.symbol_table.set_scope(f.node.start); + for stmt in &f.body { + self.visit_stmt(stmt); + } + self.type_eval.symbol_table.revert_scope(); + } + Statement::TypeAlias(a) => (), + } + } + + fn visit_expr(&mut self, e: &ast::Expression) { + match e { + ast::Expression::Constant(c) => (), + ast::Expression::List(l) => (), + ast::Expression::Tuple(t) => (), + ast::Expression::Dict(d) => (), + ast::Expression::Set(s) => (), + ast::Expression::Name(n) => self.save_type(e), + ast::Expression::BoolOp(b) => (), + ast::Expression::UnaryOp(u) => (), + ast::Expression::BinOp(b) => { + self.save_type(&b.left); + self.save_type(&b.right); + } + ast::Expression::NamedExpr(n) => (), + ast::Expression::Yield(y) => (), + ast::Expression::YieldFrom(y) => (), + ast::Expression::Starred(s) => (), + ast::Expression::Generator(g) => (), + ast::Expression::ListComp(l) => (), + ast::Expression::SetComp(s) => (), + ast::Expression::DictComp(d) => (), + ast::Expression::Attribute(a) => {} + ast::Expression::Subscript(s) => (), + ast::Expression::Slice(s) => (), + ast::Expression::Call(c) => { + self.save_type(e); + for arg in &c.args { + self.save_type(arg); + } + } + ast::Expression::Await(a) => (), + ast::Expression::Compare(c) => (), + ast::Expression::Lambda(l) => (), + ast::Expression::IfExp(i) => (), + ast::Expression::JoinedStr(j) => (), + ast::Expression::FormattedValue(f) => (), + } + } +} + +#[cfg(test)] +mod tests { + use std::{fs, path::PathBuf}; + + use insta::glob; + + use super::*; + use crate::{build::BuildManager, build_source::BuildSource, settings::Settings}; + + fn snapshot_type_eval(source: &str) -> String { + use enderpy_python_parser::Parser; + + let mut parser = Parser::new(source.to_string(), "".into()); + let ast_module = parser.parse(); + let build_source = BuildSource { + path: PathBuf::from("test-file"), + source: source.to_string(), + module: "test".to_string(), + followed: false, + }; + + // we use the manager to also import the python typeshed into modules + // This can be refactored but for now it's fine + let mut manager = BuildManager::new(vec![build_source], Settings::test_settings()); + manager.build(); + + let mut all_symbol_tables = Vec::new(); + for module in manager.modules.values() { + all_symbol_tables.push(module.get_symbol_table()); + } + + let module = manager.get_state("test-file".into()).unwrap(); + let symbol_table = module.get_symbol_table(); + + let type_eval = TypeEvaluator { + symbol_table, + imported_symbol_tables: all_symbol_tables, + }; + + let mut type_eval_visitor = DumpTypes::new(module.clone(), type_eval); + type_eval_visitor.visit_module(); + + let result = type_eval_visitor.types; + + // sort result by key + let mut result_sorted = result.clone().into_iter().collect::>(); + result_sorted.sort_by(|a, b| a.position.line.cmp(&b.position.line)); + + let mut str = String::new(); + let mut last_line = 0; + + for r in result_sorted { + let line = r.position.line; + if line > last_line { + if last_line != 0 { + str.push_str("\n---\n"); + } + let line_content = module.get_line_content(line); + str.push_str(format!("Line {}: {}\n", line, line_content).as_str()); + str.push_str("\nExpr types in the line --->:\n"); + last_line = line; + } + str.push_str(&format!(" {:?} => {:?}\n", r.symbol_text, r.typ)); + } + str.push_str("\n---\n"); + + str + } + + #[test] + fn test_type_evaluator() { + glob!("../../test_data/inputs/", "*.py", |path| { + // TODO: temporary only run the base test + if !path.to_str().unwrap().contains("base") { + return; + } + let _ = env_logger::builder() + .filter_level(log::LevelFilter::Debug) + .is_test(true) + .try_init(); + let contents = fs::read_to_string(path).unwrap(); + let result = snapshot_type_eval(&contents); + + let mut content_with_line_numbers = String::new(); + for (i, line) in contents.lines().enumerate() { + content_with_line_numbers.push_str(&format!("{}: {}\n", i + 1, line)); + } + + // TODO move this redaction setting to a central place + let mut settings = insta::Settings::clone_current(); + settings.add_filter(r"module_name: .*.typeshed.", "module_name: [TYPESHED]."); + settings.set_snapshot_path("../../test_data/output/"); + settings.set_description(content_with_line_numbers); + // TODO CLEAN THE classes name + settings.bind(|| { + insta::assert_snapshot!(result); + }); + }) + } +} diff --git a/typechecker/src/type_check/type_evaluator.rs b/typechecker/src/type_check/type_evaluator.rs index ba700d7a..ba84d199 100755 --- a/typechecker/src/type_check/type_evaluator.rs +++ b/typechecker/src/type_check/type_evaluator.rs @@ -2,7 +2,7 @@ #![allow(unused_variables)] use core::panic; -use std::{path::Path}; +use std::path::Path; use enderpy_python_parser as parser; use enderpy_python_parser::ast; @@ -239,15 +239,10 @@ impl TypeEvaluator { return Ok(PythonType::Unknown); } }; - log::debug!("checking type for expression: {:#?}", a); log::debug!("looking up attribute in type: {:?}", value_type); match value_type { PythonType::Class(c) => { - let class_scope = self - .symbol_table - .get_scope(&c.details.declaration_path.node) - .expect("cannot find class scope for attribute access"); - + let class_scope = self.get_scope_of(&c); log::debug!("class scope for the attribute: {:#?}", class_scope); let symbol_table_node = self.symbol_table.lookup_attribute(&a.attr, class_scope); @@ -878,6 +873,26 @@ impl TypeEvaluator { .find(|symbol_table| symbol_table.file_path == path); symbol_table } + + fn get_scope_of(&self, c: &ClassType) -> &symbol_table::SymbolTableScope { + let symbol_table = self + .imported_symbol_tables + .iter() + .find(|symbol_table| { + symbol_table + .file_path + .ends_with(&c.details.declaration_path.module_name) + }) + .unwrap_or_else(|| { + panic!( + "Declaration path not found: {:?}", + c.details.declaration_path, + ) + }); + symbol_table + .get_scope(&c.details.declaration_path.node) + .unwrap_or_else(|| panic!("Scope not found for: {:?}", c.details.declaration_path)) + } } impl TraversalVisitorImmutGeneric for TypeEvaluator { diff --git a/typechecker/test_data/inputs/base.py b/typechecker/test_data/inputs/base.py index 7a1415eb..afd11f65 100644 --- a/typechecker/test_data/inputs/base.py +++ b/typechecker/test_data/inputs/base.py @@ -38,3 +38,5 @@ def get_x(self) -> float: d = {"a": 1, "b": 2} s = {1,2,3} +l.append(4) + diff --git a/typechecker/test_data/output/enderpy_python_type_checker__build__tests__symbol_table@class_definition.py.snap b/typechecker/test_data/output/enderpy_python_type_checker__build__tests__symbol_table@class_definition.py.snap index f900668b..01530090 100644 --- a/typechecker/test_data/output/enderpy_python_type_checker__build__tests__symbol_table@class_definition.py.snap +++ b/typechecker/test_data/output/enderpy_python_type_checker__build__tests__symbol_table@class_definition.py.snap @@ -269,7 +269,7 @@ SymbolFlags( --: Class { name: "c", declaration_path: DeclarationPath { - module_name: "", + module_name: "[TYPECHECKER]/test_data/inputs/symbol_table/class_definition.py", node: Node { start: 0, end: 80, diff --git a/typechecker/test_data/output/enderpy_python_type_checker__type_check__type_evaluator__tests__type_evaluator@base.py.snap b/typechecker/test_data/output/enderpy_python_type_checker__type_check__type_evaluator__tests__type_evaluator@base.py.snap index d8f16077..29cdea92 100644 --- a/typechecker/test_data/output/enderpy_python_type_checker__type_check__type_evaluator__tests__type_evaluator@base.py.snap +++ b/typechecker/test_data/output/enderpy_python_type_checker__type_check__type_evaluator__tests__type_evaluator@base.py.snap @@ -1,134 +1,141 @@ --- source: typechecker/src/type_check/type_evaluator.rs -description: "1: a = 1\n2: b = \"1\"\n3: c = True\n4: d = False\n5: a + int(b)\n6: \n7: \n8: a + c\n9: \n10: def func(param1: int) -> int:\n11: \treturn param1 + a\n12: \n13: class C:\n14: \tcls_attribute = 1\n15: \n16: \tdef __init__(self, x: int):\n17: \t\tprint(self.cls_attribute)\n18: \t\tself.x = float(x)\n19: \t\tprint(self.x)\n20: \n21: \tdef add(self, value: int):\n22: \t\tself.cls_attribute += value\n23: \n24: \tdef get_attr(self) -> int:\n25: \t\treturn self.cls_attribute\n26: \n27: \tdef\tget_x(self) -> float:\n28: \t\treturn self.x\n29: \n30: t = C(0)\n31: t.add(2)\n32: t.cls_attribute\n33: t.x\n34: t.get_x()\n35: t.get_attr()\n36: \n37: l = [1,2,3]\n38: d = {\"a\": 1, \"b\": 2}\n39: s = {1,2,3}\n40: \n41: # l.append(1)\n" +description: "1: a = 1\n2: b = \"1\"\n3: c = True\n4: d = False\n5: a + int(b)\n6: \n7: \n8: a + c\n9: \n10: def func(param1: int) -> int:\n11: \treturn param1 + a\n12: \n13: class C:\n14: \tcls_attribute = 1\n15: \n16: \tdef __init__(self, x: int):\n17: \t\tprint(self.cls_attribute)\n18: \t\tself.x = float(x)\n19: \t\tprint(self.x)\n20: \n21: \tdef add(self, value: int):\n22: \t\tself.cls_attribute += value\n23: \n24: \tdef get_attr(self) -> int:\n25: \t\treturn self.cls_attribute\n26: \n27: \tdef\tget_x(self) -> float:\n28: \t\treturn self.x\n29: \n30: t = C(0)\n31: t.add(2)\n32: t.cls_attribute\n33: t.x\n34: t.get_x()\n35: t.get_attr()\n36: \n37: l = [1,2,3]\n38: d = {\"a\": 1, \"b\": 2}\n39: s = {1,2,3}\n40: \n41: l.append(4)\n42: \n" expression: result input_file: typechecker/test_data/inputs/base.py --- Line 1: a = 1 Expr types in the line --->: - "1" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) + "1" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) --- Line 2: b = "1" Expr types in the line --->: - "\"1\"" => Class(ClassType { details: Class { name: "str", declaration_path: DeclarationPath { module_name: "", node: Node { start: 17176, end: 25985 } }, methods: ["__new__", "__new__", "capitalize", "capitalize", "casefold", "casefold", "center", "center", "count", "encode", "endswith", "find", "format", "format", "format_map", "index", "isalnum", "isalpha", "isascii", "isdecimal", "isdigit", "isidentifier", "islower", "isnumeric", "isprintable", "isspace", "istitle", "isupper", "join", "join", "ljust", "ljust", "lower", "lower", "lstrip", "lstrip", "partition", "partition", "replace", "replace", "rfind", "rindex", "rjust", "rjust", "rpartition", "rpartition", "rsplit", "rsplit", "rstrip", "rstrip", "split", "split", "splitlines", "splitlines", "startswith", "strip", "strip", "swapcase", "swapcase", "title", "title", "translate", "upper", "upper", "zfill", "zfill", "maketrans", "maketrans", "maketrans", "__add__", "__add__", "__contains__", "__eq__", "__ge__", "__getitem__", "__gt__", "__hash__", "__iter__", "__iter__", "__le__", "__len__", "__lt__", "__mod__", "__mod__", "__mul__", "__mul__", "__ne__", "__rmul__", "__rmul__", "__getnewargs__"], special: false }, type_parameters: [] }) + "\"1\"" => Class(ClassType { details: Class { name: "str", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 17176, end: 25985 } }, methods: ["__new__", "__new__", "capitalize", "capitalize", "casefold", "casefold", "center", "center", "count", "encode", "endswith", "find", "format", "format", "format_map", "index", "isalnum", "isalpha", "isascii", "isdecimal", "isdigit", "isidentifier", "islower", "isnumeric", "isprintable", "isspace", "istitle", "isupper", "join", "join", "ljust", "ljust", "lower", "lower", "lstrip", "lstrip", "partition", "partition", "replace", "replace", "rfind", "rindex", "rjust", "rjust", "rpartition", "rpartition", "rsplit", "rsplit", "rstrip", "rstrip", "split", "split", "splitlines", "splitlines", "startswith", "strip", "strip", "swapcase", "swapcase", "title", "title", "translate", "upper", "upper", "zfill", "zfill", "maketrans", "maketrans", "maketrans", "__add__", "__add__", "__contains__", "__eq__", "__ge__", "__getitem__", "__gt__", "__hash__", "__iter__", "__iter__", "__le__", "__len__", "__lt__", "__mod__", "__mod__", "__mul__", "__mul__", "__ne__", "__rmul__", "__rmul__", "__getnewargs__"], special: false }, type_parameters: [] }) --- Line 3: c = True Expr types in the line --->: - "True" => Class(ClassType { details: Class { name: "bool", declaration_path: DeclarationPath { module_name: "", node: Node { start: 39629, end: 40711 } }, methods: ["__new__", "__and__", "__and__", "__or__", "__or__", "__xor__", "__xor__", "__rand__", "__rand__", "__ror__", "__ror__", "__rxor__", "__rxor__", "__getnewargs__"], special: false }, type_parameters: [] }) + "True" => Class(ClassType { details: Class { name: "bool", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 39629, end: 40711 } }, methods: ["__new__", "__and__", "__and__", "__or__", "__or__", "__xor__", "__xor__", "__rand__", "__rand__", "__ror__", "__ror__", "__rxor__", "__rxor__", "__getnewargs__"], special: false }, type_parameters: [] }) --- Line 4: d = False Expr types in the line --->: - "False" => Class(ClassType { details: Class { name: "bool", declaration_path: DeclarationPath { module_name: "", node: Node { start: 39629, end: 40711 } }, methods: ["__new__", "__and__", "__and__", "__or__", "__or__", "__xor__", "__xor__", "__rand__", "__rand__", "__ror__", "__ror__", "__rxor__", "__rxor__", "__getnewargs__"], special: false }, type_parameters: [] }) + "False" => Class(ClassType { details: Class { name: "bool", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 39629, end: 40711 } }, methods: ["__new__", "__and__", "__and__", "__or__", "__or__", "__xor__", "__xor__", "__rand__", "__rand__", "__ror__", "__ror__", "__rxor__", "__rxor__", "__getnewargs__"], special: false }, type_parameters: [] }) --- Line 5: a + int(b) Expr types in the line --->: - "a" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) - "int(b)" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) + "a" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) + "int(b)" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) --- Line 8: a + c Expr types in the line --->: - "a" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) - "c" => Class(ClassType { details: Class { name: "bool", declaration_path: DeclarationPath { module_name: "", node: Node { start: 39629, end: 40711 } }, methods: ["__new__", "__and__", "__and__", "__or__", "__or__", "__xor__", "__xor__", "__rand__", "__rand__", "__ror__", "__ror__", "__rxor__", "__rxor__", "__getnewargs__"], special: false }, type_parameters: [] }) + "a" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) + "c" => Class(ClassType { details: Class { name: "bool", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 39629, end: 40711 } }, methods: ["__new__", "__and__", "__and__", "__or__", "__or__", "__xor__", "__xor__", "__rand__", "__rand__", "__ror__", "__ror__", "__rxor__", "__rxor__", "__getnewargs__"], special: false }, type_parameters: [] }) --- Line 11: return param1 + a Expr types in the line --->: - "param1" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) - "a" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) - "param1 + a" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) + "param1" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) + "a" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) + "param1 + a" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) --- Line 14: cls_attribute = 1 Expr types in the line --->: - "1" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) + "1" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) --- Line 17: print(self.cls_attribute) Expr types in the line --->: "print(self.cls_attribute)" => Callable(CallableType { name: "print", arguments: Arguments { node: Node { start: 69542, end: 69692 }, posonlyargs: [], args: [], vararg: Some(Arg { node: Node { start: 69543, end: 69557 }, arg: "values", annotation: Some(Name(Name { node: Node { start: 69551, end: 69557 }, id: "object" })) }), kwonlyargs: [Arg { node: Node { start: 69563, end: 69584 }, arg: "sep", annotation: Some(BinOp(BinOp { node: Node { start: 69568, end: 69578 }, op: BitOr, left: Name(Name { node: Node { start: 69568, end: 69571 }, id: "str" }), right: Constant(Constant { node: Node { start: 69574, end: 69578 }, value: None }) })) }, Arg { node: Node { start: 69590, end: 69612 }, arg: "end", annotation: Some(BinOp(BinOp { node: Node { start: 69595, end: 69605 }, op: BitOr, left: Name(Name { node: Node { start: 69595, end: 69598 }, id: "str" }), right: Constant(Constant { node: Node { start: 69601, end: 69605 }, value: None }) })) }, Arg { node: Node { start: 69618, end: 69656 }, arg: "file", annotation: Some(BinOp(BinOp { node: Node { start: 69624, end: 69649 }, op: BitOr, left: Subscript(Subscript { node: Node { start: 69624, end: 69642 }, value: Name(Name { node: Node { start: 69624, end: 69637 }, id: "SupportsWrite" }), slice: Name(Name { node: Node { start: 69638, end: 69641 }, id: "str" }) }), right: Constant(Constant { node: Node { start: 69645, end: 69649 }, value: None }) })) }, Arg { node: Node { start: 69662, end: 69691 }, arg: "flush", annotation: Some(Subscript(Subscript { node: Node { start: 69669, end: 69683 }, value: Name(Name { node: Node { start: 69669, end: 69676 }, id: "Literal" }), slice: Constant(Constant { node: Node { start: 69677, end: 69682 }, value: false }) })) }], kw_defaults: [Some(Constant(Constant { node: Node { start: 69581, end: 69584 }, value: " " })), Some(Constant(Constant { node: Node { start: 69608, end: 69612 }, value: "\n" })), Some(Constant(Constant { node: Node { start: 69652, end: 69656 }, value: None })), Some(Constant(Constant { node: Node { start: 69686, end: 69691 }, value: false }))], kwarg: None, defaults: [] }, return_type: None }) - "self.cls_attribute" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) + "self.cls_attribute" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) --- Line 18: self.x = float(x) Expr types in the line --->: - "float(x)" => Class(ClassType { details: Class { name: "float", declaration_path: DeclarationPath { module_name: "", node: Node { start: 12343, end: 15122 } }, methods: ["__new__", "as_integer_ratio", "hex", "is_integer", "fromhex", "real", "imag", "conjugate", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__pow__", "__pow__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__rpow__", "__rpow__", "__rpow__", "__getnewargs__", "__trunc__", "__round__", "__round__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__neg__", "__pos__", "__int__", "__float__", "__abs__", "__hash__", "__bool__"], special: false }, type_parameters: [] }) + "float(x)" => Class(ClassType { details: Class { name: "float", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 12343, end: 15122 } }, methods: ["__new__", "as_integer_ratio", "hex", "is_integer", "fromhex", "real", "imag", "conjugate", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__pow__", "__pow__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__rpow__", "__rpow__", "__rpow__", "__getnewargs__", "__trunc__", "__round__", "__round__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__neg__", "__pos__", "__int__", "__float__", "__abs__", "__hash__", "__bool__"], special: false }, type_parameters: [] }) --- Line 19: print(self.x) Expr types in the line --->: "print(self.x)" => Callable(CallableType { name: "print", arguments: Arguments { node: Node { start: 69542, end: 69692 }, posonlyargs: [], args: [], vararg: Some(Arg { node: Node { start: 69543, end: 69557 }, arg: "values", annotation: Some(Name(Name { node: Node { start: 69551, end: 69557 }, id: "object" })) }), kwonlyargs: [Arg { node: Node { start: 69563, end: 69584 }, arg: "sep", annotation: Some(BinOp(BinOp { node: Node { start: 69568, end: 69578 }, op: BitOr, left: Name(Name { node: Node { start: 69568, end: 69571 }, id: "str" }), right: Constant(Constant { node: Node { start: 69574, end: 69578 }, value: None }) })) }, Arg { node: Node { start: 69590, end: 69612 }, arg: "end", annotation: Some(BinOp(BinOp { node: Node { start: 69595, end: 69605 }, op: BitOr, left: Name(Name { node: Node { start: 69595, end: 69598 }, id: "str" }), right: Constant(Constant { node: Node { start: 69601, end: 69605 }, value: None }) })) }, Arg { node: Node { start: 69618, end: 69656 }, arg: "file", annotation: Some(BinOp(BinOp { node: Node { start: 69624, end: 69649 }, op: BitOr, left: Subscript(Subscript { node: Node { start: 69624, end: 69642 }, value: Name(Name { node: Node { start: 69624, end: 69637 }, id: "SupportsWrite" }), slice: Name(Name { node: Node { start: 69638, end: 69641 }, id: "str" }) }), right: Constant(Constant { node: Node { start: 69645, end: 69649 }, value: None }) })) }, Arg { node: Node { start: 69662, end: 69691 }, arg: "flush", annotation: Some(Subscript(Subscript { node: Node { start: 69669, end: 69683 }, value: Name(Name { node: Node { start: 69669, end: 69676 }, id: "Literal" }), slice: Constant(Constant { node: Node { start: 69677, end: 69682 }, value: false }) })) }], kw_defaults: [Some(Constant(Constant { node: Node { start: 69581, end: 69584 }, value: " " })), Some(Constant(Constant { node: Node { start: 69608, end: 69612 }, value: "\n" })), Some(Constant(Constant { node: Node { start: 69652, end: 69656 }, value: None })), Some(Constant(Constant { node: Node { start: 69686, end: 69691 }, value: false }))], kwarg: None, defaults: [] }, return_type: None }) - "self.x" => Class(ClassType { details: Class { name: "float", declaration_path: DeclarationPath { module_name: "", node: Node { start: 12343, end: 15122 } }, methods: ["__new__", "as_integer_ratio", "hex", "is_integer", "fromhex", "real", "imag", "conjugate", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__pow__", "__pow__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__rpow__", "__rpow__", "__rpow__", "__getnewargs__", "__trunc__", "__round__", "__round__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__neg__", "__pos__", "__int__", "__float__", "__abs__", "__hash__", "__bool__"], special: false }, type_parameters: [] }) + "self.x" => Class(ClassType { details: Class { name: "float", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 12343, end: 15122 } }, methods: ["__new__", "as_integer_ratio", "hex", "is_integer", "fromhex", "real", "imag", "conjugate", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__pow__", "__pow__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__rpow__", "__rpow__", "__rpow__", "__getnewargs__", "__trunc__", "__round__", "__round__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__neg__", "__pos__", "__int__", "__float__", "__abs__", "__hash__", "__bool__"], special: false }, type_parameters: [] }) --- Line 25: return self.cls_attribute Expr types in the line --->: - "self.cls_attribute" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) + "self.cls_attribute" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) --- Line 28: return self.x Expr types in the line --->: - "self.x" => Class(ClassType { details: Class { name: "float", declaration_path: DeclarationPath { module_name: "", node: Node { start: 12343, end: 15122 } }, methods: ["__new__", "as_integer_ratio", "hex", "is_integer", "fromhex", "real", "imag", "conjugate", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__pow__", "__pow__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__rpow__", "__rpow__", "__rpow__", "__getnewargs__", "__trunc__", "__round__", "__round__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__neg__", "__pos__", "__int__", "__float__", "__abs__", "__hash__", "__bool__"], special: false }, type_parameters: [] }) + "self.x" => Class(ClassType { details: Class { name: "float", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 12343, end: 15122 } }, methods: ["__new__", "as_integer_ratio", "hex", "is_integer", "fromhex", "real", "imag", "conjugate", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__pow__", "__pow__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__rpow__", "__rpow__", "__rpow__", "__getnewargs__", "__trunc__", "__round__", "__round__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__neg__", "__pos__", "__int__", "__float__", "__abs__", "__hash__", "__bool__"], special: false }, type_parameters: [] }) --- Line 30: t = C(0) Expr types in the line --->: - "C(0)" => Class(ClassType { details: Class { name: "C", declaration_path: DeclarationPath { module_name: "", node: Node { start: 103, end: 386 } }, methods: ["__init__", "add", "get_attr", "get_x"], special: false }, type_parameters: [] }) + "C(0)" => Class(ClassType { details: Class { name: "C", declaration_path: DeclarationPath { module_name: "test-file", node: Node { start: 103, end: 386 } }, methods: ["__init__", "add", "get_attr", "get_x"], special: false }, type_parameters: [] }) --- Line 31: t.add(2) Expr types in the line --->: "(2)" => Callable(CallableType { name: "add", arguments: Arguments { node: Node { start: 235, end: 251 }, posonlyargs: [], args: [Arg { node: Node { start: 235, end: 239 }, arg: "self", annotation: None }, Arg { node: Node { start: 241, end: 251 }, arg: "value", annotation: Some(Name(Name { node: Node { start: 248, end: 251 }, id: "int" })) }], vararg: None, kwonlyargs: [], kw_defaults: [], kwarg: None, defaults: [] }, return_type: None }) - "2" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) + "2" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) --- Line 34: t.get_x() Expr types in the line --->: - "()" => Callable(CallableType { name: "get_x", arguments: Arguments { node: Node { start: 353, end: 357 }, posonlyargs: [], args: [Arg { node: Node { start: 353, end: 357 }, arg: "self", annotation: None }], vararg: None, kwonlyargs: [], kw_defaults: [], kwarg: None, defaults: [] }, return_type: Class(ClassType { details: Class { name: "float", declaration_path: DeclarationPath { module_name: "", node: Node { start: 12343, end: 15122 } }, methods: ["__new__", "as_integer_ratio", "hex", "is_integer", "fromhex", "real", "imag", "conjugate", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__pow__", "__pow__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__rpow__", "__rpow__", "__rpow__", "__getnewargs__", "__trunc__", "__round__", "__round__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__neg__", "__pos__", "__int__", "__float__", "__abs__", "__hash__", "__bool__"], special: false }, type_parameters: [] }) }) + "()" => Callable(CallableType { name: "get_x", arguments: Arguments { node: Node { start: 353, end: 357 }, posonlyargs: [], args: [Arg { node: Node { start: 353, end: 357 }, arg: "self", annotation: None }], vararg: None, kwonlyargs: [], kw_defaults: [], kwarg: None, defaults: [] }, return_type: Class(ClassType { details: Class { name: "float", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 12343, end: 15122 } }, methods: ["__new__", "as_integer_ratio", "hex", "is_integer", "fromhex", "real", "imag", "conjugate", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__pow__", "__pow__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__rpow__", "__rpow__", "__rpow__", "__getnewargs__", "__trunc__", "__round__", "__round__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__neg__", "__pos__", "__int__", "__float__", "__abs__", "__hash__", "__bool__"], special: false }, type_parameters: [] }) }) --- Line 35: t.get_attr() Expr types in the line --->: - "()" => Callable(CallableType { name: "get_attr", arguments: Arguments { node: Node { start: 299, end: 303 }, posonlyargs: [], args: [Arg { node: Node { start: 299, end: 303 }, arg: "self", annotation: None }], vararg: None, kwonlyargs: [], kw_defaults: [], kwarg: None, defaults: [] }, return_type: Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) }) + "()" => Callable(CallableType { name: "get_attr", arguments: Arguments { node: Node { start: 299, end: 303 }, posonlyargs: [], args: [Arg { node: Node { start: 299, end: 303 }, arg: "self", annotation: None }], vararg: None, kwonlyargs: [], kw_defaults: [], kwarg: None, defaults: [] }, return_type: Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) }) --- Line 37: l = [1,2,3] Expr types in the line --->: - "[1,2,3]" => Class(ClassType { details: Class { name: "list", declaration_path: DeclarationPath { module_name: "", node: Node { start: 43505, end: 46298 } }, methods: ["__init__", "__init__", "copy", "append", "extend", "pop", "index", "count", "insert", "remove", "sort", "sort", "__len__", "__iter__", "__getitem__", "__getitem__", "__setitem__", "__setitem__", "__delitem__", "__add__", "__add__", "__iadd__", "__mul__", "__rmul__", "__imul__", "__contains__", "__reversed__", "__gt__", "__ge__", "__lt__", "__le__", "__eq__"], special: false }, type_parameters: [Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] })] }) + "[1,2,3]" => Class(ClassType { details: Class { name: "list", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] })] }) --- Line 38: d = {"a": 1, "b": 2} Expr types in the line --->: - "{\"a\": 1, \"b\": 2}" => Class(ClassType { details: Class { name: "dict", declaration_path: DeclarationPath { module_name: "", node: Node { start: 46298, end: 49982 } }, methods: ["__init__", "__init__", "__init__", "__init__", "__init__", "__init__", "__init__", "__init__", "__new__", "copy", "keys", "values", "items", "fromkeys", "fromkeys", "get", "get", "get", "pop", "pop", "pop", "__len__", "__getitem__", "__setitem__", "__delitem__", "__iter__", "__eq__"], special: false }, type_parameters: [Class(ClassType { details: Class { name: "str", declaration_path: DeclarationPath { module_name: "", node: Node { start: 17176, end: 25985 } }, methods: ["__new__", "__new__", "capitalize", "capitalize", "casefold", "casefold", "center", "center", "count", "encode", "endswith", "find", "format", "format", "format_map", "index", "isalnum", "isalpha", "isascii", "isdecimal", "isdigit", "isidentifier", "islower", "isnumeric", "isprintable", "isspace", "istitle", "isupper", "join", "join", "ljust", "ljust", "lower", "lower", "lstrip", "lstrip", "partition", "partition", "replace", "replace", "rfind", "rindex", "rjust", "rjust", "rpartition", "rpartition", "rsplit", "rsplit", "rstrip", "rstrip", "split", "split", "splitlines", "splitlines", "startswith", "strip", "strip", "swapcase", "swapcase", "title", "title", "translate", "upper", "upper", "zfill", "zfill", "maketrans", "maketrans", "maketrans", "__add__", "__add__", "__contains__", "__eq__", "__ge__", "__getitem__", "__gt__", "__hash__", "__iter__", "__iter__", "__le__", "__len__", "__lt__", "__mod__", "__mod__", "__mul__", "__mul__", "__ne__", "__rmul__", "__rmul__", "__getnewargs__"], special: false }, type_parameters: [] }), Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] })] }) + "{\"a\": 1, \"b\": 2}" => Class(ClassType { details: Class { name: "dict", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] })] }) --- Line 39: s = {1,2,3} Expr types in the line --->: - "{1,2,3}" => Class(ClassType { details: Class { name: "set", declaration_path: DeclarationPath { module_name: "", node: Node { start: 49982, end: 52187 } }, methods: ["__init__", "__init__", "add", "copy", "difference", "difference_update", "discard", "intersection", "intersection_update", "isdisjoint", "issubset", "issuperset", "remove", "symmetric_difference", "symmetric_difference_update", "union", "update", "__len__", "__contains__", "__iter__", "__and__", "__iand__", "__or__", "__ior__", "__sub__", "__isub__", "__xor__", "__ixor__", "__le__", "__lt__", "__ge__", "__gt__", "__eq__"], special: false }, type_parameters: [Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: "", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] })] }) + "{1,2,3}" => Class(ClassType { details: Class { name: "set", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] })] }) + +--- +Line 41: l.append(4) + +Expr types in the line --->: + "(4)" => Callable(CallableType { name: "append", arguments: Arguments { node: Node { start: 43715, end: 43733 }, posonlyargs: [], args: [Arg { node: Node { start: 43715, end: 43719 }, arg: "self", annotation: None }, Arg { node: Node { start: 43721, end: 43733 }, arg: "__object", annotation: Some(Name(Name { node: Node { start: 43731, end: 43733 }, id: "_T" })) }], vararg: None, kwonlyargs: [], kw_defaults: [], kwarg: None, defaults: [] }, return_type: None }) + "4" => Class(ClassType { details: Class { name: "int", declaration_path: DeclarationPath { module_name: [TYPESHED].stdlib/builtins.pyi", node: Node { start: 7961, end: 12343 } }, methods: ["__new__", "__new__", "real", "imag", "numerator", "denominator", "conjugate", "bit_length", "__add__", "__sub__", "__mul__", "__floordiv__", "__truediv__", "__mod__", "__divmod__", "__radd__", "__rsub__", "__rmul__", "__rfloordiv__", "__rtruediv__", "__rmod__", "__rdivmod__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__pow__", "__rpow__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__neg__", "__pos__", "__invert__", "__trunc__", "__ceil__", "__floor__", "__round__", "__getnewargs__", "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", "__float__", "__int__", "__abs__", "__hash__", "__bool__", "__index__"], special: false }, type_parameters: [] }) ---