Skip to content

Commit

Permalink
Handle incorrect models better in getModelInstance (#10382)
Browse files Browse the repository at this point in the history
- Try to ignore missing types.
- Treat connectors where part of the name can't be found like expandable
  connectors, to allow connectors referring to elements inside missing
  types.
  • Loading branch information
perost committed Mar 10, 2023
1 parent 2862a75 commit 9c41269
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 25 deletions.
45 changes: 30 additions & 15 deletions OMCompiler/Compiler/NFFrontEnd/NFInst.mo
Expand Up @@ -1748,21 +1748,24 @@ algorithm
mod := Modifier.propagate(mod, node, node);
(ty_node, ty_attr) := instTypeSpec(component.typeSpec, mod, attr,
useBinding and not Binding.isBound(binding), parent, node, info, instLevel, context);
ty := InstNode.getClass(ty_node);
res := Class.restriction(ty);

if not InstContext.inRedeclared(context) then
checkPartialComponent(node, attr, ty_node, Class.isPartial(ty), res, context, info);
end if;
if not InstNode.isEmpty(ty_node) then
ty := InstNode.getClass(ty_node);
res := Class.restriction(ty);

if not InstContext.inRedeclared(context) then
checkPartialComponent(node, attr, ty_node, Class.isPartial(ty), res, context, info);
end if;

checkBindingRestriction(res, binding, node, info);
checkBindingRestriction(res, binding, node, info);

// Update some of the attributes now that we now the type of the component.
ty_attr := Attributes.updateVariability(ty_attr, ty, ty_node);
ty_attr := Attributes.updateComponentConnectorType(ty_attr, res, context, node);
// Update some of the attributes now that we now the type of the component.
ty_attr := Attributes.updateVariability(ty_attr, ty, ty_node);
ty_attr := Attributes.updateComponentConnectorType(ty_attr, res, context, node);

if not referenceEq(attr, ty_attr) then
InstNode.componentApply(node, Component.setAttributes, ty_attr);
if not referenceEq(attr, ty_attr) then
InstNode.componentApply(node, Component.setAttributes, ty_attr);
end if;
end if;
then
();
Expand Down Expand Up @@ -2000,7 +2003,7 @@ function instTypeSpec
output InstNode node;
output Attributes outAttributes;
algorithm
node := match typeSpec
node := matchcontinue typeSpec
case Absyn.TPATH()
algorithm
node := Lookup.lookupClassName(typeSpec.path, scope, context, info);
Expand All @@ -2014,13 +2017,20 @@ algorithm
then
node;

case Absyn.TPATH()
guard InstContext.inInstanceAPI(context)
algorithm
outAttributes := attributes;
then
InstNode.EMPTY_NODE();

case Absyn.TCOMPLEX()
algorithm
print("NFInst.instTypeSpec: TCOMPLEX not implemented.\n");
then
fail();

end match;
end matchcontinue;
end instTypeSpec;

function checkRecursiveDefinition
Expand Down Expand Up @@ -2321,7 +2331,10 @@ algorithm
algorithm
c.binding := instBinding(c.binding, context);
c.condition := instBinding(c.condition, context);
instExpressions(c.classInst, node, context = context);

if not InstNode.isEmpty(c.classInst) then
instExpressions(c.classInst, node, context = context);
end if;

for i in 1:arrayLength(dims) loop
dims[i] := instDimension(dims[i], context, c.info);
Expand Down Expand Up @@ -3490,7 +3503,9 @@ algorithm
Structural.markExp(Binding.getUntypedExp(condition));
end if;

updateImplicitVariability(c.classInst, eval or parentEval);
if not InstNode.isEmpty(c.classInst) then
updateImplicitVariability(c.classInst, eval or parentEval);
end if;
then
();

Expand Down
11 changes: 9 additions & 2 deletions OMCompiler/Compiler/NFFrontEnd/NFLookup.mo
Expand Up @@ -904,7 +904,7 @@ function lookupCrefInNode
input InstContext.Type context;
protected
InstNode scope;
InstNode n;
InstNode n, cls_node;
String name;
Class cls;
Boolean is_import;
Expand All @@ -929,7 +929,14 @@ algorithm
end if;

name := AbsynUtil.crefFirstIdent(cref);
cls := InstNode.getClass(scope);
cls_node := InstNode.classScope(scope);

if InstNode.isEmpty(cls_node) then
foundCref := ComponentRef.fromAbsynCref(cref, foundCref);
return;
end if;

cls := InstNode.getClass(cls_node);

try
(n, is_import) := Class.lookupElement(name, cls);
Expand Down
15 changes: 10 additions & 5 deletions OMCompiler/Compiler/NFFrontEnd/NFTyping.mo
Expand Up @@ -433,7 +433,11 @@ algorithm
typeDimensions(c.dimensions, node, c.binding, context, c.info);

// Construct the type of the component and update the node with it.
ty := typeClassType(c.classInst, c.binding, context, component);
if InstNode.isEmpty(c.classInst) then
ty := Type.UNKNOWN();
else
ty := typeClassType(c.classInst, c.binding, context, component);
end if;
ty := Type.liftArrayLeftList(ty, arrayList(c.dimensions));

if Binding.isBound(c.condition) then
Expand All @@ -447,7 +451,7 @@ algorithm
c_typed := Component.setType(ty, c);
InstNode.updateComponent(c_typed, node);

if not is_deleted then
if not is_deleted and not InstNode.isEmpty(c.classInst) then
// Check that flow/stream variables are Real.
checkComponentStreamAttribute(c.attributes.connectorType, ty, component);

Expand Down Expand Up @@ -943,7 +947,8 @@ algorithm
try
binding := typeBinding(binding, InstContext.set(context, NFInstContext.BINDING));

if not (InstContext.inAnnotation(context) and stringEq(name, "graphics")) then
if not (InstContext.inAnnotation(context) and stringEq(name, "graphics") or
InstNode.isEmpty(c.classInst)) then
binding := TypeCheck.matchBinding(binding, c.ty, name, node, context);
end if;

Expand All @@ -967,7 +972,7 @@ algorithm

InstNode.updateComponent(c, node);

if typeChildren then
if typeChildren and not InstNode.isEmpty(c.classInst) then
typeBindings(c.classInst, context);
end if;
then
Expand All @@ -981,7 +986,7 @@ algorithm
checkComponentBindingVariability(InstNode.name(component), c, c.binding, context);
end if;

if typeChildren then
if typeChildren and not InstNode.isEmpty(c.classInst) then
typeBindings(c.classInst, context);
end if;
then
Expand Down
30 changes: 27 additions & 3 deletions OMCompiler/Compiler/Script/NFApi.mo
Expand Up @@ -1005,11 +1005,18 @@ function buildInstanceTreeComponent
input Mutable<InstNode> compNode;
output InstanceTree tree;
protected
InstNode node;
InstNode node, cls_node;
InstanceTree cls;
algorithm
node := Mutable.access(compNode);
cls := buildInstanceTree(InstNode.classScope(InstNode.resolveInner(node)));
cls_node := InstNode.classScope(InstNode.resolveInner(node));

if InstNode.isEmpty(cls_node) then
cls := InstanceTree.EMPTY();
else
cls := buildInstanceTree(cls_node);
end if;

tree := InstanceTree.COMPONENT(node, cls);
end buildInstanceTreeComponent;

Expand Down Expand Up @@ -1317,13 +1324,30 @@ function dumpJSONComponentType
input Boolean isDeleted = false;
output JSON json;
algorithm
json := match (cls, ty)
json := match (cls, Type.arrayElementType(ty))
case (_, Type.ENUMERATION()) then dumpJSONEnumType(node);
case (_, Type.UNKNOWN()) then dumpJSONSCodeElementType(InstNode.definition(node));
case (InstanceTree.CLASS(), _) then dumpJSONInstanceTree(cls, node, isDeleted = isDeleted);
else dumpJSONTypeName(ty);
end match;
end dumpJSONComponentType;

function dumpJSONSCodeElementType
input SCode.Element elem;
output JSON json = JSON.makeNull();
algorithm
() := match elem
case SCode.Element.COMPONENT()
algorithm
json := JSON.addPair("name", dumpJSONPath(AbsynUtil.typeSpecPath(elem.typeSpec)), json);
json := JSON.addPair("missing", JSON.makeBoolean(true), json);
then
();

else ();
end match;
end dumpJSONSCodeElementType;

function dumpJSONEnumType
input InstNode enumNode;
output JSON json;
Expand Down
12 changes: 12 additions & 0 deletions doc/instanceAPI/getModelInstance.schema.json
Expand Up @@ -214,6 +214,18 @@
{
"description": "Builtin type",
"type": "string"
},
{
"description": "Missing type",
"type": "object",
"properties": {
"type": {
"type": "string"
},
"missing": {
"type": "boolean"
}
}
}
]
},
Expand Down
@@ -0,0 +1,72 @@
// name: GetModelInstanceMissingClass1
// keywords:
// status: correct
// cflags: -d=newInst
//
//

