@@ -13,13 +13,16 @@ use crate::named_entity::{Signature, *};
1313use crate :: { ast, named_entity, HasTokenSpan } ;
1414use analyze:: * ;
1515use fnv:: FnvHashMap ;
16+ use itertools:: Itertools ;
1617use std:: collections:: hash_map:: Entry ;
18+ use std:: collections:: HashSet ;
1719
1820impl Declaration {
1921 pub fn is_allowed_in_context ( & self , parent : & AnyEntKind ) -> bool {
2022 use Declaration :: * ;
2123 use ObjectClass :: * ;
2224 match parent {
25+ // LRM: block_declarative_item
2326 AnyEntKind :: Design ( Design :: Architecture ( ..) )
2427 | AnyEntKind :: Concurrent ( Some ( Concurrent :: Block | Concurrent :: Generate ) ) => matches ! (
2528 self ,
@@ -37,10 +40,13 @@ impl Declaration {
3740 | Use ( _)
3841 | Package ( _)
3942 | Configuration ( _)
43+ | View ( _)
4044 ) ,
45+ // LRM: configuration_declarative_item
4146 AnyEntKind :: Design ( Design :: Configuration ) => {
4247 matches ! ( self , Use ( _) | Attribute ( ast:: Attribute :: Specification ( _) ) )
4348 }
49+ // LRM: entity_declarative_item
4450 AnyEntKind :: Design ( Design :: Entity ( ..) ) => matches ! (
4551 self ,
4652 Object ( _)
@@ -53,7 +59,9 @@ impl Declaration {
5359 | SubprogramBody ( _)
5460 | Use ( _)
5561 | Package ( _)
62+ | View ( _)
5663 ) ,
64+ // LRM: package_body_declarative_item
5765 AnyEntKind :: Design ( Design :: PackageBody | Design :: UninstPackage ( ..) )
5866 | AnyEntKind :: Overloaded (
5967 Overloaded :: SubprogramDecl ( _)
@@ -77,6 +85,7 @@ impl Declaration {
7785 | Use ( _)
7886 | Package ( _)
7987 ) ,
88+ // LRM: package_declarative_item
8089 AnyEntKind :: Design ( Design :: Package ( ..) ) => matches ! (
8190 self ,
8291 Object ( _)
@@ -89,6 +98,7 @@ impl Declaration {
8998 | SubprogramInstantiation ( _)
9099 | Use ( _)
91100 | Package ( _)
101+ | View ( _)
92102 ) ,
93103 _ => {
94104 // AnyEntKind::Library is used in tests for a generic declarative region
@@ -297,9 +307,13 @@ impl<'a> AnalyzeContext<'a> {
297307 return Err ( EvalError :: Unknown ) ;
298308 }
299309 }
300- ResolvedName :: Final ( _) => {
301- // @TODO some of these can probably be aliased
302- return Err ( EvalError :: Unknown ) ;
310+ ResolvedName :: Final ( ent) => {
311+ if let Some ( ent) = ViewEnt :: from_any ( ent) {
312+ AnyEntKind :: View ( * ent. subtype ( ) )
313+ } else {
314+ // @TODO some of these can probably be aliased
315+ return Err ( EvalError :: Unknown ) ;
316+ }
303317 }
304318 }
305319 } ;
@@ -566,7 +580,6 @@ impl<'a> AnalyzeContext<'a> {
566580 Declaration :: Use ( ref mut use_clause) => {
567581 self . analyze_use_clause ( scope, use_clause, diagnostics) ?;
568582 }
569-
570583 Declaration :: Package ( ref mut instance) => {
571584 let ent = self . arena . define (
572585 & mut instance. ident ,
@@ -586,12 +599,79 @@ impl<'a> AnalyzeContext<'a> {
586599 }
587600 }
588601 Declaration :: Configuration ( ..) => { }
602+ Declaration :: View ( view) => {
603+ if let Some ( view) =
604+ as_fatal ( self . analyze_view_declaration ( scope, parent, view, diagnostics) ) ?
605+ {
606+ scope. add ( view, diagnostics) ;
607+ }
608+ }
589609 Declaration :: Type ( ..) => unreachable ! ( "Handled elsewhere" ) ,
590610 } ;
591611
592612 Ok ( ( ) )
593613 }
594614
615+ /// Analyzes a mode view declaration.
616+ /// * Checks that the type of the view declaration is a record type
617+ /// * Checks that all elements are associated in the view
618+ fn analyze_view_declaration (
619+ & self ,
620+ scope : & Scope < ' a > ,
621+ parent : EntRef < ' a > ,
622+ view : & mut ModeViewDeclaration ,
623+ diagnostics : & mut dyn DiagnosticHandler ,
624+ ) -> EvalResult < EntRef < ' a > > {
625+ let typ = self . resolve_subtype_indication ( scope, & mut view. typ , diagnostics) ?;
626+ let record_region = match typ. type_mark ( ) . kind ( ) {
627+ Type :: Record ( region) => region,
628+ _ => {
629+ let diag = Diagnostic :: new (
630+ & view. typ . type_mark ,
631+ format ! (
632+ "The type of a view must be a record type, not {}" ,
633+ typ. type_mark( ) . describe( )
634+ ) ,
635+ ErrorCode :: TypeMismatch ,
636+ )
637+ . opt_related (
638+ typ. type_mark ( ) . decl_pos . as_ref ( ) ,
639+ format ! ( "{} declared here" , typ. type_mark( ) . describe( ) ) ,
640+ ) ;
641+ bail ! ( diagnostics, diag) ;
642+ }
643+ } ;
644+ let mut unassociated: HashSet < _ > = record_region. elems . iter ( ) . collect ( ) ;
645+ for element in view. elements . iter_mut ( ) {
646+ for name in element. names . items . iter_mut ( ) {
647+ let desi = Designator :: Identifier ( name. item . item . clone ( ) ) ;
648+ let Some ( record_element) = record_region. lookup ( & desi) else {
649+ diagnostics. push ( Diagnostic :: new (
650+ & name. item . pos ,
651+ format ! ( "Not a part of {}" , typ. type_mark( ) . describe( ) ) ,
652+ ErrorCode :: Unresolved ,
653+ ) ) ;
654+ continue ;
655+ } ;
656+ name. set_unique_reference ( & record_element) ;
657+ unassociated. remove ( & record_element) ;
658+ }
659+ }
660+ if !unassociated. is_empty ( ) {
661+ diagnostics. add (
662+ & view. ident . tree ,
663+ pretty_format_unassociated_message ( & unassociated) ,
664+ ErrorCode :: Unassociated ,
665+ ) ;
666+ }
667+ Ok ( self . arena . define (
668+ & mut view. ident ,
669+ parent,
670+ AnyEntKind :: View ( typ) ,
671+ Some ( view. span ) ,
672+ ) )
673+ }
674+
595675 fn find_deferred_constant_declaration (
596676 & self ,
597677 scope : & Scope < ' a > ,
@@ -792,41 +872,7 @@ impl<'a> AnalyzeContext<'a> {
792872 )
793873 }
794874 InterfaceDeclaration :: Object ( ref mut object_decl) => {
795- let subtype = self . resolve_subtype_indication (
796- scope,
797- & mut object_decl. subtype_indication ,
798- diagnostics,
799- ) ;
800-
801- if let Some ( ref mut expression) = object_decl. expression {
802- if let Ok ( ref subtype) = subtype {
803- self . expr_pos_with_ttyp (
804- scope,
805- subtype. type_mark ( ) ,
806- & expression. pos ,
807- & mut expression. item ,
808- diagnostics,
809- ) ?;
810- } else {
811- self . expr_unknown_ttyp ( scope, expression, diagnostics) ?
812- }
813- }
814-
815- let subtype = subtype?;
816- self . arena . define (
817- & mut object_decl. ident ,
818- parent,
819- AnyEntKind :: Object ( Object {
820- class : object_decl. class ,
821- iface : Some ( ObjectInterface :: new (
822- object_decl. list_type ,
823- object_decl. mode ,
824- ) ) ,
825- subtype,
826- has_default : object_decl. expression . is_some ( ) ,
827- } ) ,
828- None ,
829- )
875+ self . analyze_interface_object_declaration ( scope, parent, object_decl, diagnostics) ?
830876 }
831877 InterfaceDeclaration :: Type ( ref mut ident) => {
832878 let typ = TypeEnt :: from_any ( self . arena . define (
@@ -880,6 +926,91 @@ impl<'a> AnalyzeContext<'a> {
880926 Ok ( ent)
881927 }
882928
929+ pub fn analyze_interface_object_declaration (
930+ & self ,
931+ scope : & Scope < ' a > ,
932+ parent : EntRef < ' a > ,
933+ object_decl : & mut InterfaceObjectDeclaration ,
934+ diagnostics : & mut dyn DiagnosticHandler ,
935+ ) -> EvalResult < EntRef < ' a > > {
936+ match & mut object_decl. mode {
937+ ModeIndication :: Simple ( mode) => {
938+ let ( subtype, class) =
939+ self . analyze_simple_mode_indication ( scope, mode, diagnostics) ?;
940+ Ok ( self . arena . define (
941+ & mut object_decl. ident ,
942+ parent,
943+ AnyEntKind :: Object ( Object {
944+ class,
945+ iface : Some ( ObjectInterface :: simple (
946+ object_decl. list_type ,
947+ mode. mode . unwrap_or_default ( ) ,
948+ ) ) ,
949+ subtype,
950+ has_default : mode. expression . is_some ( ) ,
951+ } ) ,
952+ None ,
953+ ) )
954+ }
955+ ModeIndication :: View ( view) => {
956+ let resolved =
957+ self . name_resolve ( scope, & view. name . pos , & mut view. name . item , diagnostics) ?;
958+ let view_ent = self . resolve_view_ent ( & resolved, diagnostics, & view. name . pos ) ?;
959+ if let Some ( ast_declared_subtype) = & mut view. subtype_indication {
960+ let declared_subtype =
961+ self . resolve_subtype_indication ( scope, ast_declared_subtype, diagnostics) ?;
962+ if declared_subtype. type_mark ( ) != view_ent. subtype ( ) . type_mark ( ) {
963+ bail ! (
964+ diagnostics,
965+ Diagnostic :: new(
966+ & ast_declared_subtype. type_mark,
967+ "Specified subtype must match the subtype declared for the view" ,
968+ ErrorCode :: TypeMismatch
969+ )
970+ ) ;
971+ }
972+ }
973+ Ok ( self . arena . define (
974+ & mut object_decl. ident ,
975+ parent,
976+ AnyEntKind :: Object ( Object {
977+ class : ObjectClass :: Signal ,
978+ iface : Some ( ObjectInterface :: Port ( InterfaceMode :: View ( view_ent) ) ) ,
979+ subtype : * view_ent. subtype ( ) ,
980+ has_default : false ,
981+ } ) ,
982+ None ,
983+ ) )
984+ }
985+ }
986+ }
987+
988+ pub fn analyze_simple_mode_indication (
989+ & self ,
990+ scope : & Scope < ' a > ,
991+ mode : & mut SimpleModeIndication ,
992+ diagnostics : & mut dyn DiagnosticHandler ,
993+ ) -> EvalResult < ( Subtype < ' a > , ObjectClass ) > {
994+ let subtype =
995+ self . resolve_subtype_indication ( scope, & mut mode. subtype_indication , diagnostics) ;
996+
997+ if let Some ( ref mut expression) = mode. expression {
998+ if let Ok ( ref subtype) = subtype {
999+ self . expr_pos_with_ttyp (
1000+ scope,
1001+ subtype. type_mark ( ) ,
1002+ & expression. pos ,
1003+ & mut expression. item ,
1004+ diagnostics,
1005+ ) ?;
1006+ } else {
1007+ self . expr_unknown_ttyp ( scope, expression, diagnostics) ?
1008+ }
1009+ }
1010+
1011+ Ok ( ( subtype?, mode. class ) )
1012+ }
1013+
8831014 pub fn analyze_interface_list (
8841015 & self ,
8851016 scope : & Scope < ' a > ,
@@ -1020,6 +1151,7 @@ fn get_entity_class(ent: EntRef) -> Option<EntityClass> {
10201151 Design :: InterfacePackageInstance ( _) => None ,
10211152 Design :: Context ( _) => None ,
10221153 } ,
1154+ AnyEntKind :: View ( _) => None ,
10231155 }
10241156}
10251157
@@ -1043,3 +1175,46 @@ fn find_full_type_definition<'a>(
10431175 }
10441176 None
10451177}
1178+
1179+ const UNASSOCIATED_DISPLAY_THRESHOLD : usize = 3 ;
1180+
1181+ /// Pretty formats a hash set with unassociated record elements.
1182+ /// This is for an improved user experience.
1183+ /// The returned message has the format "Missing association of x".
1184+ /// * If there is only one element, the message becomes "Missing association of element the_element"
1185+ /// * If there are more elements, the message becomes
1186+ /// "Missing association of element the_element1, the_element2 and the_element3"
1187+ /// * If there are more elements than [UNASSOCIATED_DISPLAY_THRESHOLD], the message will be truncated
1188+ /// to "Missing association of element the_element1, the_element2, the_element3 and 17 more"
1189+ fn pretty_format_unassociated_message ( unassociated : & HashSet < & RecordElement > ) -> String {
1190+ assert ! (
1191+ !unassociated. is_empty( ) ,
1192+ "Should never be called with an empty set"
1193+ ) ;
1194+ let mut as_string_vec = unassociated
1195+ . iter ( )
1196+ . sorted_by_key ( |el| el. decl_pos ( ) )
1197+ . map ( |el| el. designator ( ) . describe ( ) )
1198+ . collect_vec ( ) ;
1199+ let description = if as_string_vec. len ( ) == 1 {
1200+ as_string_vec. pop ( ) . unwrap ( )
1201+ } else if as_string_vec. len ( ) > UNASSOCIATED_DISPLAY_THRESHOLD {
1202+ let mut desc = as_string_vec[ ..UNASSOCIATED_DISPLAY_THRESHOLD ] . join ( ", " ) ;
1203+ desc. push_str ( " and " ) ;
1204+ desc. push_str ( & ( as_string_vec. len ( ) - UNASSOCIATED_DISPLAY_THRESHOLD ) . to_string ( ) ) ;
1205+ desc. push_str ( " more" ) ;
1206+ desc
1207+ } else {
1208+ // len > 1, therefore we always have a last element
1209+ let last = as_string_vec. pop ( ) . unwrap ( ) ;
1210+ let mut desc = as_string_vec. join ( ", " ) ;
1211+ desc. push_str ( " and " ) ;
1212+ desc. push_str ( & last) ;
1213+ desc
1214+ } ;
1215+ if unassociated. len ( ) == 1 {
1216+ format ! ( "Missing association of element {}" , description)
1217+ } else {
1218+ format ! ( "Missing association of elements {}" , description)
1219+ }
1220+ }
0 commit comments