WIP on name-analysis gather, up to statements.
This commit is contained in:
		
							parent
							
								
									d5ac6dfc2d
								
							
						
					
					
						commit
						3ab59961dd
					
				| @ -1,6 +1,36 @@ | |||||||
| pub mod node { | pub mod node { | ||||||
|     include!(concat!(env!("OUT_DIR"), "/src/ast/node.rs")); |     include!(concat!(env!("OUT_DIR"), "/src/ast/node.rs")); | ||||||
| 
 | 
 | ||||||
|  |     impl OperatorInner { | ||||||
|  |         pub fn name(&self) -> &'static str { | ||||||
|  |             match self { | ||||||
|  |                 OperatorInner::Or => "op_or", | ||||||
|  |                 OperatorInner::And => "op_and", | ||||||
|  |                 OperatorInner::EqualTo => "op_eq", | ||||||
|  |                 OperatorInner::NotEqualTo => "op_neq", | ||||||
|  |                 OperatorInner::Greater => "op_gt", | ||||||
|  |                 OperatorInner::Less => "op_lt", | ||||||
|  |                 OperatorInner::GreaterEqual => "op_ge", | ||||||
|  |                 OperatorInner::LessEqual => "op_le", | ||||||
|  |                 OperatorInner::Add => "op_add", | ||||||
|  |                 OperatorInner::Subtract => "op_sub", | ||||||
|  |                 OperatorInner::Multiply => "op_mul", | ||||||
|  |                 OperatorInner::Divide => "op_div", | ||||||
|  |                 OperatorInner::Modulo => "op_mod", | ||||||
|  |                 OperatorInner::LeftShift => "op_ls", | ||||||
|  |                 OperatorInner::RightShift => "op_rs", | ||||||
|  |                 OperatorInner::Spread => "op_spread", | ||||||
|  |                 OperatorInner::Star => "op_star", | ||||||
|  |                 OperatorInner::Not => "op_not", | ||||||
|  |                 OperatorInner::Negative => "op_neg", | ||||||
|  |                 OperatorInner::PlusPlus => "op_pp", | ||||||
|  |                 OperatorInner::MinusMinus => "op_mm", | ||||||
|  |                 OperatorInner::CallOp => "op_call", | ||||||
|  |                 OperatorInner::Index => "op_index", | ||||||
|  |             } | ||||||
|  |         }    
 | ||||||
|  |     } | ||||||
|  |     
 | ||||||
|     impl Default for Parameters { |     impl Default for Parameters { | ||||||
|         fn default() -> Self { |         fn default() -> Self { | ||||||
|             Self::new(vec![]) |             Self::new(vec![]) | ||||||
|  | |||||||
| @ -1,10 +1,13 @@ | |||||||
| use crate::ast::ast_node::{AstNode, AstNodeRef}; | use crate::ast::ast_node::{AstNode, AstNodeRef}; | ||||||
| use crate::ast::node::{ | use crate::ast::node::{ | ||||||
|     Class, CompilationUnit, Function, FunctionBlockBody, FunctionBody, Identifier, Interface, |     Class, CompilationUnit, Function, FunctionBody, Identifier, Interface, | ||||||
|     Module, Namespace, Statement, UseStatement, UseStatementSuffix, VariableDeclaration, |     InterfaceDefaultFunction, InterfaceDefaultOperatorFunction, InterfaceFunction, | ||||||
|  |     InterfaceOperatorFunction, Member, Module, Namespace, OperatorFunction, PlatformFunction, | ||||||
|  |     PlatformOperatorFunction, Statement, UseStatement, UseStatementSuffix, VariableDeclaration, | ||||||
| }; | }; | ||||||
| use crate::diagnostic::DmDiagnostic; | use crate::diagnostic::DmDiagnostic; | ||||||
| use crate::name_analysis::fqn_context::FqnContext; | use crate::name_analysis::fqn_context::FqnContext; | ||||||
|  | use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol; | ||||||
| use crate::name_analysis::symbol::function_symbol::FunctionSymbol; | use crate::name_analysis::symbol::function_symbol::FunctionSymbol; | ||||||
| use crate::name_analysis::symbol::module_symbol::ModuleSymbol; | use crate::name_analysis::symbol::module_symbol::ModuleSymbol; | ||||||
| use crate::name_analysis::symbol::source_definition::SourceDefinition; | use crate::name_analysis::symbol::source_definition::SourceDefinition; | ||||||
| @ -67,9 +70,14 @@ fn gather_node( | |||||||
|     diagnostics: &mut Vec<DmDiagnostic>, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     match node { |     match node { | ||||||
|         AstNodeRef::Operator(_) => {} |         AstNodeRef::Operator(_) => { | ||||||
|  |             unreachable!(); | ||||||
|  |         } | ||||||
|  |         AstNodeRef::OperatorInner(_) => { | ||||||
|  |             unreachable!(); | ||||||
|  |         } | ||||||
|         AstNodeRef::Identifier(_) => { |         AstNodeRef::Identifier(_) => { | ||||||
|             unreachable!() |             unreachable!(); | ||||||
|         } |         } | ||||||
|         AstNodeRef::FullyQualifiedName(_) => {} |         AstNodeRef::FullyQualifiedName(_) => {} | ||||||
|         AstNodeRef::TypeUseList(_) => {} |         AstNodeRef::TypeUseList(_) => {} | ||||||
| @ -98,13 +106,13 @@ fn gather_node( | |||||||
|             gather_use_statement(use_statement, symbol_table, diagnostics); |             gather_use_statement(use_statement, symbol_table, diagnostics); | ||||||
|         } |         } | ||||||
|         AstNodeRef::UseStatementPrefix(_) => { |         AstNodeRef::UseStatementPrefix(_) => { | ||||||
|             unreachable!() |             unreachable!(); | ||||||
|         } |         } | ||||||
|         AstNodeRef::UseStatementSuffix(_) => { |         AstNodeRef::UseStatementSuffix(_) => { | ||||||
|             unreachable!() |             unreachable!(); | ||||||
|         } |         } | ||||||
|         AstNodeRef::UseList(_) => { |         AstNodeRef::UseList(_) => { | ||||||
|             unreachable!() |             unreachable!(); | ||||||
|         } |         } | ||||||
|         AstNodeRef::ModuleLevelDeclaration(module_level_declaration) => { |         AstNodeRef::ModuleLevelDeclaration(module_level_declaration) => { | ||||||
|             gather_node_children( |             gather_node_children( | ||||||
| @ -142,45 +150,65 @@ fn gather_node( | |||||||
|         AstNodeRef::Function(function) => { |         AstNodeRef::Function(function) => { | ||||||
|             gather_function(function, symbol_table, fqn_context, diagnostics); |             gather_function(function, symbol_table, fqn_context, diagnostics); | ||||||
|         } |         } | ||||||
|         AstNodeRef::OperatorFunction(_) => {} |         AstNodeRef::OperatorFunction(operator_function) => { | ||||||
|         AstNodeRef::PlatformFunction(_) => {} |             gather_operator_function(operator_function, symbol_table, fqn_context, diagnostics); | ||||||
|         AstNodeRef::InterfaceFunction(_) => {} |         } | ||||||
|         AstNodeRef::InterfaceDefaultFunction(_) => {} |         AstNodeRef::PlatformFunction(platform_function) => { | ||||||
|         AstNodeRef::InterfaceOperatorFunction(_) => {} |             gather_platform_function(platform_function, symbol_table, fqn_context, diagnostics); | ||||||
|         AstNodeRef::InterfaceDefaultOperatorFunction(_) => {} |         } | ||||||
|         AstNodeRef::FunctionBody(function_body) => match function_body { |         AstNodeRef::PlatformOperatorFunction(platform_operator_function) => { | ||||||
|             FunctionBody::FunctionAliasBody(alias_body) => { |             gather_platform_operator_function( | ||||||
|                 gather_node( |                 platform_operator_function, | ||||||
|                     alias_body.as_node_ref(), |                 symbol_table, | ||||||
|                     symbol_table, |                 fqn_context, | ||||||
|                     fqn_context, |                 diagnostics, | ||||||
|                     diagnostics, |             ); | ||||||
|                 ); |         } | ||||||
|             } |         AstNodeRef::InterfaceFunction(interface_function) => { | ||||||
|             FunctionBody::FunctionEqualsBody(equals_body) => { |             gather_interface_function(interface_function, symbol_table, fqn_context, diagnostics); | ||||||
|                 gather_node( |         } | ||||||
|                     equals_body.as_node_ref(), |         AstNodeRef::InterfaceDefaultFunction(interface_default_function) => { | ||||||
|                     symbol_table, |             gather_interface_default_function( | ||||||
|                     fqn_context, |                 interface_default_function, | ||||||
|                     diagnostics, |                 symbol_table, | ||||||
|                 ); |                 fqn_context, | ||||||
|             } |                 diagnostics, | ||||||
|             FunctionBody::FunctionBlockBody(block_body) => { |             ); | ||||||
|                 gather_node( |         } | ||||||
|                     block_body.as_node_ref(), |         AstNodeRef::InterfaceOperatorFunction(interface_operator_function) => { | ||||||
|                     symbol_table, |             gather_interface_operator_function( | ||||||
|                     fqn_context, |                 interface_operator_function, | ||||||
|                     diagnostics, |                 symbol_table, | ||||||
|                 ); |                 fqn_context, | ||||||
|             } |                 diagnostics, | ||||||
|         }, |             ); | ||||||
|         AstNodeRef::FunctionEqualsBody(_) => {} |         } | ||||||
|         AstNodeRef::FunctionAliasBody(_) => {} |         AstNodeRef::InterfaceDefaultOperatorFunction(interface_default_operator_function) => { | ||||||
|         AstNodeRef::FunctionBlockBody(block_body) => { |             gather_interface_default_operator_function( | ||||||
|             gather_function_block_body(block_body, symbol_table, fqn_context, diagnostics); |                 interface_default_operator_function, | ||||||
|  |                 symbol_table, | ||||||
|  |                 fqn_context, | ||||||
|  |                 diagnostics, | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         AstNodeRef::FunctionBody(function_body) => { | ||||||
|  |             gather_function_body(function_body, symbol_table, fqn_context, diagnostics); | ||||||
|  |         } | ||||||
|  |         AstNodeRef::FunctionEqualsBody(function_equals_body) => { | ||||||
|  |             gather_node_children(function_equals_body, symbol_table, fqn_context, diagnostics); | ||||||
|  |         } | ||||||
|  |         AstNodeRef::FunctionAliasBody(_) => { | ||||||
|  |             // no-op
 | ||||||
|  |         } | ||||||
|  |         AstNodeRef::FunctionBlockBody(function_block_body) => { | ||||||
|  |             gather_node_children(function_block_body, symbol_table, fqn_context, diagnostics); | ||||||
|  |         } | ||||||
|  |         AstNodeRef::ClassConstructor(class_constructor) => { | ||||||
|  |             gather_node_children(class_constructor, symbol_table, fqn_context, diagnostics); | ||||||
|  |         } | ||||||
|  |         AstNodeRef::Member(member) => { | ||||||
|  |             gather_member(member, symbol_table, fqn_context, diagnostics); | ||||||
|         } |         } | ||||||
|         AstNodeRef::ClassConstructor(_) => {} |  | ||||||
|         AstNodeRef::Member(_) => {} |  | ||||||
|         AstNodeRef::Statement(statement) => match statement { |         AstNodeRef::Statement(statement) => match statement { | ||||||
|             Statement::VariableDeclaration(variable_declaration) => { |             Statement::VariableDeclaration(variable_declaration) => { | ||||||
|                 gather_node( |                 gather_node( | ||||||
| @ -190,14 +218,59 @@ fn gather_node( | |||||||
|                     diagnostics, |                     diagnostics, | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
|             Statement::AssignmentStatement(_) => {} |             Statement::AssignmentStatement(assignment_statement) => { | ||||||
|             Statement::ExpressionStatement(_) => {} |                 gather_node( | ||||||
|             Statement::UseStatement(_) => {} |                     assignment_statement.as_node_ref(), | ||||||
|             Statement::IfStatement(_) => {} |                     symbol_table, | ||||||
|             Statement::WhileStatement(_) => {} |                     fqn_context, | ||||||
|             Statement::ForStatement(_) => {} |                     diagnostics, | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             Statement::ExpressionStatement(expression_statement) => { | ||||||
|  |                 gather_node( | ||||||
|  |                     expression_statement.as_node_ref(), | ||||||
|  |                     symbol_table, | ||||||
|  |                     fqn_context, | ||||||
|  |                     diagnostics, | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             Statement::UseStatement(use_statement) => { | ||||||
|  |                 gather_node( | ||||||
|  |                     use_statement.as_node_ref(), | ||||||
|  |                     symbol_table, | ||||||
|  |                     fqn_context, | ||||||
|  |                     diagnostics, | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             Statement::IfStatement(if_statement) => gather_node( | ||||||
|  |                 if_statement.as_node_ref(), | ||||||
|  |                 symbol_table, | ||||||
|  |                 fqn_context, | ||||||
|  |                 diagnostics, | ||||||
|  |             ), | ||||||
|  |             Statement::WhileStatement(while_statement) => gather_node( | ||||||
|  |                 while_statement.as_node_ref(), | ||||||
|  |                 symbol_table, | ||||||
|  |                 fqn_context, | ||||||
|  |                 diagnostics, | ||||||
|  |             ), | ||||||
|  |             Statement::ForStatement(for_statement) => { | ||||||
|  |                 gather_node( | ||||||
|  |                     for_statement.as_node_ref(), | ||||||
|  |                     symbol_table, | ||||||
|  |                     fqn_context, | ||||||
|  |                     diagnostics, | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|         }, |         }, | ||||||
|         AstNodeRef::VariableDeclaration(_) => {} |         AstNodeRef::VariableDeclaration(variable_declaration) => { | ||||||
|  |             gather_variable_declaration( | ||||||
|  |                 variable_declaration, | ||||||
|  |                 symbol_table, | ||||||
|  |                 fqn_context, | ||||||
|  |                 diagnostics, | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|         AstNodeRef::AssignmentStatement(_) => {} |         AstNodeRef::AssignmentStatement(_) => {} | ||||||
|         AstNodeRef::ExpressionStatement(_) => {} |         AstNodeRef::ExpressionStatement(_) => {} | ||||||
|         AstNodeRef::IfStatement(_) => {} |         AstNodeRef::IfStatement(_) => {} | ||||||
| @ -443,6 +516,12 @@ fn gather_class( | |||||||
|     fqn_context.push(class.identifier().name()); |     fqn_context.push(class.identifier().name()); | ||||||
|     symbol_table.push_scope(&format!("ClassScope {}", class.identifier().name())); |     symbol_table.push_scope(&format!("ClassScope {}", class.identifier().name())); | ||||||
| 
 | 
 | ||||||
|  |     gather_node( | ||||||
|  |         class.class_constructor().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|     for declaration in class.class_level_declarations() { |     for declaration in class.class_level_declarations() { | ||||||
|         gather_node( |         gather_node( | ||||||
|             declaration.as_node_ref(), |             declaration.as_node_ref(), | ||||||
| @ -479,25 +558,488 @@ fn gather_function( | |||||||
|             diagnostics, |             diagnostics, | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |     symbol_table.push_scope(&format!("FunctionScope {}", function.identifier().name())); | ||||||
|  |     gather_node( | ||||||
|  |         function.generics().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         function.parameters().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         function.return_type().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|     gather_node( |     gather_node( | ||||||
|         function.function_body().as_node_ref(), |         function.function_body().as_node_ref(), | ||||||
|         symbol_table, |         symbol_table, | ||||||
|         fqn_context, |         fqn_context, | ||||||
|         diagnostics, |         diagnostics, | ||||||
|     ); |     ); | ||||||
|  |     symbol_table.pop_scope(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn gather_function_block_body( | fn gather_operator_function( | ||||||
|     function_block_body: &FunctionBlockBody, |     operator_function: &OperatorFunction, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     fqn_context: &mut FqnContext, |     fqn_context: &mut FqnContext, | ||||||
|     diagnostics: &mut Vec<DmDiagnostic>, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     symbol_table.push_scope("FunctionBlockBody"); |     let function_symbol = FunctionSymbol::without_parameters_or_return_type( | ||||||
|     gather_node_children(function_block_body, symbol_table, fqn_context, diagnostics); |         &fqn_context.resolve(&operator_function.operator().inner().name()), | ||||||
|  |         operator_function.operator().inner().name(), | ||||||
|  |         operator_function.is_public(), | ||||||
|  |         false, | ||||||
|  |         Some(SourceDefinition::from_operator( | ||||||
|  |             operator_function.operator(), | ||||||
|  |         )), | ||||||
|  |     ); | ||||||
|  |     if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { | ||||||
|  |         handle_insert_error( | ||||||
|  |             insert_error, | ||||||
|  |             operator_function.operator().inner().name(), | ||||||
|  |             operator_function.operator().file_id(), | ||||||
|  |             operator_function.operator().range(), | ||||||
|  |             "Operator", | ||||||
|  |             diagnostics, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     symbol_table.push_scope(&format!( | ||||||
|  |         "FunctionScope {}", | ||||||
|  |         operator_function.operator().inner().name() | ||||||
|  |     )); | ||||||
|  |     gather_node( | ||||||
|  |         operator_function.generics().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         operator_function.parameters().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         operator_function.return_type().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         operator_function.function_body().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|     symbol_table.pop_scope(); |     symbol_table.pop_scope(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn gather_platform_function( | ||||||
|  |     platform_function: &PlatformFunction, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let function_symbol = FunctionSymbol::without_parameters_or_return_type( | ||||||
|  |         &fqn_context.resolve(platform_function.identifier().name()), | ||||||
|  |         platform_function.identifier().name(), | ||||||
|  |         platform_function.is_public(), | ||||||
|  |         true, | ||||||
|  |         Some(SourceDefinition::from_identifier( | ||||||
|  |             platform_function.identifier(), | ||||||
|  |         )), | ||||||
|  |     ); | ||||||
|  |     if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { | ||||||
|  |         handle_insert_error( | ||||||
|  |             insert_error, | ||||||
|  |             platform_function.identifier().name(), | ||||||
|  |             platform_function.identifier().file_id(), | ||||||
|  |             platform_function.identifier().range(), | ||||||
|  |             "Function", | ||||||
|  |             diagnostics, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     symbol_table.push_scope(&format!( | ||||||
|  |         "PlatformFunctionScope {}", | ||||||
|  |         platform_function.identifier().name() | ||||||
|  |     )); | ||||||
|  |     gather_node( | ||||||
|  |         platform_function.generics().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         platform_function.parameters().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         platform_function.return_type().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     symbol_table.pop_scope(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_platform_operator_function( | ||||||
|  |     platform_operator_function: &PlatformOperatorFunction, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let function_symbol = FunctionSymbol::without_parameters_or_return_type( | ||||||
|  |         &fqn_context.resolve(platform_operator_function.operator().inner().name()), | ||||||
|  |         platform_operator_function.operator().inner().name(), | ||||||
|  |         platform_operator_function.is_public(), | ||||||
|  |         true, | ||||||
|  |         Some(SourceDefinition::from_operator( | ||||||
|  |             platform_operator_function.operator(), | ||||||
|  |         )), | ||||||
|  |     ); | ||||||
|  |     if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { | ||||||
|  |         handle_insert_error( | ||||||
|  |             insert_error, | ||||||
|  |             platform_operator_function.operator().inner().name(), | ||||||
|  |             platform_operator_function.operator().file_id(), | ||||||
|  |             platform_operator_function.operator().range(), | ||||||
|  |             "Function", | ||||||
|  |             diagnostics, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     symbol_table.push_scope(&format!( | ||||||
|  |         "PlatformOperatorFunctionScope {}", | ||||||
|  |         platform_operator_function.operator().inner().name() | ||||||
|  |     )); | ||||||
|  |     gather_node( | ||||||
|  |         platform_operator_function.generics().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         platform_operator_function.parameters().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         platform_operator_function.return_type().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     symbol_table.pop_scope(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_interface_function( | ||||||
|  |     interface_function: &InterfaceFunction, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let function_symbol = FunctionSymbol::without_parameters_or_return_type( | ||||||
|  |         &fqn_context.resolve(interface_function.identifier().name()), | ||||||
|  |         interface_function.identifier().name(), | ||||||
|  |         true, | ||||||
|  |         false, | ||||||
|  |         Some(SourceDefinition::from_identifier( | ||||||
|  |             interface_function.identifier(), | ||||||
|  |         )), | ||||||
|  |     ); | ||||||
|  |     if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { | ||||||
|  |         handle_insert_error( | ||||||
|  |             insert_error, | ||||||
|  |             interface_function.identifier().name(), | ||||||
|  |             interface_function.identifier().file_id(), | ||||||
|  |             interface_function.identifier().range(), | ||||||
|  |             "Type", | ||||||
|  |             diagnostics, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     symbol_table.push_scope(&format!( | ||||||
|  |         "InterfaceFunctionScope {}", | ||||||
|  |         interface_function.identifier().name() | ||||||
|  |     )); | ||||||
|  |     gather_node( | ||||||
|  |         interface_function.generics().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         interface_function.parameters().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         interface_function.return_type().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     symbol_table.pop_scope(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_interface_default_function( | ||||||
|  |     interface_default_function: &InterfaceDefaultFunction, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let function_symbol = FunctionSymbol::without_parameters_or_return_type( | ||||||
|  |         &fqn_context.resolve(interface_default_function.identifier().name()), | ||||||
|  |         interface_default_function.identifier().name(), | ||||||
|  |         true, | ||||||
|  |         false, | ||||||
|  |         Some(SourceDefinition::from_identifier( | ||||||
|  |             interface_default_function.identifier(), | ||||||
|  |         )), | ||||||
|  |     ); | ||||||
|  |     if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { | ||||||
|  |         handle_insert_error( | ||||||
|  |             insert_error, | ||||||
|  |             interface_default_function.identifier().name(), | ||||||
|  |             interface_default_function.identifier().file_id(), | ||||||
|  |             interface_default_function.identifier().range(), | ||||||
|  |             "Function", | ||||||
|  |             diagnostics, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     symbol_table.push_scope(&format!( | ||||||
|  |         "InterfaceDefaultFunctionScope {}", | ||||||
|  |         interface_default_function.identifier().name() | ||||||
|  |     )); | ||||||
|  |     gather_node( | ||||||
|  |         interface_default_function.generics().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         interface_default_function.parameters().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         interface_default_function.return_type().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         interface_default_function.function_body().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     symbol_table.pop_scope(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_interface_operator_function( | ||||||
|  |     interface_operator_function: &InterfaceOperatorFunction, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let function_symbol = FunctionSymbol::without_parameters_or_return_type( | ||||||
|  |         &fqn_context.resolve(interface_operator_function.operator().inner().name()), | ||||||
|  |         interface_operator_function.operator().inner().name(), | ||||||
|  |         true, | ||||||
|  |         false, | ||||||
|  |         Some(SourceDefinition::from_operator( | ||||||
|  |             interface_operator_function.operator(), | ||||||
|  |         )), | ||||||
|  |     ); | ||||||
|  |     if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { | ||||||
|  |         handle_insert_error( | ||||||
|  |             insert_error, | ||||||
|  |             interface_operator_function.operator().inner().name(), | ||||||
|  |             interface_operator_function.operator().file_id(), | ||||||
|  |             interface_operator_function.operator().range(), | ||||||
|  |             "Function", | ||||||
|  |             diagnostics, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     symbol_table.push_scope(&format!( | ||||||
|  |         "InterfaceOperatorFunctionScope {}", | ||||||
|  |         interface_operator_function.operator().inner().name() | ||||||
|  |     )); | ||||||
|  |     gather_node( | ||||||
|  |         interface_operator_function.generics().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         interface_operator_function.parameters().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         interface_operator_function.return_type().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     symbol_table.pop_scope(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_interface_default_operator_function( | ||||||
|  |     interface_default_operator_function: &InterfaceDefaultOperatorFunction, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let function_symbol = FunctionSymbol::without_parameters_or_return_type( | ||||||
|  |         &fqn_context.resolve( | ||||||
|  |             interface_default_operator_function | ||||||
|  |                 .operator() | ||||||
|  |                 .inner() | ||||||
|  |                 .name(), | ||||||
|  |         ), | ||||||
|  |         interface_default_operator_function | ||||||
|  |             .operator() | ||||||
|  |             .inner() | ||||||
|  |             .name(), | ||||||
|  |         true, | ||||||
|  |         false, | ||||||
|  |         Some(SourceDefinition::from_operator( | ||||||
|  |             interface_default_operator_function.operator(), | ||||||
|  |         )), | ||||||
|  |     ); | ||||||
|  |     if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { | ||||||
|  |         handle_insert_error( | ||||||
|  |             insert_error, | ||||||
|  |             interface_default_operator_function | ||||||
|  |                 .operator() | ||||||
|  |                 .inner() | ||||||
|  |                 .name(), | ||||||
|  |             interface_default_operator_function.operator().file_id(), | ||||||
|  |             interface_default_operator_function.operator().range(), | ||||||
|  |             "Function", | ||||||
|  |             diagnostics, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     symbol_table.push_scope(&format!( | ||||||
|  |         "InterfaceDefaultOperatorFunctionScope {}", | ||||||
|  |         interface_default_operator_function | ||||||
|  |             .operator() | ||||||
|  |             .inner() | ||||||
|  |             .name() | ||||||
|  |     )); | ||||||
|  |     gather_node( | ||||||
|  |         interface_default_operator_function.generics().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         interface_default_operator_function | ||||||
|  |             .parameters() | ||||||
|  |             .as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         interface_default_operator_function | ||||||
|  |             .return_type() | ||||||
|  |             .as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_node( | ||||||
|  |         interface_default_operator_function | ||||||
|  |             .function_body() | ||||||
|  |             .as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     symbol_table.pop_scope(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_function_body( | ||||||
|  |     function_body: &FunctionBody, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     symbol_table.push_scope("FunctionBodyScope"); | ||||||
|  |     match function_body { | ||||||
|  |         FunctionBody::FunctionAliasBody(alias_body) => { | ||||||
|  |             gather_node( | ||||||
|  |                 alias_body.as_node_ref(), | ||||||
|  |                 symbol_table, | ||||||
|  |                 fqn_context, | ||||||
|  |                 diagnostics, | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         FunctionBody::FunctionEqualsBody(equals_body) => { | ||||||
|  |             gather_node( | ||||||
|  |                 equals_body.as_node_ref(), | ||||||
|  |                 symbol_table, | ||||||
|  |                 fqn_context, | ||||||
|  |                 diagnostics, | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         FunctionBody::FunctionBlockBody(block_body) => { | ||||||
|  |             gather_node( | ||||||
|  |                 block_body.as_node_ref(), | ||||||
|  |                 symbol_table, | ||||||
|  |                 fqn_context, | ||||||
|  |                 diagnostics, | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     symbol_table.pop_scope(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_member( | ||||||
|  |     member: &Member, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let member_symbol = ClassMemberSymbol::new( | ||||||
|  |         member.is_public(), | ||||||
|  |         member.is_mut(), | ||||||
|  |         member.identifier().name(), | ||||||
|  |         Some(SourceDefinition::from_identifier(member.identifier())), | ||||||
|  |     ); | ||||||
|  |     if let Err(insert_error) = symbol_table.insert_class_member_symbol(member_symbol) { | ||||||
|  |         handle_insert_error( | ||||||
|  |             insert_error, | ||||||
|  |             member.identifier().name(), | ||||||
|  |             member.identifier().file_id(), | ||||||
|  |             member.identifier().range(), | ||||||
|  |             "Class Member", | ||||||
|  |             diagnostics, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     gather_node( | ||||||
|  |         member.type_use().as_node_ref(), | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn gather_variable_declaration( | fn gather_variable_declaration( | ||||||
|     variable_declaration: &VariableDeclaration, |     variable_declaration: &VariableDeclaration, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|  | |||||||
| @ -3,30 +3,37 @@ use std::fmt::{Debug, Formatter}; | |||||||
| 
 | 
 | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| pub struct ClassMemberSymbol { | pub struct ClassMemberSymbol { | ||||||
|  |     is_public: bool, | ||||||
|  |     is_mut: bool, | ||||||
|     declared_name: String, |     declared_name: String, | ||||||
|     is_field: bool, |  | ||||||
|     source_definition: Option<SourceDefinition>, |     source_definition: Option<SourceDefinition>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl ClassMemberSymbol { | impl ClassMemberSymbol { | ||||||
|     pub fn new( |     pub fn new( | ||||||
|  |         is_public: bool, | ||||||
|  |         is_mut: bool, | ||||||
|         declared_name: &str, |         declared_name: &str, | ||||||
|         is_field: bool, |  | ||||||
|         source_definition: Option<SourceDefinition>, |         source_definition: Option<SourceDefinition>, | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         Self { |         Self { | ||||||
|  |             is_public, | ||||||
|  |             is_mut, | ||||||
|             declared_name: declared_name.to_string(), |             declared_name: declared_name.to_string(), | ||||||
|             is_field, |  | ||||||
|             source_definition, |             source_definition, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     
 |     
 | ||||||
|     pub fn declared_name(&self) -> &str { |     pub fn is_public(&self) -> bool { | ||||||
|         &self.declared_name |         self.is_public | ||||||
|     } |     } | ||||||
|     
 |     
 | ||||||
|     pub fn is_field(&self) -> bool { |     pub fn is_mut(&self) -> bool { | ||||||
|         self.is_field |         self.is_mut | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn declared_name(&self) -> &str { | ||||||
|  |         &self.declared_name | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn source_definition(&self) -> Option<&SourceDefinition> { |     pub fn source_definition(&self) -> Option<&SourceDefinition> { | ||||||
| @ -37,8 +44,9 @@ impl ClassMemberSymbol { | |||||||
| impl Debug for ClassMemberSymbol { | impl Debug for ClassMemberSymbol { | ||||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||||||
|         f.debug_struct("ClassMemberSymbol") |         f.debug_struct("ClassMemberSymbol") | ||||||
|  |             .field("is_public", &self.is_public) | ||||||
|  |             .field("is_mut", &self.is_mut) | ||||||
|             .field("declared_name", &self.declared_name) |             .field("declared_name", &self.declared_name) | ||||||
|             .field("is_field", &self.is_field) |  | ||||||
|             .field("source_definition", &self.source_definition) |             .field("source_definition", &self.source_definition) | ||||||
|             .finish() |             .finish() | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| use std::cell::RefCell; | use std::cell::RefCell; | ||||||
| use std::range::Range; | use std::range::Range; | ||||||
| use std::rc::Rc; | use std::rc::Rc; | ||||||
| use crate::ast::node::{Identifier, UseStatement}; | use crate::ast::node::{Identifier, Operator, UseStatement}; | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, Debug)] | #[derive(Clone, Debug)] | ||||||
| pub struct SourceDefinition { | pub struct SourceDefinition { | ||||||
| @ -17,14 +17,6 @@ impl SourceDefinition { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     
 |     
 | ||||||
|     pub fn from_identifier_rc(identifier: Rc<RefCell<Identifier>>) -> Self { |  | ||||||
|         let borrowed = identifier.borrow(); |  | ||||||
|         SourceDefinition { |  | ||||||
|             file_id: borrowed.file_id(), |  | ||||||
|             range: borrowed.range(), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     
 |  | ||||||
|     pub fn from_use_statement(use_statement: &UseStatement) -> Self { |     pub fn from_use_statement(use_statement: &UseStatement) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             file_id: use_statement.file_id(), |             file_id: use_statement.file_id(), | ||||||
| @ -32,6 +24,13 @@ impl SourceDefinition { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     
 |     
 | ||||||
|  |     pub fn from_operator(operator: &Operator) -> Self { | ||||||
|  |         Self { | ||||||
|  |             file_id: operator.file_id(), | ||||||
|  |             range: operator.range(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn file_id(&self) -> usize { |     pub fn file_id(&self) -> usize { | ||||||
|         self.file_id |         self.file_id | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -57,11 +57,11 @@ impl SymbolTable { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn current_scope(&self) -> &Scope { |     fn current_scope(&self) -> &Scope { | ||||||
|         self.scopes.last().unwrap() |         &self.scopes[self.current_scope_id] | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn current_scope_mut(&mut self) -> &mut Scope { |     fn current_scope_mut(&mut self) -> &mut Scope { | ||||||
|         self.scopes.last_mut().unwrap() |         &mut self.scopes[self.current_scope_id] | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn find_current_scope_concrete_use_symbol( |     fn find_current_scope_concrete_use_symbol( | ||||||
|  | |||||||
| @ -127,7 +127,13 @@ macro_rules! write_symbols { | |||||||
| 
 | 
 | ||||||
| impl Display for Scope { | impl Display for Scope { | ||||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||||||
|         writeln!(f, "----Scope {} {}----", self.id(), self.debug_name())?; |         writeln!( | ||||||
|  |             f, | ||||||
|  |             "----Scope {} (p: {}) {}----", | ||||||
|  |             self.id(), | ||||||
|  |             self.parent().map(|parent_id| format!("{}", parent_id)).unwrap_or_else(|| "None".to_string()), | ||||||
|  |             self.debug_name() | ||||||
|  |         )?; | ||||||
|         write_symbols!(f, self.concrete_use_symbols()); |         write_symbols!(f, self.concrete_use_symbols()); | ||||||
|         write_symbols!(f, self.star_use_symbols()); |         write_symbols!(f, self.star_use_symbols()); | ||||||
|         write_symbols!(f, self.module_symbols()); |         write_symbols!(f, self.module_symbols()); | ||||||
|  | |||||||
| @ -1,6 +1,18 @@ | |||||||
| # $schema: ./ast.schema.yaml | # $schema: ./ast.schema.yaml | ||||||
| # Operators | # Operators | ||||||
| Operator: | Operator: | ||||||
|  |   struct:  | ||||||
|  |     children: | ||||||
|  |       - inner: | ||||||
|  |           member:  | ||||||
|  |             rule: OperatorInner | ||||||
|  |       - file_id: | ||||||
|  |           special:  | ||||||
|  |             kind: file_id | ||||||
|  |       - range: | ||||||
|  |           special:  | ||||||
|  |             kind: range | ||||||
|  | OperatorInner: | ||||||
|   leaf_enum: |   leaf_enum: | ||||||
|     rules: |     rules: | ||||||
|       - Or |       - Or | ||||||
| @ -429,6 +441,30 @@ PlatformFunction: | |||||||
|       - identifier |       - identifier | ||||||
|       - parameters |       - parameters | ||||||
|       - return_type |       - return_type | ||||||
|  | PlatformOperatorFunction: | ||||||
|  |   struct:  | ||||||
|  |     children: | ||||||
|  |       - is_public: | ||||||
|  |           member:  | ||||||
|  |             rule: Pub | ||||||
|  |             build:  | ||||||
|  |               boolean:  | ||||||
|  |                 on: rule_present | ||||||
|  |       - platform_kw: | ||||||
|  |           skip:  | ||||||
|  |             rule: Platform | ||||||
|  |       - op_kw: | ||||||
|  |           skip: | ||||||
|  |             rule: Op | ||||||
|  |       - generics: | ||||||
|  |           member:  | ||||||
|  |             rule: GenericParameters | ||||||
|  |             build:  | ||||||
|  |               node: | ||||||
|  |                 or_else_default: true | ||||||
|  |       - operator | ||||||
|  |       - parameters | ||||||
|  |       - return_type | ||||||
| InterfaceFunction: | InterfaceFunction: | ||||||
|   struct: |   struct: | ||||||
|     children: |     children: | ||||||
|  | |||||||
| @ -131,6 +131,10 @@ Index = { "[]" } | |||||||
| BorrowMut = { Borrow ~ Mut } | BorrowMut = { Borrow ~ Mut } | ||||||
| 
 | 
 | ||||||
| Operator = { | Operator = { | ||||||
|  |       OperatorInner | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | OperatorInner = { | ||||||
|       Or |       Or | ||||||
|     | And |     | And | ||||||
|     | EqualTo |     | EqualTo | ||||||
| @ -431,6 +435,16 @@ PlatformFunction = { | |||||||
|     ~ ReturnType |     ~ ReturnType | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | PlatformOperatorFunction = { | ||||||
|  |       Pub? | ||||||
|  |     ~ Platform | ||||||
|  |     ~ Op | ||||||
|  |     ~ GenericParameters? | ||||||
|  |     ~ Operator | ||||||
|  |     ~ Parameters | ||||||
|  |     ~ ReturnType | ||||||
|  | } | ||||||
|  | 
 | ||||||
| InterfaceFunction = { | InterfaceFunction = { | ||||||
|       Fn |       Fn | ||||||
|     ~ GenericParameters? |     ~ GenericParameters? | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Jesse Brault
						Jesse Brault