loadString("
model M
MissingClass x = 1.0;
AlsoMissing y[:] = {1, 2, 3};
end M;
");

getModelInstance(M, prettyPrint=true);
getErrorString();

// Result:
// true
// "{
// \"name\": \"M\",
// \"restriction\": \"model\",
// \"elements\": [
// {
// \"$kind\": \"component\",
// \"name\": \"x\",
// \"type\": {
// \"name\": \"MissingClass\",
// \"missing\": true
// },
// \"modifiers\": \"1.0\",
// \"value\": {
// \"binding\": 1
// }
// },
// {
// \"$kind\": \"component\",
// \"name\": \"y\",
// \"type\": {
// \"name\": \"AlsoMissing\",
// \"missing\": true
// },
// \"dims\": {
// \"absyn\": [
// \":\"
// ],
// \"typed\": [
// \"3\"
// ]
// },
// \"modifiers\": \"{1, 2, 3}\",
// \"value\": {
// \"binding\": [
// 1,
// 2,
// 3
// ]
// }
// }
// ],
// \"source\": {
// \"filename\": \"<interactive>\",
// \"lineStart\": 2,
// \"columnStart\": 3,
// \"lineEnd\": 5,
// \"columnEnd\": 8
// }
// }"
// "[<interactive>:3:5-3:25:writable] Error: Class MissingClass not found in scope M.
// [<interactive>:4:5-4:33:writable] Error: Class AlsoMissing not found in scope M.
// "
// endResult

0 comments on commit 9c41269

Please sign in to comment.