@@ -186,7 +186,7 @@ function instantiate
186186algorithm
187187 node := partialInstClass(node);
188188 node := expandClass(node);
189- node := instClass(node, Modifier . NOMOD (), NFComponent . DEFAULT_ATTR , true , parent);
189+ node := instClass(node, Modifier . NOMOD (), NFComponent . DEFAULT_ATTR , true , 0 , parent);
190190end instantiate;
191191
192192function expand
@@ -705,6 +705,7 @@ function instClass
705705 input Modifier modifier;
706706 input output Component . Attributes attributes = NFComponent . DEFAULT_ATTR ;
707707 input Boolean useBinding;
708+ input Integer instLevel;
708709 input InstNode parent = InstNode . EMPTY_NODE ();
709710protected
710711 Class cls;
@@ -721,7 +722,7 @@ algorithm
721722 fail();
722723 end if ;
723724
724- (attributes, node) := instClassDef(cls, modifier, attributes, useBinding, node, parent);
725+ (attributes, node) := instClassDef(cls, modifier, attributes, useBinding, node, parent, instLevel );
725726end instClass;
726727
727728function instClassDef
@@ -731,6 +732,7 @@ function instClassDef
731732 input Boolean useBinding;
732733 input output InstNode node;
733734 input InstNode parent;
735+ input Integer instLevel;
734736protected
735737 InstNode par, base_node;
736738 Class inst_cls;
@@ -768,7 +770,7 @@ algorithm
768770 applyModifier(mod, cls_tree, InstNode . name(node));
769771
770772 // Apply element redeclares.
771- ClassTree . mapRedeclareChains(cls_tree, redeclareElements);
773+ ClassTree . mapRedeclareChains(cls_tree, function redeclareElements(instLevel = instLevel) );
772774 // Redeclare classes with redeclare modifiers. Redeclared components could
773775 // also be handled here, but since each component is only instantiated once
774776 // it's more efficient to apply the redeclare when instantiating them instead.
@@ -777,12 +779,12 @@ algorithm
777779 // Instantiate the extends nodes.
778780 ClassTree . mapExtends(cls_tree,
779781 function instExtends(attributes = attributes, useBinding = useBinding,
780- visibility = ExtendsVisibility . PUBLIC ));
782+ visibility = ExtendsVisibility . PUBLIC , instLevel = instLevel + 1 ));
781783
782784 // Instantiate local components.
783785 ClassTree . applyLocalComponents(cls_tree,
784786 function instComponent(attributes = attributes, innerMod = Modifier . NOMOD (),
785- originalAttr = NONE (), useBinding = useBinding));
787+ originalAttr = NONE (), useBinding = useBinding, instLevel = instLevel + 1 ));
786788
787789 // Remove duplicate elements.
788790 cls_tree := ClassTree . replaceDuplicates(cls_tree);
@@ -804,7 +806,7 @@ algorithm
804806 attributes := mergeDerivedAttributes(attrs, attributes, parent);
805807
806808 // Instantiate the base class and update the nodes.
807- (base_node, attributes) := instClass(base_node, mod, attributes, useBinding, par);
809+ (base_node, attributes) := instClass(base_node, mod, attributes, useBinding, instLevel, par);
808810 cls. baseClass := base_node;
809811 cls. attributes := attributes;
810812 cls. dims := arrayCopy(cls. dims);
@@ -848,7 +850,7 @@ algorithm
848850 node := InstNode . replaceClass(Class . NOT_INSTANTIATED (), node);
849851 node := InstNode . setNodeType(InstNodeType . NORMAL_CLASS (), node);
850852 node := expand(node);
851- node := instClass(node, outerMod, attributes, useBinding, parent);
853+ node := instClass(node, outerMod, attributes, useBinding, instLevel, parent);
852854 updateComponentType(parent, node);
853855 then
854856 ();
@@ -995,6 +997,7 @@ function instExtends
995997 input Component . Attributes attributes;
996998 input Boolean useBinding;
997999 input ExtendsVisibility visibility;
1000+ input Integer instLevel;
9981001protected
9991002 Class cls, inst_cls;
10001003 ClassTree cls_tree;
@@ -1023,11 +1026,12 @@ algorithm
10231026 end if ;
10241027
10251028 ClassTree . mapExtends(cls_tree,
1026- function instExtends(attributes = attributes, useBinding = useBinding, visibility = vis));
1029+ function instExtends(attributes = attributes, useBinding = useBinding,
1030+ visibility = vis, instLevel = instLevel));
10271031
10281032 ClassTree . applyLocalComponents(cls_tree,
10291033 function instComponent(attributes = attributes, innerMod = Modifier . NOMOD (),
1030- originalAttr = NONE (), useBinding = useBinding));
1034+ originalAttr = NONE (), useBinding = useBinding, instLevel = instLevel ));
10311035 then
10321036 ();
10331037
@@ -1037,7 +1041,7 @@ algorithm
10371041 vis := ExtendsVisibility . DERIVED_PROTECTED ;
10381042 end if ;
10391043
1040- cls. baseClass := instExtends(cls. baseClass, attributes, useBinding, vis);
1044+ cls. baseClass := instExtends(cls. baseClass, attributes, useBinding, vis, instLevel );
10411045 node := InstNode . updateClass(cls, node);
10421046 then
10431047 ();
@@ -1160,17 +1164,23 @@ end redeclareClasses;
11601164
11611165function redeclareElements
11621166 input list< Mutable < InstNode >> chain;
1167+ input Integer instLevel;
11631168protected
11641169 InstNode node;
11651170 Mutable < InstNode > node_ptr;
11661171algorithm
11671172 node := Mutable . access(listHead(chain));
1173+ node_ptr := listHead(chain);
11681174
11691175 if InstNode . isClass(node) then
1170- node_ptr := redeclareClassElement(cls_ptr for cls_ptr in chain);
1176+ for cls_ptr in listRest(chain) loop
1177+ node_ptr := redeclareClassElement(cls_ptr, node_ptr);
1178+ end for ;
11711179 node := Mutable . access(node_ptr);
11721180 else
1173- node_ptr := redeclareComponentElement(comp_ptr for comp_ptr in chain);
1181+ for comp_ptr in listRest(chain) loop
1182+ node_ptr := redeclareComponentElement(comp_ptr, node_ptr, instLevel);
1183+ end for ;
11741184 node := Mutable . access(node_ptr);
11751185 end if ;
11761186
@@ -1195,14 +1205,15 @@ end redeclareClassElement;
11951205function redeclareComponentElement
11961206 input Mutable < InstNode > redeclareComp;
11971207 input Mutable < InstNode > replaceableComp;
1208+ input Integer instLevel;
11981209 output Mutable < InstNode > outComp;
11991210protected
12001211 InstNode rdcl_node, repl_node;
12011212algorithm
12021213 rdcl_node := Mutable . access(redeclareComp);
12031214 repl_node := Mutable . access(replaceableComp);
1204- instComponent(repl_node, NFComponent . DEFAULT_ATTR , Modifier . NOMOD (), true );
1205- redeclareComponent(rdcl_node, repl_node, Modifier . NOMOD (), Modifier . NOMOD (), NFComponent . DEFAULT_ATTR , rdcl_node);
1215+ instComponent(repl_node, NFComponent . DEFAULT_ATTR , Modifier . NOMOD (), true , instLevel );
1216+ redeclareComponent(rdcl_node, repl_node, Modifier . NOMOD (), Modifier . NOMOD (), NFComponent . DEFAULT_ATTR , rdcl_node, instLevel );
12061217 outComp := Mutable . create(rdcl_node);
12071218end redeclareComponentElement;
12081219
@@ -1301,6 +1312,7 @@ function instComponent
13011312 input Component . Attributes attributes "Attributes to be propagated to the component." ;
13021313 input Modifier innerMod;
13031314 input Boolean useBinding "Ignore the component's binding if false." ;
1315+ input Integer instLevel;
13041316 input Option < Component . Attributes > originalAttr = NONE ();
13051317protected
13061318 Component comp;
@@ -1317,6 +1329,8 @@ algorithm
13171329
13181330 // Skip already instantiated components.
13191331 if not Component . isDefinition(comp) then
1332+ // An already instantiated component might be due to an instantiation loop, check it.
1333+ checkRecursiveDefinition(Component . classInstance(comp), comp_node, limitReached = false );
13201334 return ;
13211335 end if ;
13221336
@@ -1325,7 +1339,7 @@ algorithm
13251339 if Modifier . isRedeclare(outer_mod) then
13261340 checkOuterComponentMod(outer_mod, def, comp_node);
13271341 instComponentDef(def, Modifier . NOMOD (), Modifier . NOMOD (), NFComponent . DEFAULT_ATTR ,
1328- useBinding, comp_node, parent, originalAttr, isRedeclared = true );
1342+ useBinding, comp_node, parent, instLevel, originalAttr, isRedeclared = true );
13291343
13301344 Modifier . REDECLARE (element = rdcl_node, mod = outer_mod) := outer_mod;
13311345
@@ -1337,9 +1351,9 @@ algorithm
13371351
13381352 outer_mod := Modifier . merge(InstNode . getModifier(rdcl_node), outer_mod);
13391353 InstNode . setModifier(outer_mod, rdcl_node);
1340- redeclareComponent(rdcl_node, node, Modifier . NOMOD (), cc_mod, attributes, node);
1354+ redeclareComponent(rdcl_node, node, Modifier . NOMOD (), cc_mod, attributes, node, instLevel );
13411355 else
1342- instComponentDef(def, outer_mod, cc_mod, attributes, useBinding, comp_node, parent, originalAttr);
1356+ instComponentDef(def, outer_mod, cc_mod, attributes, useBinding, comp_node, parent, instLevel, originalAttr);
13431357 end if ;
13441358end instComponent;
13451359
@@ -1351,6 +1365,7 @@ function instComponentDef
13511365 input Boolean useBinding;
13521366 input InstNode node;
13531367 input InstNode parent;
1368+ input Integer instLevel;
13541369 input Option < Component . Attributes > originalAttr = NONE ();
13551370 input Boolean isRedeclared = false ;
13561371algorithm
@@ -1403,7 +1418,7 @@ algorithm
14031418
14041419 // Instantiate the type of the component.
14051420 (ty_node, ty_attr) := instTypeSpec(component. typeSpec, mod, attr,
1406- useBinding and not Binding . isBound(binding), parent, node, info);
1421+ useBinding and not Binding . isBound(binding), parent, node, info, instLevel );
14071422 ty := InstNode . getClass(ty_node);
14081423
14091424 // Update the component's variability based on its type (e.g. Integer is discrete).
@@ -1491,6 +1506,7 @@ function redeclareComponent
14911506 input Modifier constrainingMod;
14921507 input Component . Attributes outerAttr;
14931508 input InstNode redeclaredNode;
1509+ input Integer instLevel;
14941510protected
14951511 Component orig_comp, rdcl_comp, new_comp;
14961512 Binding binding, condition;
@@ -1513,7 +1529,7 @@ algorithm
15131529 rdcl_node := InstNode . setNodeType(rdcl_type, redeclareNode);
15141530 rdcl_node := InstNode . copyInstancePtr(originalNode, rdcl_node);
15151531 rdcl_node := InstNode . updateComponent(InstNode . component(redeclareNode), rdcl_node);
1516- instComponent(rdcl_node, outerAttr, constrainingMod, true , SOME (Component . getAttributes(orig_comp)));
1532+ instComponent(rdcl_node, outerAttr, constrainingMod, true , instLevel, SOME (Component . getAttributes(orig_comp)));
15171533 rdcl_comp := InstNode . component(rdcl_node);
15181534
15191535 new_comp := match (orig_comp, rdcl_comp)
@@ -1855,15 +1871,21 @@ function instTypeSpec
18551871 input InstNode scope;
18561872 input InstNode parent;
18571873 input SourceInfo info;
1874+ input Integer instLevel;
18581875 output InstNode node;
18591876 output Component . Attributes outAttributes;
18601877algorithm
18611878 node := match typeSpec
18621879 case Absyn . TPATH ()
18631880 algorithm
18641881 node := Lookup . lookupClassName(typeSpec. path, scope, info);
1882+
1883+ if instLevel >= 100 then
1884+ checkRecursiveDefinition(node, parent, limitReached = true );
1885+ end if ;
1886+
18651887 node := expand(node);
1866- (node, outAttributes) := instClass(node, modifier, attributes, useBinding, parent);
1888+ (node, outAttributes) := instClass(node, modifier, attributes, useBinding, instLevel, parent);
18671889 then
18681890 node;
18691891
@@ -1876,6 +1898,48 @@ algorithm
18761898 end match;
18771899end instTypeSpec;
18781900
1901+ function checkRecursiveDefinition
1902+ "Prints an error if a component causes a loop in the instance tree, for
1903+ example because it has the same type as one of its parents. If the depth
1904+ limit of the instance tree is reached, indicated by limitReached = true, then
1905+ some error is always given. Otherwise an error is only given if an actual
1906+ issue can be detected."
1907+ input InstNode componentType;
1908+ input InstNode component;
1909+ input Boolean limitReached;
1910+ protected
1911+ InstNode parent = InstNode . parent(component);
1912+ InstNode parent_type;
1913+ algorithm
1914+ // Functions can contain instances of a parent, e.g. in equalityConstraint
1915+ // functions, so skip this check for functions.
1916+ if not Class . isFunction(InstNode . getClass(parent)) then
1917+ // Check whether any parent of the component has the same type as the component.
1918+ while not InstNode . isEmpty(parent) loop
1919+ parent_type := InstNode . classScope(parent);
1920+
1921+ // Check equality by comparing the definitions, because comparing the
1922+ // nodes or instances in the nodes is unreliable due to instantiation
1923+ // creating new nodes.
1924+ if referenceEq(InstNode . definition(componentType), InstNode . definition(parent_type)) then
1925+ Error . addSourceMessage(Error . RECURSIVE_DEFINITION ,
1926+ {InstNode . name(component), InstNode . name(InstNode . classScope(InstNode . parent(component)))},
1927+ InstNode . info(component));
1928+ fail();
1929+ end if ;
1930+
1931+ parent := InstNode . parent(parent);
1932+ end while ;
1933+ end if ;
1934+
1935+ if limitReached then
1936+ // If we couldn't determine the exact cause of the recursion, print a generic error.
1937+ Error . addSourceMessage(Error . INST_RECURSION_LIMIT_REACHED ,
1938+ {Absyn . pathString(InstNode . scopePath(component))}, InstNode . info(component));
1939+ fail();
1940+ end if ;
1941+ end checkRecursiveDefinition;
1942+
18791943function instDimension
18801944 input output Dimension dimension;
18811945 input InstNode scope;
@@ -3039,7 +3103,7 @@ algorithm
30393103 // not part of the flat class.
30403104 if InstNode . isComponent(n) then
30413105 // The components shouldn't have been instantiated yet, so do it here.
3042- instComponent(n, NFComponent . DEFAULT_ATTR , Modifier . NOMOD (), true );
3106+ instComponent(n, NFComponent . DEFAULT_ATTR , Modifier . NOMOD (), true , 0 );
30433107
30443108 // If the component's class has a missingInnerMessage annotation, use it
30453109 // to give a diagnostic message.
0 commit comments