66import re
77from dataclasses import dataclass
88from typing import Pattern
9+ from typing import Type as T
910
1011from fortls .constants import (
1112 ASSOC_TYPE_ID ,
@@ -570,7 +571,7 @@ def __init__(self, file_ast, line_number: int, name: str, keywords: list = None)
570571 self .sline : int = line_number
571572 self .eline : int = line_number
572573 self .name : str = name
573- self .children : list = []
574+ self .children : list [ T [ Scope ]] = []
574575 self .members : list = []
575576 self .use : list [Use | Import ] = []
576577 self .keywords : list = keywords
@@ -621,7 +622,7 @@ def update_fqsn(self, enc_scope=None):
621622 def add_member (self , member ):
622623 self .members .append (member )
623624
624- def get_children (self , public_only = False ):
625+ def get_children (self , public_only = False ) -> list [ T [ FortranObj ]] :
625626 if not public_only :
626627 return copy .copy (self .children )
627628 pub_children = []
@@ -634,40 +635,40 @@ def get_children(self, public_only=False):
634635 pub_children .append (child )
635636 return pub_children
636637
637- def check_definitions (self , obj_tree ):
638+ def check_definitions (self , obj_tree ) -> list [ Diagnostic ] :
638639 """Check for definition errors in scope"""
639- FQSN_dict = {}
640+ fqsn_dict : dict [str , int ] = {}
641+ errors : list [Diagnostic ] = []
642+ known_types : dict [str , FortranObj ] = {}
643+
640644 for child in self .children :
641645 # Skip masking/double checks for interfaces
642646 if child .get_type () == INTERFACE_TYPE_ID :
643647 continue
644648 # Check other variables in current scope
645- if child .FQSN in FQSN_dict :
646- if child .sline < FQSN_dict [child .FQSN ]:
647- FQSN_dict [child .FQSN ] = child .sline - 1
649+ if child .FQSN in fqsn_dict :
650+ if child .sline < fqsn_dict [child .FQSN ]:
651+ fqsn_dict [child .FQSN ] = child .sline - 1
648652 else :
649- FQSN_dict [child .FQSN ] = child .sline - 1
650- #
653+ fqsn_dict [child .FQSN ] = child .sline - 1
654+
651655 contains_line = - 1
652- after_contains_list = (SUBROUTINE_TYPE_ID , FUNCTION_TYPE_ID )
653656 if self .get_type () in (
654657 MODULE_TYPE_ID ,
655658 SUBMODULE_TYPE_ID ,
656659 SUBROUTINE_TYPE_ID ,
657660 FUNCTION_TYPE_ID ,
658661 ):
659- if self .contains_start is None :
660- contains_line = self .eline
661- else :
662- contains_line = self .contains_start
662+ contains_line = (
663+ self .contains_start if self .contains_start is not None else self .eline
664+ )
663665 # Detect interface definitions
664666 is_interface = (
665667 self .parent is not None
666668 and self .parent .get_type () == INTERFACE_TYPE_ID
667669 and not self .is_mod_scope ()
668670 )
669- errors = []
670- known_types = {}
671+
671672 for child in self .children :
672673 if child .name .startswith ("#" ):
673674 continue
@@ -679,8 +680,9 @@ def check_definitions(self, obj_tree):
679680 if def_error is not None :
680681 errors .append (def_error )
681682 # Detect contains errors
682- if (contains_line >= child .sline ) and (
683- child .get_type (no_link = True ) in after_contains_list
683+ if contains_line >= child .sline and child .get_type (no_link = True ) in (
684+ SUBROUTINE_TYPE_ID ,
685+ FUNCTION_TYPE_ID ,
684686 ):
685687 new_diag = Diagnostic (
686688 line_number ,
@@ -689,12 +691,13 @@ def check_definitions(self, obj_tree):
689691 )
690692 errors .append (new_diag )
691693 # Skip masking/double checks for interfaces and members
692- if (self .get_type () == INTERFACE_TYPE_ID ) or (
693- child .get_type () == INTERFACE_TYPE_ID
694+ if (
695+ self .get_type () == INTERFACE_TYPE_ID
696+ or child .get_type () == INTERFACE_TYPE_ID
694697 ):
695698 continue
696699 # Check other variables in current scope
697- if child .FQSN in FQSN_dict and line_number > FQSN_dict [child .FQSN ]:
700+ if child .FQSN in fqsn_dict and line_number > fqsn_dict [child .FQSN ]:
698701 new_diag = Diagnostic (
699702 line_number ,
700703 message = f'Variable "{ child .name } " declared twice in scope' ,
@@ -703,22 +706,26 @@ def check_definitions(self, obj_tree):
703706 )
704707 new_diag .add_related (
705708 path = self .file_ast .path ,
706- line = FQSN_dict [child .FQSN ],
709+ line = fqsn_dict [child .FQSN ],
707710 message = "First declaration" ,
708711 )
709712 errors .append (new_diag )
710713 continue
711714 # Check for masking from parent scope in subroutines, functions, and blocks
712- if (self .parent is not None ) and (
713- self .get_type () in (SUBROUTINE_TYPE_ID , FUNCTION_TYPE_ID , BLOCK_TYPE_ID )
715+ if self .parent is not None and self .get_type () in (
716+ SUBROUTINE_TYPE_ID ,
717+ FUNCTION_TYPE_ID ,
718+ BLOCK_TYPE_ID ,
714719 ):
715720 parent_var = find_in_scope (self .parent , child .name , obj_tree )
716721 if parent_var is not None :
717722 # Ignore if function return variable
718- if (self .get_type () == FUNCTION_TYPE_ID ) and (
719- parent_var .FQSN == self .FQSN
723+ if (
724+ self .get_type () == FUNCTION_TYPE_ID
725+ and parent_var .FQSN == self .FQSN
720726 ):
721727 continue
728+
722729 new_diag = Diagnostic (
723730 line_number ,
724731 message = (
@@ -733,6 +740,7 @@ def check_definitions(self, obj_tree):
733740 message = "First declaration" ,
734741 )
735742 errors .append (new_diag )
743+
736744 return errors
737745
738746 def check_use (self , obj_tree ):
@@ -854,7 +862,9 @@ def require_inherit(self):
854862 return True
855863
856864 def resolve_link (self , obj_tree ):
857- def get_ancestor_interfaces (ancestor_children : list [FortranObj ]):
865+ def get_ancestor_interfaces (
866+ ancestor_children : list [Scope ],
867+ ) -> list [T [Interface ]]:
858868 interfaces = []
859869 for child in ancestor_children :
860870 if child .get_type () != INTERFACE_TYPE_ID :
0 commit comments