[colobot] 46/74: Add implicit cast and null for passing arguments

Didier Raboud odyx at moszumanska.debian.org
Mon Nov 7 07:50:04 UTC 2016


This is an automated email from the git hooks/post-receive script.

odyx pushed a commit to branch debian/master
in repository colobot.

commit 4a14a44f3f07ee103161fbec2bcaa4bf5e6e2a84
Author: melex750 <melex750 at users.noreply.github.com>
Date:   Sat Sep 17 07:58:39 2016 -0400

    Add implicit cast and null for passing arguments
---
 src/CBot/CBotEnums.h                  |   1 +
 src/CBot/CBotInstr/CBotFunction.cpp   | 107 +++++++++++++++++++++-------------
 src/CBot/CBotInstr/CBotInstrUtils.cpp |  10 +++-
 src/common/restext.cpp                |   1 +
 test/unit/CBot/CBot_test.cpp          |  88 ++++++++++++++++++++++++++++
 5 files changed, 165 insertions(+), 42 deletions(-)

diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h
index 24e0095..da0dbea 100644
--- a/src/CBot/CBotEnums.h
+++ b/src/CBot/CBotEnums.h
@@ -236,6 +236,7 @@ enum CBotError : int
     CBotErrPrivate       = 5041, //!< protected item
     CBotErrNoPublic      = 5042, //!< missing word "public"
     CBotErrNoExpression  = 5043, //!< expression expected after =
+    CBotErrAmbiguousCall = 5044, //!< ambiguous call to overloaded function
 
     // Runtime errors
     CBotErrZeroDiv       = 6000, //!< division by zero
diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp
index d00e8ea..1e7e0b9 100644
--- a/src/CBot/CBotInstr/CBotFunction.cpp
+++ b/src/CBot/CBotInstr/CBotFunction.cpp
@@ -466,8 +466,7 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
 
     if ( name.empty() ) return nullptr;
 
-    int     delta   = 99999;                // seeks the lowest signature
-    CBotFunction*   pFunc = nullptr;           // the best function found
+    std::map<CBotFunction*, int> funcMap;
 
     if ( this != nullptr )
     {
@@ -482,44 +481,48 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
                 CBotVar* pw = ppVars[i++];              // provided list parameter
                 while ( pv != nullptr && pw != nullptr)
                 {
-                    if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult()))
+                    CBotTypResult paramType = pv->GetTypResult();
+                    CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
+
+                    if (!TypesCompatibles(paramType, argType))
                     {
-                        if ( pFunc == nullptr ) TypeOrError = CBotErrBadParam;
+                        if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam);
                         break;
                     }
-                    int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
-                    alpha += d>0 ? d : -10*d;       // quality loss, 10 times more expensive!
 
+                    if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer))
+                    {
+                        CBotClass* c1 = paramType.GetClass();
+                        CBotClass* c2 = argType.GetClass();
+                        while (c2 != c1 && c2 != nullptr)    // implicit cast
+                        {
+                            alpha += 10;
+                            c2 = c2->GetParent();
+                        }
+                    }
+                    else
+                    {
+                        int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
+                        alpha += d>0 ? d : -10*d;       // quality loss, 10 times more expensive!
+                    }
                     pv = pv->GetNext();
                     pw = ppVars[i++];
                 }
                 if ( pw != nullptr )
                 {
-                    if ( pFunc != nullptr ) continue;
+                    if ( !funcMap.empty() ) continue;
                     if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam);
                     if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam);
                     continue;                   // too many parameters
                 }
                 if ( pv != nullptr )
                 {
-                    if ( pFunc != nullptr ) continue;
+                    if ( !funcMap.empty() ) continue;
                     if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam);
                     if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam);
                     continue;                   // not enough parameters
                 }
-
-                if (alpha == 0)                 // perfect signature
-                {
-                    nIdent = pt->m_nFuncIdent;
-                    TypeOrError = pt->m_retTyp;
-                    return pt;
-                }
-
-                if ( alpha < delta )            // a better signature?
-                {
-                    pFunc = pt;
-                    delta = alpha;
-                }
+                funcMap.insert( std::pair<CBotFunction*, int>(pt, alpha) );
             }
         }
     }
