diff --git a/Compiler/NFFrontEnd/NFClass.mo b/Compiler/NFFrontEnd/NFClass.mo index a31e53ee533..2e82b6fcca8 100644 --- a/Compiler/NFFrontEnd/NFClass.mo +++ b/Compiler/NFFrontEnd/NFClass.mo @@ -395,6 +395,7 @@ uniontype Class case INSTANCED_CLASS() algorithm cls.restriction := res; then (); case INSTANCED_BUILTIN() algorithm cls.restriction := res; then (); case EXPANDED_CLASS() algorithm cls.restriction := res; then (); + // PARTIAL_BUILTIN is only used for predefined builtin types and not needed here. case DERIVED_CLASS() algorithm cls.restriction := res; then (); end match; end setRestriction; diff --git a/Compiler/NFFrontEnd/NFClassTree.mo b/Compiler/NFFrontEnd/NFClassTree.mo index 4c42bf0ccdc..302f631712d 100644 --- a/Compiler/NFFrontEnd/NFClassTree.mo +++ b/Compiler/NFFrontEnd/NFClassTree.mo @@ -153,6 +153,8 @@ public constant ClassTree EMPTY = ClassTree.PARTIAL_TREE(LookupTree.EMPTY(), listArray({}), listArray({}), listArray({}), listArray({}), DuplicateTree.EMPTY()); + constant ClassTree EMPTY_FLAT = ClassTree.FLAT_TREE(LookupTree.EMPTY(), + listArray({}), listArray({}), listArray({}), DuplicateTree.EMPTY()); uniontype ClassTree record PARTIAL_TREE diff --git a/Compiler/NFFrontEnd/NFFunction.mo b/Compiler/NFFrontEnd/NFFunction.mo index afbdf8b0aa6..66f57aff290 100644 --- a/Compiler/NFFrontEnd/NFFunction.mo +++ b/Compiler/NFFrontEnd/NFFunction.mo @@ -207,7 +207,7 @@ uniontype Function {Dump.printComponentRefStr(functionName)}, info); end try; - (functionRef, found_scope) := Lookup.lookupCallableName(functionName, scope, info); + (functionRef, found_scope) := Lookup.lookupFunctionName(functionName, scope, info); prefix := ComponentRef.fromNodeList(InstNode.scopeList(found_scope)); functionRef := ComponentRef.append(functionRef, prefix); end lookupFunction; @@ -258,11 +258,8 @@ uniontype Function input SourceInfo info; output Boolean specialBuiltin; protected - SCode.Element def; + SCode.Element def = InstNode.definition(fnNode); algorithm - - def := InstNode.definition(fnNode); - (fnNode, specialBuiltin) := match def local SCode.ClassDef cdef; diff --git a/Compiler/NFFrontEnd/NFInst.mo b/Compiler/NFFrontEnd/NFInst.mo index a9d7b733459..7515d28960e 100644 --- a/Compiler/NFFrontEnd/NFInst.mo +++ b/Compiler/NFFrontEnd/NFInst.mo @@ -560,10 +560,14 @@ algorithm node := match InstNode.name(builtin_ext) case "ExternalObject" algorithm - (tree, eo_ty) := makeExternalObjectType(scope, node); - tree := ClassTree.expand(tree); - c := Class.PARTIAL_BUILTIN(Type.COMPLEX(node, eo_ty), tree, Modifier.NOMOD(), - Restriction.EXTERNAL_OBJECT()); + // Construct the ComplexType for the external object. + eo_ty := makeExternalObjectType(scope, node); + // Construct the Class for the external object. We use an empty class + // tree here, since the constructor and destructor is embedded in the + // ComplexType instead. Using an empty class tree makes sure it's not + // possible to call the constructor or destructor explicitly. + c := Class.PARTIAL_BUILTIN(Type.COMPLEX(node, eo_ty), NFClassTree.EMPTY_FLAT, + Modifier.NOMOD(), Restriction.EXTERNAL_OBJECT()); node := InstNode.updateClass(c, node); then node; @@ -592,14 +596,14 @@ end expandBuiltinExtends; function makeExternalObjectType "Constructs a ComplexType for an external object, and also checks that the external object declaration is valid." - input output ClassTree tree; + input ClassTree tree; input InstNode node; - output ComplexType ty; + output ComplexType ty; protected Absyn.Path base_path; InstNode constructor = InstNode.EMPTY_NODE(), destructor = InstNode.EMPTY_NODE(); algorithm - (tree, ty) := match tree + ty := match tree case ClassTree.PARTIAL_TREE() algorithm // An external object may not contain components. @@ -664,18 +668,8 @@ algorithm {InstNode.name(node), "destructor"}, InstNode.info(node)); fail(); end if; - - // We don't need the ExternalObject extends anymore, get rid of it so we - // don't have to handle it later. - tree.exts := arrayCreate(0, InstNode.EMPTY_NODE()); - // The component array will only contain a reference node to the - // ExternalObject extends, so get rid of it too. - tree.components := arrayCreate(0, InstNode.EMPTY_NODE()); - - // Construct the ComplexType for the external object. - ty := ComplexType.EXTERNAL_OBJECT(constructor, destructor); then - (tree, ty); + ComplexType.EXTERNAL_OBJECT(constructor, destructor); end match; end makeExternalObjectType; diff --git a/Compiler/NFFrontEnd/NFLookup.mo b/Compiler/NFFrontEnd/NFLookup.mo index 2626acc497a..da735582de7 100644 --- a/Compiler/NFFrontEnd/NFLookup.mo +++ b/Compiler/NFFrontEnd/NFLookup.mo @@ -52,6 +52,7 @@ import NFInstNode.NodeTree; import NFInstNode.CachedData; import NFComponent.Component; import Subscript = NFSubscript; +import ComplexType = NFComplexType; public type MatchType = enumeration(FOUND, NOT_FOUND, PARTIAL); @@ -97,7 +98,8 @@ protected LookupState state; InstNode node; algorithm - (foundCref, foundScope, state) := lookupCref(cref, scope, info); + (foundCref, foundScope, state) := lookupCref(cref, scope, info, + Error.LOOKUP_VARIABLE_ERROR); node := ComponentRef.node(foundCref); state := fixTypenameState(node, state); LookupState.assertComponent(state, node, cref, info); @@ -137,26 +139,6 @@ algorithm LookupState.assertComponent(state, ComponentRef.node(foundCref), cref, info); end lookupLocalComponent; -function lookupCallableName - input Absyn.ComponentRef cref; - input InstNode scope "The scope to look in."; - input SourceInfo info; - output ComponentRef foundCref; - output InstNode foundScope; -protected - LookupState state; - InstNode node; -algorithm - (foundCref, foundScope, state) := lookupCref(cref, scope, info); - node := ComponentRef.node(foundCref); - - //try - LookupState.assertFunction(state, node, cref, info); - //else - //end try; - -end lookupCallableName; - function lookupFunctionName input Absyn.ComponentRef cref; input InstNode scope "The scope to look in."; @@ -167,11 +149,52 @@ protected LookupState state; InstNode node; algorithm - (foundCref, foundScope, state) := lookupCref(cref, scope, info); + (foundCref, foundScope, state) := lookupCref(cref, scope, info, + Error.LOOKUP_FUNCTION_ERROR); node := ComponentRef.node(foundCref); + (foundCref, state) := fixExternalObjectCall(node, foundCref, state); LookupState.assertFunction(state, node, cref, info); end lookupFunctionName; +function fixExternalObjectCall + "Changes calls to external objects so that the constructor is called instead, + i.e. a call such as + 'ExtObj eo = ExtObj(...)' + is changed to + 'ExtObj eo = ExtObj.constructor(...)'" + input InstNode node; + input output ComponentRef cref; + input output LookupState state; +protected + Class cls; + InstNode constructor; +algorithm + // If it's not a class it can't be an external object. + if not LookupState.isClass(state) then + return; + end if; + + // External objects are identified by extending from ExternalObject, so the + // node needs to be expanded before we know whether it's an external object or + // not. Components are instantiated before their bindings, so in proper models + // we shouldn't get any non-expanded external objects here. But to avoid + // getting weird errors in erroneous models we make sure it's expanded anyway. + Inst.expand(node); + cls := InstNode.getClass(node); + + () := match cls + case Class.PARTIAL_BUILTIN(ty = Type.COMPLEX(complexTy = + ComplexType.EXTERNAL_OBJECT(constructor = constructor))) + algorithm + cref := ComponentRef.prefixCref(constructor, Type.UNKNOWN(), {}, cref); + state := LookupState.FUNC(); + then + (); + + else (); + end match; +end fixExternalObjectCall; + function lookupImport input Absyn.Path name; input InstNode scope; @@ -188,6 +211,7 @@ function lookupCref input Absyn.ComponentRef cref; input InstNode scope "The scope to look in."; input SourceInfo info; + input Error.Message errMsg; output ComponentRef foundCref; output InstNode foundScope "The scope where the first part of the cref was found."; output LookupState state; @@ -224,7 +248,7 @@ algorithm (foundCref, foundScope, state); case Absyn.ComponentRef.CREF_FULLYQUALIFIED() - then lookupCref(cref.componentRef, InstNode.topScope(scope), info); + then lookupCref(cref.componentRef, InstNode.topScope(scope), info, errMsg); case Absyn.ComponentRef.WILD() then (ComponentRef.WILD(), scope, LookupState.PREDEF_COMP()); case Absyn.ComponentRef.ALLWILD() then (ComponentRef.WILD(), scope, LookupState.PREDEF_COMP()); @@ -242,7 +266,7 @@ algorithm end if; if match_ty <> MatchType.FOUND then - Error.addSourceMessage(Error.LOOKUP_VARIABLE_ERROR, + Error.addSourceMessage(errMsg, {Dump.printComponentRefStr(cref), InstNode.name(scope)}, info); fail(); end if; diff --git a/Compiler/NFFrontEnd/NFLookupState.mo b/Compiler/NFFrontEnd/NFLookupState.mo index f86e9678ecb..dadb5995ba1 100644 --- a/Compiler/NFFrontEnd/NFLookupState.mo +++ b/Compiler/NFFrontEnd/NFLookupState.mo @@ -132,14 +132,25 @@ uniontype LookupState function isCallable input InstNode node; - output Boolean b = false; + output Boolean callable; protected - SCode.Element def; + SCode.Element def = InstNode.definition(node); algorithm - def := InstNode.definition(node); - b := SCode.isRecord(def) or SCode.isOperator(def); + callable := SCode.isRecord(def) or SCode.isOperator(def); end isCallable; + function isClass + input LookupState state; + output Boolean isClass; + algorithm + isClass := match state + case COMP_CLASS() then true; + case CLASS() then true; + case PREDEF_CLASS() then true; + else false; + end match; + end isClass; + function assertState input LookupState endState; input LookupState expectedState;