diff --git a/src/builtins.rs b/src/builtins.rs index d5d09dd647..d6b8791262 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -21,14 +21,19 @@ use crate::{ index::Index, lexer, parser, resolver::{ - self, - generics::{generic_name_resolver, no_generic_name_resolver, GenericType}, - AnnotationMap, StatementAnnotation, TypeAnnotator, VisitorContext, + self, generics::{generic_name_resolver, no_generic_name_resolver, GenericType}, AnnotationMap, AnnotationMapImpl, StatementAnnotation, TypeAnnotator, VisitorContext }, typesystem::{self, get_bigger_type, get_literal_actual_signed_type_name, DataTypeInformationProvider}, validation::{Validator, Validators}, }; +// macro that turns the given AstNode into a slice-of nodes, used for parameter list +macro_rules! param_list { + ($node:expr) => { + $node.map(|p| p.get_as_list()).unwrap_or_default().as_slice() + }; +} + // Defines a set of functions that are always included in a compiled application lazy_static! { static ref BUILTIN: FxHashMap<&'static str, BuiltIn> = FxHashMap::from_iter([ @@ -42,7 +47,6 @@ lazy_static! { END_FUNCTION ", annotation: None, - replacement: None, validation: None, generic_name_resolver: no_generic_name_resolver, code: |generator, params, location| { @@ -68,29 +72,16 @@ lazy_static! { END_VAR END_FUNCTION ", - replacement: None, - annotation: Some(|annotator, _, operator, parameters, _| { - // invalid amount of parameters is checked during validation - let Some(params) = parameters else { return; }; - // Get the input and annotate it with a pointer type - let input = flatten_expression_list(params); - let Some(input) = input.first() else { return; }; - let input_type = annotator.annotation_map - .get_type_or_void(input, annotator.index) - .get_type_information() - .get_name() - .to_owned(); - - let ptr_type = resolver::add_pointer_type( - &mut annotator.annotation_map.new_index, - input_type - ); - - annotator.annotate( - operator, resolver::StatementAnnotation::Function { - return_type: ptr_type, qualified_name: "REF".to_string(), call_name: None - } - ); + annotation: Some(|annotator, stmt, _, parameters, _| { + if let Some(passed_type) = parameters.and_then(|it| annotator.get_type_name(it)).map(|it| it.to_string()){ + //TODO can we return &str instead of String? + let ptr_type = resolver::add_pointer_type( + &mut annotator.new_index, + passed_type + ); + + annotator.annotate(stmt, StatementAnnotation::value(ptr_type.as_str())); + } }), validation: Some(|validator, operator, parameters, _, _| { let Some(params) = parameters else { @@ -130,7 +121,6 @@ lazy_static! { END_FUNCTION ", annotation : None, - replacement: None, validation: None, generic_name_resolver: no_generic_name_resolver, code: |generator, params, location| { @@ -188,7 +178,6 @@ lazy_static! { END_FUNCTION ", annotation: None, - replacement: None, validation: None, generic_name_resolver: no_generic_name_resolver, code: |generator, params, location| { @@ -232,7 +221,6 @@ lazy_static! { END_VAR END_FUNCTION", annotation: None, - replacement: None, validation: None, generic_name_resolver: no_generic_name_resolver, code : |generator, params, location| { @@ -253,7 +241,6 @@ lazy_static! { END_VAR END_FUNCTION", annotation: None, - replacement: None, validation: None, generic_name_resolver: no_generic_name_resolver, code : |generator, params, location| { @@ -293,9 +280,9 @@ lazy_static! { dim : T; END_VAR END_FUNCTION", - replacement: None, annotation: Some(|annotator, _, _, parameters, _| { - annotate_variable_length_array_bound_function(annotator, parameters); + // annotate_variable_length_array_bound_function(annotator, parameters); + todo!() }), validation: Some(|validator, operator, parameters, annotations, index| { validate_variable_length_array_bound_function(validator, operator, parameters, annotations, index) @@ -317,9 +304,9 @@ lazy_static! { dim : T; END_VAR END_FUNCTION", - replacement: None, annotation: Some(|annotator, _, _, parameters, _| { - annotate_variable_length_array_bound_function(annotator, parameters); + // annotate_variable_length_array_bound_function(annotator, parameters); + todo!() }), validation: Some(|validator, operator, parameters, annotations, index| { validate_variable_length_array_bound_function(validator, operator, parameters, annotations, index) @@ -340,13 +327,10 @@ lazy_static! { END_VAR END_FUNCTION ", - replacement: Some(|parameters, id_provider| generate_arithmetic_function(parameters, Operator::Plus, id_provider)), - annotation: Some(|annotator, statement, operator, parameters, ctx| { - let Some(params) = parameters else { - return; - }; - - annotate_arithmetic_function(annotator, statement, operator, params, ctx, Operator::Plus) + annotation: Some(|annotator, statement, operator, parameters, id_provider| { + annotator.annotate(statement, + StatementAnnotation::ReplacementAst { statement: generate_arithmetic_function(param_list!(parameters), + Operator::Plus, id_provider) }); }), validation:Some(|validator, operator, parameters, _, _| { validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Plus) @@ -366,13 +350,10 @@ lazy_static! { END_VAR END_FUNCTION ", - replacement: Some(|parameters, id_provider| generate_arithmetic_function(parameters, Operator::Multiplication, id_provider)), - annotation: Some(|annotator, statement, operator, parameters, ctx| { - let Some(params) = parameters else { - return; - }; - - annotate_arithmetic_function(annotator, statement, operator, params, ctx, Operator::Multiplication) + annotation: Some(|annotator, statement, operator, parameters, id_provider| { + annotator.annotate(statement, + StatementAnnotation::ReplacementAst { statement: generate_arithmetic_function(param_list!(parameters), + Operator::Multiplication, id_provider) }); }), validation: Some(|validator, operator, parameters, _, _| { validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Multiplication) @@ -393,12 +374,10 @@ lazy_static! { END_VAR END_FUNCTION ", - replacement: Some(|parameters, id_provider| generate_arithmetic_function(parameters, Operator::Minus, id_provider)), - annotation: Some(|annotator, statement, operator, parameters, ctx| { - let Some(params) = parameters else { - return; - }; - annotate_arithmetic_function(annotator, statement, operator, params, ctx, Operator::Minus) + annotation: Some(|annotator, statement, operator, parameters, id_provider| { + annotator.annotate(statement, + StatementAnnotation::ReplacementAst { statement: generate_arithmetic_function(param_list!(parameters), + Operator::Minus, id_provider) }); }), validation:Some(|validator, operator, parameters, _, _| { validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Minus) @@ -419,12 +398,10 @@ lazy_static! { END_VAR END_FUNCTION ", - replacement: Some(|parameters, id_provider| generate_arithmetic_function(parameters, Operator::Division, id_provider)), - annotation: Some(|annotator, statement, operator, parameters, ctx| { - let Some(params) = parameters else { - return; - }; - annotate_arithmetic_function(annotator, statement, operator, params, ctx, Operator::Division) + annotation: Some(|annotator, statement, operator, parameters, id_provider| { + annotator.annotate(statement, + StatementAnnotation::ReplacementAst { statement: generate_arithmetic_function(param_list!(parameters), + Operator::Division, id_provider) }); }), validation:Some(|validator, operator, parameters, _, _| { validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Division) @@ -445,13 +422,8 @@ lazy_static! { END_VAR END_FUNCTION ", - replacement: Some(|parameters, id_provider| generate_comparison_function(parameters, Operator::Greater, id_provider)), - annotation: Some(|annotator, statement, operator, parameters, ctx| { - let Some(params) = parameters else { - return; - }; - annotate_comparison_function(annotator, statement, operator, params, ctx, Operator::Greater); - }), + annotation: Some(|annotator, statement, operator, parameters, id_provider| + annotate_comparison_function(annotator, statement, Operator::Greater, param_list!(parameters), id_provider)), validation:Some(|validator, operator, parameters, _, _| { validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Greater) }), @@ -470,13 +442,8 @@ lazy_static! { END_VAR END_FUNCTION ", - replacement: Some(|parameters, id_provider| generate_comparison_function(parameters, Operator::GreaterOrEqual, id_provider)), -annotation: Some(|annotator, statement, operator, parameters, ctx| { - let Some(params) = parameters else { - return; - }; - annotate_comparison_function(annotator, statement, operator, params, ctx, Operator::GreaterOrEqual); - }), + annotation: Some(|annotator, statement, operator, parameters, id_provider| + annotate_comparison_function(annotator, statement, Operator::GreaterOrEqual, param_list!(parameters), id_provider)), validation:Some(|validator, operator, parameters, _, _| { validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::GreaterOrEqual) }), @@ -495,13 +462,8 @@ annotation: Some(|annotator, statement, operator, parameters, ctx| { END_VAR END_FUNCTION ", - replacement: Some(|nodes, id_provider| generate_comparison_function(nodes, Operator::Equal, id_provider)), -annotation: Some(|annotator, statement, operator, parameters, ctx| { - let Some(params) = parameters else { - return; - }; - annotate_comparison_function(annotator, statement, operator, params, ctx, Operator::Equal); - }), + annotation: Some(|annotator, statement, operator, parameters, id_provider| + annotate_comparison_function(annotator, statement, Operator::Equal, param_list!(parameters), id_provider)), validation:Some(|validator, operator, parameters, _, _| { validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Equal) }), @@ -520,13 +482,8 @@ annotation: Some(|annotator, statement, operator, parameters, ctx| { END_VAR END_FUNCTION ", - replacement: Some(|parameters, id_provider| generate_comparison_function(parameters, Operator::LessOrEqual, id_provider)), - annotation: Some(|annotator, statement, operator, parameters, ctx| { - let Some(params) = parameters else { - return; - }; - annotate_comparison_function(annotator, statement, operator, params, ctx, Operator::LessOrEqual); - }), + annotation: Some(|annotator, statement, operator, parameters, id_provider| + annotate_comparison_function(annotator, statement, Operator::LessOrEqual, param_list!(parameters), id_provider)), validation:Some(|validator, operator, parameters, _, _| { validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::LessOrEqual) }), @@ -545,13 +502,8 @@ annotation: Some(|annotator, statement, operator, parameters, ctx| { END_VAR END_FUNCTION ", - replacement: Some(|parameters, id_provider| generate_comparison_function(parameters, Operator::Less, id_provider)), - annotation: Some(|annotator, statement, operator, parameters, ctx| { - let Some(params) = parameters else { - return; - }; - annotate_comparison_function(annotator, statement, operator, params, ctx, Operator::Less); - }), + annotation: Some(|annotator, statement, operator, parameters, id_provider| + annotate_comparison_function(annotator, statement, Operator::Less, param_list!(parameters), id_provider)), validation:Some(|validator, operator, parameters, _, _| { validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::Less) }), @@ -571,13 +523,8 @@ annotation: Some(|annotator, statement, operator, parameters, ctx| { END_VAR END_FUNCTION ", - replacement: Some(|parameters, id_provider| generate_comparison_function(parameters, Operator::NotEqual, id_provider)), - annotation: Some(|annotator, statement, operator, parameters, ctx| { - let Some(params) = parameters else { - return; - }; - annotate_comparison_function(annotator, statement, operator, params, ctx, Operator::NotEqual); - }), + annotation: Some(|annotator, statement, operator, parameters, id_provider| + annotate_comparison_function(annotator, statement, Operator::NotEqual, param_list!(parameters), id_provider)), validation: Some(|validator, operator, parameters, _, _| { validate_builtin_symbol_parameter_count(validator, operator, parameters, Operator::NotEqual) }), @@ -674,8 +621,11 @@ fn generate_comparison_function( Some(new_statement) } -fn generate_arithmetic_function(parameters: &[&AstNode], operator: Operator, id_provider: &mut IdProvider) -> Option{ - +fn generate_arithmetic_function( + parameters: &[&AstNode], + operator: Operator, + id_provider: &mut IdProvider, +) -> AstNode { let params_flattened = parameters; // if params_flattened.iter().any(|it| { // !annotator @@ -711,7 +661,7 @@ fn generate_arithmetic_function(parameters: &[&AstNode], operator: Operator, id_ let new_statement = params_flattened.into_iter().skip(1).fold(left, |left, right| { AstFactory::create_binary_expression(left, operator, (*right).clone(), id_provider.next_id()) }); - Some(new_statement) + new_statement // annotator.visit_statement(&ctx, &new_statement); // annotator.update_expected_types(annotator.index.get_type_or_panic(&bigger_type), &new_statement); // annotator.annotate(statement, StatementAnnotation::ReplacementAst { statement: new_statement }); @@ -721,55 +671,45 @@ fn generate_arithmetic_function(parameters: &[&AstNode], operator: Operator, id_ // creates nested BinaryExpressions for each parameter, such that // GT(a, b, c, d) ends up as (a > b) & (b > c) & (c > d) fn annotate_comparison_function( - annotator: &mut TypeAnnotator, + annotator: &mut AnnotationMapImpl, statement: &AstNode, - operator: &AstNode, - parameters: &AstNode, - ctx: VisitorContext, - operation: Operator, + operator: Operator, + parameters: &[&AstNode], + id_provider: &mut IdProvider, ) { - let mut ctx = ctx; - let params_flattened = flatten_expression_list(parameters); - if params_flattened.iter().any(|it| { - !annotator - .annotation_map - .get_type_or_void(it, annotator.index) - .has_nature(TypeNature::Elementary, annotator.index) - }) { - // we are trying to call this function with a non-elementary type, so we redirect back to the resolver - annotator.annotate_call_statement(operator, Some(parameters), &ctx); - return; - } - let comparisons = params_flattened + let comparisons = parameters .windows(2) .map(|window| { AstFactory::create_binary_expression( window[0].clone(), - operation, + operator, window[1].clone(), - ctx.id_provider.next_id(), + id_provider.next_id(), ) }) .collect::>(); - let Some(new_statement) = comparisons.first() else { - // no windows => less than 2 parameters, caught during validation - return; - }; - let mut new_statement = new_statement.clone(); - comparisons.into_iter().skip(1).for_each(|right| { - new_statement = AstFactory::create_binary_expression( - new_statement.clone(), - Operator::And, - right, - ctx.id_provider.next_id(), - ) - }); + // let Some(new_statement) = comparisons.first() else { + // // no windows => less than 2 parameters, caught during validation - annotator.visit_statement(&ctx, &new_statement); - annotator.update_expected_types(annotator.index.get_type_or_panic(typesystem::BOOL_TYPE), &new_statement); - annotator.annotate(statement, StatementAnnotation::ReplacementAst { statement: new_statement }); - annotator.update_expected_types(annotator.index.get_type_or_panic(typesystem::BOOL_TYPE), statement); + // //TODO: could we generate an empty-statemen instead and use standard validation for it? + // return None; + // }; + + + + if let Some((first, comparisons)) = comparisons.split_first() { + let new_statement = comparisons.iter().fold((*first).clone(), |a, b| { + let new_statement = AstFactory::create_binary_expression( + a.clone(), + Operator::And, + (*b).clone(), + id_provider.next_id(), + ); + new_statement + }); + annotator.annotate(statement, StatementAnnotation::ReplacementAst { statement: new_statement }); + } } fn annotate_arithmetic_function( @@ -988,7 +928,7 @@ fn generate_variable_length_array_bound_function<'ink>( Ok(ExpressionValue::RValue(bound)) } -type AnnotationFunction = fn(&mut TypeAnnotator, &AstNode, &AstNode, Option<&AstNode>, VisitorContext); +type AnnotationFunction = fn(&mut AnnotationMapImpl, &AstNode, &AstNode, Option<&AstNode>, &mut IdProvider); type GenericNameResolver = fn(&str, &[GenericBinding], &FxHashMap) -> String; type CodegenFunction = for<'ink, 'b> fn( &'b ExpressionCodeGenerator<'ink, 'b>, @@ -1002,7 +942,6 @@ type ReplacementFunction = fn(&[&AstNode], &mut IdProvider) -> Option; pub struct BuiltIn { decl: &'static str, annotation: Option, - replacement: Option, validation: Option, generic_name_resolver: GenericNameResolver, code: CodegenFunction, @@ -1028,10 +967,6 @@ impl BuiltIn { pub(crate) fn get_validation(&self) -> Option { self.validation } - - pub(crate) fn get_replacement(&self) -> Option { - self.replacement - } } pub fn parse_built_ins(id_provider: IdProvider) -> CompilationUnit { diff --git a/src/name_resolver.rs b/src/name_resolver.rs index 5bab67242e..7039f53736 100644 --- a/src/name_resolver.rs +++ b/src/name_resolver.rs @@ -13,7 +13,10 @@ use plc_util::convention::internal_type_name; use crate::{ builtins, index::{Index, VariableIndexEntry}, - resolver::{register_string_type, AnnotationMap, AnnotationMapImpl, StatementAnnotation, StringLiterals}, + resolver::{ + register_string_type, AnnotationMap, AnnotationMapImpl, AstAnnotations, StatementAnnotation, + StringLiterals, + }, typesystem::{ self, get_bigger_type, get_type_name_for_direct_access, DataTypeInformation, BOOL_TYPE, DATE_AND_TIME_TYPE, DATE_TYPE, DINT_TYPE, LINT_TYPE, REAL_TYPE, TIME_OF_DAY_TYPE, TIME_TYPE, @@ -21,10 +24,10 @@ use crate::{ }, }; -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum Scope { Type, - Program, + POU, GlobalVariable, LocalVariable(String), Composite(Vec), @@ -71,7 +74,7 @@ impl Scope { index.find_type(identifier).map(|dt| dt.get_type_information()).map(StatementAnnotation::from) } - Scope::Program => index.find_pou(identifier).map(StatementAnnotation::from), + Scope::POU => index.find_pou(identifier).map(StatementAnnotation::from), // lookup a global variable Scope::GlobalVariable => { @@ -133,6 +136,7 @@ impl Scope { } } +#[derive(Debug)] pub enum ScopingStrategy { /// Indicates that this scope inherits symbols from /// it's parent scope (as reflected by the order of the ScopeStack) @@ -145,6 +149,7 @@ pub enum ScopingStrategy { Strict(Scope), } +#[derive(Debug)] pub struct ScopeStack { stack: Vec, } @@ -155,6 +160,7 @@ impl ScopeStack { stack: vec![ScopingStrategy::Strict(Scope::Composite(vec![ Scope::GlobalVariable, Scope::Callable(None), + Scope::POU, ]))], } } @@ -180,6 +186,10 @@ impl ScopeStack { f(); self.pop(); } + + pub fn print_dump(&self) { + println!("{:#?}", self); + } } impl ScopeStack { @@ -226,17 +236,25 @@ impl<'i> NameResolver<'i> { self.scope.pop(); } - fn get_possible_replacement( + /// tries to apply a possible replacement for the given operator + /// returns true if a replacement was applied + fn apply_possible_replacement( &mut self, operator: &AstNode, parameters: Option<&AstNode>, - ) -> Option { + full_statement: &AstNode, + ) -> bool { let builtin = operator.get_flat_reference_name().and_then(|rn| builtins::get_builtin(rn)); - - builtin.map(|b| b.get_replacement()).and_then(|r| { - let parameters = parameters.map(|it| it.get_as_list()).unwrap_or_default(); - r.and_then(|f| f(parameters.as_slice(), &mut self.id_provider)) - }) + let did_apply = builtin.map(|b| b.get_annotation()).and_then(|r| { + r.map(|f| { + f(&mut self.annotations, full_statement, operator, parameters, &mut self.id_provider); + matches!( + self.annotations.get(full_statement), + Some(StatementAnnotation::ReplacementAst { .. }) + ) + }) + }); + did_apply.unwrap_or(false) } } @@ -453,15 +471,7 @@ impl AstVisitor for NameResolver<'_> { } fn visit_call_statement(&mut self, stmt: &plc_ast::ast::CallStatement, node: &plc_ast::ast::AstNode) { - //lets see if this is builtin-function that needs to be replaced - if let Some(replacement) = - self.get_possible_replacement(&stmt.operator, stmt.parameters.as_deref()) - { - // this callstatement wants to be replaced with the given ast. - self.visit(&replacement); - self.annotations.annotate(&node, StatementAnnotation::ReplacementAst { statement: replacement }); - return; - } + // prioritize functions here self.walk_with_scope(&stmt.operator, ScopingStrategy::Hierarchical(Scope::Callable(None))); @@ -508,6 +518,19 @@ impl AstVisitor for NameResolver<'_> { } } } + + //lets see if this is builtin-function that needs to be replaced + if self.apply_possible_replacement(&stmt.operator, stmt.parameters.as_deref(), node) { + if let Some(StatementAnnotation::ReplacementAst { statement: replacement }) = + self.annotations.take(node) + { + //visit the new ast + self.visit(&replacement); + //re-attach the annotation + self.annotations + .annotate(&node, StatementAnnotation::ReplacementAst { statement: replacement }); + } + } } fn visit_paren_expression(&mut self, inner: &plc_ast::ast::AstNode, node: &plc_ast::ast::AstNode) { diff --git a/src/resolver.rs b/src/resolver.rs index 8d51d1e91e..a73a58e14e 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -1760,7 +1760,7 @@ impl<'i> TypeAnnotator<'i> { if let Some(annotation) = builtins::get_builtin(&operator_qualifier).and_then(BuiltIn::get_annotation) { - annotation(self, statement, operator, parameters_stmt, ctx.to_owned()); + // annotation(self, statement, operator, parameters_stmt, ctx.to_owned()); } else { //This is skipped for builtins that provide their own annotation-logic self.annotate_call_statement(operator, parameters_stmt, &ctx); diff --git a/src/resolver/post_annotator.rs b/src/resolver/post_annotator.rs index 0a2279d034..92aee75cf8 100644 --- a/src/resolver/post_annotator.rs +++ b/src/resolver/post_annotator.rs @@ -215,18 +215,20 @@ impl AstVisitor for PostAnnotator<'_> { } } - fn visit_call_statement(&mut self, stmt: &CallStatement, node: &AstNode) { - // this is a bold optimization to only look for replacement ASTs in calls!!! :-/ - if let Some(StatementAnnotation::ReplacementAst { statement: replacement}) = self.annotations.take(node) { - replacement.walk(self); - //re-attached replacement ast - self.annotations.annotate(node, StatementAnnotation::ReplacementAst { statement: replacement }); - }else{ - stmt.walk(self); - - xxxx // Why is this worse!!`!`!` - } - } + //TODO: why does this cause several tests to fail? + // fn visit_call_statement(&mut self, stmt: &CallStatement, node: &AstNode) { + // // this is a bold optimization to only look for replacement ASTs in calls!!! :-/ + // if let Some(StatementAnnotation::ReplacementAst { statement: replacement}) = self.annotations.take(node) { + // replacement.walk(self); + // // copy the top level annotation back to the original one + // self.annotations.copy_annotation(&replacement, node); + // //re-attached replacement ast + // self.annotations.annotate(node, StatementAnnotation::ReplacementAst { statement: replacement }); + // }else{ + // stmt.walk(self); + + // } + // } fn visit_literal(&mut self, stmt: &plc_ast::literals::AstLiteral, node: &AstNode) { stmt.walk(self); diff --git a/src/resolver/tests/resolve_expressions_tests.rs b/src/resolver/tests/resolve_expressions_tests.rs index 7304164b77..ffd682eb67 100644 --- a/src/resolver/tests/resolve_expressions_tests.rs +++ b/src/resolver/tests/resolve_expressions_tests.rs @@ -3897,9 +3897,9 @@ fn passing_a_function_as_param_correctly_resolves_as_variable() { // THEN the type of the parameter resolves to the original function type if let AstNode { stmt: AstStatement::CallStatement(CallStatement { parameters, .. }), .. } = call_stmt { let parameters = flatten_expression_list(parameters.as_ref().as_ref().unwrap()); - assert_type_and_hint!(&annotations, &index, parameters[1], DINT_TYPE, Some(DINT_TYPE)); - assert_type_and_hint!(&annotations, &index, parameters[2], DINT_TYPE, Some(DINT_TYPE)); - assert_type_and_hint!(&annotations, &index, parameters[3], DINT_TYPE, Some(DINT_TYPE)); + assert_type_and_hint!(&annotations, &index, parameters[1], DINT_TYPE, /*same*/None); + assert_type_and_hint!(&annotations, &index, parameters[2], DINT_TYPE, /*same*/None); + assert_type_and_hint!(&annotations, &index, parameters[3], DINT_TYPE, /*same*/None); } else { unreachable!() } @@ -4364,11 +4364,11 @@ fn mux_generic_with_strings_is_annotated_correctly() { // MUX(2, str2, str3, str4) // ~ - assert_type_and_hint!(&annotations, &index, list[0], "DINT", Some("DINT")); + assert_type_and_hint!(&annotations, &index, list[0], "DINT", None /*same*/); // MUX(2, str2, str3, str4) // ~~~~ - assert_type_and_hint!(&annotations, &index, list[1], "STRING", Some("STRING")); + assert_type_and_hint!(&annotations, &index, list[1], "STRING", None /*same*/); // the reference "str2" on its own has no type-hint to string assert_type_and_hint!(&annotations, &index, &unit.implementations[0].statements[1], "STRING", None);