@@ -537,50 +540,72 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
                 CBotVar* pw = ppVars[i++];              // list of provided parameters
                 while ( pv != nullptr && pw != nullptr)
                 {
-                    if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult()))
+                    CBotTypResult paramType = pv->GetTypResult();
+                    CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
+
+                    if (!TypesCompatibles(paramType, argType))
                     {
-                        if ( pFunc == nullptr ) TypeOrError = CBotErrBadParam;
+                        if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam);
                         break;
                     }
-                    int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
-                    alpha += d>0 ? d : -10*d;       // quality loss, 10 times more expensive!
 
+                    if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer))
+                    {
+                        CBotClass* c1 = paramType.GetClass();
+                        CBotClass* c2 = argType.GetClass();
+                        while (c2 != c1 && c2 != nullptr)    // implicit cast
+                        {
+                            alpha += 10;
+                            c2 = c2->GetParent();
+                        }
+                    }
+                    else
+                    {
+                        int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
+                        alpha += d>0 ? d : -10*d;       // quality loss, 10 times more expensive!
+                    }
                     pv = pv->GetNext();
                     pw = ppVars[i++];
                 }
                 if ( pw != nullptr )
                 {
-                    if ( pFunc != nullptr ) continue;
+                    if ( !funcMap.empty() ) continue; // previous useable function
                     if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam);
                     if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam);
                     continue;                   // to many parameters
                 }
                 if ( pv != nullptr )
                 {
-                    if ( pFunc != nullptr ) continue;
+                    if ( !funcMap.empty() ) continue; // previous useable function
                     if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam);
                     if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam);
                     continue;                   // not enough parameters
                 }
-
-                if (alpha == 0)                 // perfect signature
-                {
-                    nIdent = pt->m_nFuncIdent;
-                    TypeOrError = pt->m_retTyp;
-                    return pt;
-                }
-
-                if ( alpha < delta )            // a better signature?
-                {
-                    pFunc = pt;
-                    delta = alpha;
-                }
+                funcMap.insert( std::pair<CBotFunction*, int>(pt, alpha) );
             }
         }
     }
 
-    if ( pFunc != nullptr )
+    if ( !funcMap.empty() )
     {
+        auto it = funcMap.begin();
+        CBotFunction* pFunc = it->first;        // the best function found
+        signed int    delta = it->second;       // seeks the lowest signature
+
+        for (++it ; it != funcMap.end() ; it++)
+        {
+            if (it->second < delta) // a better signature?
+            {
+                TypeOrError.SetType(CBotNoErr);
+                pFunc = it->first;
+                delta = it->second;
+                continue;
+            }
+
+            if (it->second == delta) TypeOrError.SetType(CBotErrAmbiguousCall);
+        }
+
+        if (TypeOrError.Eq(CBotErrAmbiguousCall)) return nullptr;
         nIdent = pFunc->m_nFuncIdent;
         TypeOrError = pFunc->m_retTyp;
         return pFunc;
diff --git a/src/CBot/CBotInstr/CBotInstrUtils.cpp b/src/CBot/CBotInstr/CBotInstrUtils.cpp
index bbe80b2..067f443 100644
--- a/src/CBot/CBotInstr/CBotInstrUtils.cpp
+++ b/src/CBot/CBotInstr/CBotInstrUtils.cpp
@@ -149,12 +149,20 @@ bool TypesCompatibles(const CBotTypResult& type1, const CBotTypResult& type2)
 
     if (max >= CBotTypBoolean)
     {
+        if (t1 == CBotTypPointer && t2 == CBotTypNullPointer) return true;
         if (t2 != t1) return false;
 
+        if (max == CBotTypPointer)
+        {
+            CBotClass*    c1 = type1.GetClass();
+            CBotClass*    c2 = type2.GetClass();
+            return c2->IsChildOf(c1);
+        }
+
         if (max == CBotTypArrayPointer)
             return TypesCompatibles(type1.GetTypElem(), type2.GetTypElem());
 
-        if (max == CBotTypClass || max == CBotTypPointer)
+        if (max == CBotTypClass)
             return type1.GetClass() == type2.GetClass() ;
 
         return true ;
diff --git a/src/common/restext.cpp b/src/common/restext.cpp
index 9770c32..859a61f 100644
--- a/src/common/restext.cpp
+++ b/src/common/restext.cpp
@@ -717,6 +717,7 @@ void InitializeRestext()
     stringsCbot[CBot::CBotErrPrivate]       = TR("Private element");
     stringsCbot[CBot::CBotErrNoPublic]      = TR("Public required");
     stringsCbot[CBot::CBotErrNoExpression]  = TR("Expression expected after =");
+    stringsCbot[CBot::CBotErrAmbiguousCall] = TR("Ambiguous call to overloaded function");
 
     stringsCbot[CBot::CBotErrZeroDiv]       = TR("Dividing by zero");
     stringsCbot[CBot::CBotErrNotInit]       = TR("Variable not initialized");
diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp
index 071abb9..2a112d7 100644
--- a/test/unit/CBot/CBot_test.cpp
+++ b/test/unit/CBot/CBot_test.cpp
@@ -1786,3 +1786,91 @@ TEST_F(CBotUT, ClassNewConstructorMethodChain)
         "}\n"
     );
 }
+
+TEST_F(CBotUT, PassNullAsArgument)
+{
+    auto publicProgram = ExecuteTest(
+        "public class BaseClass {}\n"
+        "public class SubClass extends BaseClass {}\n"
+    );
+
+    ExecuteTest(
+        "bool Test(BaseClass b) {\n"
+        "    return (b == null);\n"
+        "}\n"
+        "extern void PassNullAsArgument() {\n"
+        "    ASSERT(true == Test(null));\n"
+        "}\n"
+    );
+
+    ExecuteTest(
+        "void Test(BaseClass b) {}\n"
+        "void Test(SubClass s) {}\n"
+        "\n"
+        "extern void AmbiguousCallArgumentNull() {\n"
+        "    Test(null);\n"
+        "}\n",
+        CBotErrAmbiguousCall
+    );
+}
+
+TEST_F(CBotUT, ClassImplicitCastArguments)
+{
+    auto publicProgram = ExecuteTest(
+        "public class BaseClass { int a = 360; }\n"
+        "public class SubClass extends BaseClass {}\n"
+    );
+
+    ExecuteTest(
+        "bool Test(BaseClass b) {\n"
+        "    SubClass s = b;\n"
+        "    return (360 == s.a);\n"
+        "}\n"
+        "extern void UpcastPassingArguments() {\n"
+        "    ASSERT(true == Test(new SubClass()));\n"
+        "}\n"
+    );
+
+    ExecuteTest(
+        "void Test(BaseClass b, SubClass s) {}\n"
+        "void Test(SubClass s, BaseClass b) {}\n"
+        "\n"
+        "extern void UpcastAmbiguousCall() {\n"
+        "    Test(new SubClass(), new SubClass());\n"
+        "}\n",
+        CBotErrAmbiguousCall
+    );
+
+    ExecuteTest(
+        "bool Test(BaseClass b, SubClass s) { return false; }\n"
+        "bool Test(SubClass s, BaseClass b) { return false; }\n"
+        "bool Test(SubClass s, SubClass s2) { return true; }\n"
+        "\n"
+        "extern void NoErrorMoreSpecific() {\n"
+        "    ASSERT(true == Test(new SubClass(), new SubClass()));\n"
+        "}\n"
+    );
+}
+
+TEST_F(CBotUT, AmbiguousCallWithNumbers)
+{
+    ExecuteTest(
+        "void Test(int i, float f) {}\n"
+        "void Test(float f, int i) {}\n"
+        "\n"
+        "extern void AmbiguousCallNumbers() {\n"
+        "    Test(1, 2);\n"
+        "}\n",
+        CBotErrAmbiguousCall
+    );
+
+    ExecuteTest(
+        "bool Test(int i, float f) { return false; }\n"
+        "bool Test(float f, int i) { return false; }\n"
+        "bool Test(int i, int ii)  { return true; }\n"
+        "\n"
+        "extern void NoErrorMoreSpecific() {\n"
+        "    ASSERT(true == Test(1, 2));\n"
+        "}\n"
+    );
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/colobot.git



More information about the Pkg-games-commits mailing list