1 // =================================
   2 // Copyright (c) 2021 Seppo Laakko
   3 // Distributed under the MIT license
   4 // =================================
   5 
   6 #include <cmajor/binder/OverloadResolution.hpp>
   7 #include <cmajor/binder/BoundCompileUnit.hpp>
   8 #include <cmajor/binder/BoundFunction.hpp>
   9 #include <cmajor/binder/BoundConstraint.hpp>
  10 #include <cmajor/binder/Concept.hpp>
  11 #include <cmajor/binder/TypeBinder.hpp>
  12 #include <cmajor/binder/BoundClass.hpp>
  13 #include <cmajor/symbols/TemplateSymbol.hpp>
  14 #include <cmajor/symbols/InterfaceTypeSymbol.hpp>
  15 #include <cmajor/symbols/GlobalFlags.hpp>
  16 #include <cmajor/symbols/Warning.hpp>
  17 #include <cmajor/symbols/DebugFlags.hpp>
  18 #include <soulng/util/Unicode.hpp>
  19 #include <soulng/util/Log.hpp>
  20 #include <soulng/util/Time.hpp>
  21 #include <algorithm>
  22 
  23 namespace cmajor { namespace binder {
  24 
  25 using namespace soulng::unicode;
  26 
  27 bool BetterFunctionMatch::operator()(const FunctionMatch& leftconst FunctionMatch& right) const
  28 {
  29     int leftBetterArgumentMatches = 0;
  30     int rightBetterArgumentMatches = 0;
  31     int n = std::max(int(left.argumentMatches.size())int(right.argumentMatches.size()));
  32     for (int i = 0; i < n; ++i)
  33     {
  34         ArgumentMatch leftMatch;
  35         if (i < int(left.argumentMatches.size()))
  36         {
  37             leftMatch = left.argumentMatches[i];
  38         }
  39         ArgumentMatch rightMatch;
  40         if (i < int(right.argumentMatches.size()))
  41         {
  42             rightMatch = right.argumentMatches[i];
  43         }
  44         if (BetterArgumentMatch(leftMatchrightMatch))
  45         {
  46             ++leftBetterArgumentMatches;
  47         }
  48         else if (BetterArgumentMatch(rightMatchleftMatch))
  49         {
  50             ++rightBetterArgumentMatches;
  51         }
  52     }
  53     if (leftBetterArgumentMatches > rightBetterArgumentMatches)
  54     {
  55         return true;
  56     }
  57     if (rightBetterArgumentMatches > leftBetterArgumentMatches)
  58     {
  59         return false;
  60     }
  61     if (left.numConversions < right.numConversions)
  62     {
  63         return true;
  64     }
  65     if (left.numConversions > right.numConversions)
  66     {
  67         return false;
  68     }
  69     if (left.numQualifyingConversions < right.numQualifyingConversions)
  70     {
  71         return true;
  72     }
  73     if (left.numQualifyingConversions > right.numQualifyingConversions)
  74     {
  75         return false;
  76     }
  77     if (!left.fun->IsFunctionTemplate() && right.fun->IsFunctionTemplate())
  78     {
  79         return true;
  80     }
  81     if (left.fun->IsFunctionTemplate() && !right.fun->IsFunctionTemplate())
  82     {
  83         return false;
  84     }
  85     if (!left.fun->IsTemplateSpecialization() && right.fun->IsTemplateSpecialization())
  86     {
  87         return true;
  88     }
  89     if (left.fun->IsTemplateSpecialization() && !right.fun->IsTemplateSpecialization())
  90     {
  91         return false;
  92     }
  93     if (left.boundConstraint && !right.boundConstraint)
  94     {
  95         return true;
  96     }
  97     if (!left.boundConstraint && right.boundConstraint)
  98     {
  99         return false;
 100     }
 101     if (left.boundConstraint && right.boundConstraint)
 102     {
 103         bool leftSubsumeRight = left.boundConstraint->Subsume(right.boundConstraint);
 104         bool rightSubsumeLeft = right.boundConstraint->Subsume(left.boundConstraint);
 105         if (leftSubsumeRight && !rightSubsumeLeft)
 106         {
 107             return true;
 108         }
 109         if (rightSubsumeLeft && !leftSubsumeRight)
 110         {
 111             return false;
 112         }
 113     }
 114     return false;
 115 }
 116 
 117 bool FindQualificationConversion(TypeSymbol* sourceTypeTypeSymbol* targetTypeBoundExpression* argumentConversionType conversionTypeconst Span& spanconst boost::uuids::uuid& moduleId
 118     FunctionMatch& functionMatchArgumentMatch& argumentMatch)
 119 {
 120     int distance = 0;
 121     if (argumentMatch.conversionFun)
 122     {
 123         distance = argumentMatch.conversionFun->ConversionDistance();
 124     }
 125     if (targetType->IsRvalueReferenceType() && !sourceType->IsRvalueReferenceType())
 126     {
 127         ++functionMatch.numQualifyingConversions;
 128     }
 129     if (sourceType->IsConstType())
 130     {
 131         if (targetType->IsConstType() || !targetType->IsReferenceType())
 132         {
 133             ++distance;
 134         }
 135         else if (conversionType == ConversionType::implicit_)
 136         {
 137             if (sourceType->PointerCount() < 1)
 138             {
 139                 functionMatch.cannotBindConstArgToNonConstParam = true;
 140                 functionMatch.sourceType = sourceType;
 141                 functionMatch.targetType = targetType;
 142                 return false;
 143             }
 144             else
 145             {
 146                 ++distance;
 147             }
 148         }
 149         else
 150         {
 151             distance = 255;
 152         }
 153     }
 154     else
 155     {
 156         if (targetType->IsConstType())
 157         {
 158             distance += 2;
 159         }
 160         else
 161         {
 162             distance += 3;
 163         }
 164     }
 165     if (sourceType->IsReferenceType() && !targetType->IsReferenceType())
 166     {
 167         argumentMatch.postReferenceConversionFlags = OperationFlags::deref;
 168         argumentMatch.conversionDistance = distance;
 169         ++functionMatch.numQualifyingConversions;
 170         return true;
 171     }
 172     else if (!sourceType->IsReferenceType() && (targetType->IsReferenceType() || targetType->IsClassTypeSymbol() || targetType->GetSymbolType() == SymbolType::classDelegateTypeSymbol))
 173     {
 174         if (targetType->IsConstType() || targetType->IsClassTypeSymbol() || targetType->GetSymbolType() == SymbolType::classDelegateTypeSymbol)
 175         {
 176             argumentMatch.postReferenceConversionFlags = OperationFlags::addr;
 177             argumentMatch.conversionDistance = distance;
 178             ++functionMatch.numQualifyingConversions;
 179             return true;
 180         }
 181         else if ((!sourceType->IsConstType() || sourceType->PointerCount() >= 1) && argument->IsLvalueExpression())
 182         {
 183             if (targetType->IsRvalueReferenceType() && !sourceType->IsRvalueReferenceType())
 184             {
 185                 if (argument->GetFlag(BoundExpressionFlags::bindToRvalueReference))
 186                 {
 187                     distance = 0;
 188                 }
 189                 else
 190                 {
 191                     distance += 10;
 192                 }
 193             }
 194             argumentMatch.postReferenceConversionFlags = OperationFlags::addr;
 195             argumentMatch.conversionDistance = distance;
 196             ++functionMatch.numQualifyingConversions;
 197             return true;
 198         }
 199         else
 200         {
 201             functionMatch.cannotBindConstArgToNonConstParam = true;
 202             functionMatch.sourceType = sourceType;
 203             functionMatch.targetType = targetType;
 204         }
 205     }
 206     else if (sourceType->IsConstType() && !targetType->IsConstType())
 207     {
 208         ++functionMatch.numQualifyingConversions;
 209         ++distance;
 210         if (sourceType->IsLvalueReferenceType() && targetType->IsRvalueReferenceType())
 211         {
 212             ++distance;
 213             ++functionMatch.numQualifyingConversions;
 214         }
 215         argumentMatch.conversionDistance = distance;
 216         return true;
 217     }
 218     else if (!sourceType->IsConstType() && targetType->IsConstType())
 219     {
 220         ++functionMatch.numQualifyingConversions;
 221         ++distance;
 222         if (sourceType->IsLvalueReferenceType() && targetType->IsRvalueReferenceType())
 223         {
 224             ++distance;
 225             ++functionMatch.numQualifyingConversions;
 226         }
 227         argumentMatch.conversionDistance = distance;
 228         return true;
 229     }
 230     else if (sourceType->IsLvalueReferenceType() && targetType->IsRvalueReferenceType())
 231     {
 232         ++distance;
 233         ++functionMatch.numQualifyingConversions;
 234         argumentMatch.conversionDistance = distance;
 235         return true;
 236     }
 237     else if (sourceType->IsRvalueReferenceType() && targetType->IsLvalueReferenceType())
 238     {
 239         ++distance;
 240         ++functionMatch.numQualifyingConversions;
 241         argumentMatch.conversionDistance = distance;
 242         return true;
 243     }
 244     else if (argumentMatch.conversionFun)
 245     {
 246         argumentMatch.conversionDistance = distance;
 247         return true;
 248     }
 249     return false;
 250 }
 251 
 252 bool FindTemplateParameterMatch(TypeSymbol* sourceTypeTypeSymbol* targetTypeConversionType conversionTypeBoundExpression* argument
 253     BoundCompileUnit& boundCompileUnitFunctionMatch& functionMatchContainerScope* containerScopeBoundFunction* currentFunctionconst Span& spanconst boost::uuids::uuid& moduleId)
 254 {
 255     if (targetType->BaseType()->GetSymbolType() != SymbolType::templateParameterSymbol) return false;
 256     TemplateParameterSymbol* templateParameter = static_cast<TemplateParameterSymbol*>(targetType->BaseType());
 257     TypeSymbol* templateArgumentType = nullptr;
 258     auto it = functionMatch.templateParameterMap.find(templateParameter);
 259     if (it == functionMatch.templateParameterMap.cend())
 260     {
 261         templateArgumentType = sourceType->RemoveDerivations(targetType->DerivationRec()spanmoduleId);
 262         if (templateArgumentType)
 263         {
 264             functionMatch.templateParameterMap[templateParameter] = templateArgumentType;
 265         }
 266         else
 267         {
 268             return false;
 269         }
 270     }
 271     else
 272     {
 273         templateArgumentType = it->second;
 274     }
 275     targetType = targetType->Unify(templateArgumentTypespanmoduleId);
 276     if (!targetType)
 277     {
 278         return false;
 279     }
 280     if (TypesEqual(sourceTypetargetType))
 281     {
 282         functionMatch.argumentMatches.push_back(ArgumentMatch());
 283         return true;
 284     }
 285     else
 286     {
 287         bool qualificationConversionMatch = false;
 288         ArgumentMatch argumentMatch;
 289         if (TypesEqual(sourceType->PlainType(spanmoduleId)targetType->PlainType(spanmoduleId)))
 290         {
 291             qualificationConversionMatch = FindQualificationConversion(sourceTypetargetTypeargumentconversionTypespanmoduleIdfunctionMatchargumentMatch);
 292         }
 293         if (qualificationConversionMatch)
 294         {
 295             functionMatch.argumentMatches.push_back(argumentMatch);
 296             return true;
 297         }
 298         else
 299         {
 300             FunctionSymbol* conversionFun = boundCompileUnit.GetConversion(sourceTypetargetTypecontainerScopecurrentFunctionspanmoduleIdargumentMatch);
 301             if (conversionFun)
 302             {
 303                 if (conversionFun->GetConversionType() == conversionType || conversionFun->GetConversionType() == ConversionType::implicit_)
 304                 {
 305                     ++functionMatch.numConversions;
 306                     argumentMatch.conversionFun = conversionFun;
 307                     //if (argumentMatch.postReferenceConversionFlags == OperationFlags::none) bug???
 308                     if (argumentMatch.preReferenceConversionFlags == OperationFlags::none)
 309                     {
 310                         if (FindQualificationConversion(sourceTypetargetTypeargumentconversionTypespanmoduleIdfunctionMatchargumentMatch))
 311                         {
 312                             functionMatch.argumentMatches.push_back(argumentMatch);
 313                             return true;
 314                         }
 315                         else
 316                         {
 317                             return false;
 318                         }
 319                     }
 320                     else
 321                     {
 322                         if (FindQualificationConversion(conversionFun->ConversionSourceType()targetTypeargumentconversionTypespanmoduleIdfunctionMatchargumentMatch))
 323                         {
 324                             functionMatch.argumentMatches.push_back(argumentMatch);
 325                             return true;
 326                         }
 327                         else
 328                         {
 329                             return false;
 330                         }
 331                     }
 332                 }
 333                 else
 334                 {
 335                     return false;
 336                 }
 337             }
 338             else
 339             {
 340                 return false;
 341             }
 342         }
 343     }
 344     return false;
 345 }
 346 
 347 bool FindClassTemplateSpecializationMatch(TypeSymbol* sourceTypeTypeSymbol* targetTypeConversionType conversionTypeBoundExpression* argument
 348     BoundCompileUnit& boundCompileUnitFunctionMatch& functionMatchContainerScope* containerScopeBoundFunction* currentFunctionconst Span& spanconst boost::uuids::uuid& moduleId)
 349 {
 350     if (targetType->BaseType()->GetSymbolType() != SymbolType::classTemplateSpecializationSymbol)
 351     {
 352         return false;
 353     }
 354     ClassTemplateSpecializationSymbol* targetClassTemplateSpecialization = static_cast<ClassTemplateSpecializationSymbol*>(targetType->BaseType());
 355     int n = targetClassTemplateSpecialization->TemplateArgumentTypes().size();
 356     int numArgumentMatches = functionMatch.argumentMatches.size();
 357     if (sourceType->BaseType()->GetSymbolType() == SymbolType::classTemplateSpecializationSymbol)
 358     {
 359         ClassTemplateSpecializationSymbol* sourceClassTemplateSpecialization = static_cast<ClassTemplateSpecializationSymbol*>(sourceType->BaseType());
 360         int m = sourceClassTemplateSpecialization->TemplateArgumentTypes().size();
 361         if (n != m) return false;
 362         for (int i = 0; i < n; ++i)
 363         {
 364             TypeSymbol* sourceArgumentType = sourceClassTemplateSpecialization->TemplateArgumentTypes()[i];
 365             TypeSymbol* targetArgumentType = targetClassTemplateSpecialization->TemplateArgumentTypes()[i];
 366             if (FindTemplateParameterMatch(sourceArgumentTypetargetArgumentTypeconversionTypeargumentboundCompileUnitfunctionMatchcontainerScopecurrentFunctionspanmoduleId))
 367             {
 368                 continue;
 369             }
 370             else if (FindClassTemplateSpecializationMatch(sourceArgumentTypetargetArgumentTypeconversionTypeargumentboundCompileUnitfunctionMatchcontainerScopecurrentFunctionspanmoduleId))
 371             {
 372                 continue;
 373             }
 374             else
 375             {
 376                 return false;
 377             }
 378         }
 379     }
 380     functionMatch.argumentMatches.resize(numArgumentMatches);
 381     std::vector<TypeSymbol*> targetTemplateArguments;
 382     for (int i = 0; i < n; ++i)
 383     {
 384         TypeSymbol* templateArgumentType = targetClassTemplateSpecialization->TemplateArgumentTypes()[i]->BaseType()->UnifyTemplateArgumentType(
 385             boundCompileUnit.GetSymbolTable()functionMatch.templateParameterMapspanmoduleId);
 386         if (templateArgumentType)
 387         {
 388             targetTemplateArguments.push_back(templateArgumentType);
 389         }
 390         else
 391         {
 392             return false;
 393         }
 394     }
 395     TypeSymbol* plainTargetType = boundCompileUnit.GetSymbolTable().MakeClassTemplateSpecialization(targetClassTemplateSpecialization->GetClassTemplate()targetTemplateArgumentsspan
 396         GetRootModuleForCurrentThread()->Id());
 397     targetType = boundCompileUnit.GetSymbolTable().MakeDerivedType(plainTargetTypetargetType->DerivationRec()spanmoduleId);
 398     if (TypesEqual(sourceTypetargetType))
 399     {
 400         functionMatch.argumentMatches.push_back(ArgumentMatch());
 401         return true;
 402     }
 403     else
 404     {
 405         bool qualificationConversionMatch = false;
 406         ArgumentMatch argumentMatch;
 407         if (TypesEqual(sourceType->PlainType(spanmoduleId)targetType->PlainType(spanmoduleId)))
 408         {
 409             qualificationConversionMatch = FindQualificationConversion(sourceTypetargetTypeargumentconversionTypespanmoduleIdfunctionMatchargumentMatch);
 410         }
 411         if (qualificationConversionMatch)
 412         {
 413             functionMatch.argumentMatches.push_back(argumentMatch);
 414             return true;
 415         }
 416         else
 417         {
 418             FunctionSymbol* conversionFun = boundCompileUnit.GetConversion(sourceTypetargetTypecontainerScopecurrentFunctionspanmoduleIdargumentMatch);
 419             if (conversionFun)
 420             {
 421                 if (conversionFun->GetConversionType() == conversionType || conversionFun->GetConversionType() == ConversionType::implicit_)
 422                 {
 423                     argumentMatch.conversionFun = conversionFun;
 424                     ++functionMatch.numConversions;
 425                     if (argumentMatch.preReferenceConversionFlags == OperationFlags::none)
 426                     {
 427                         if (FindQualificationConversion(sourceTypetargetTypeargumentconversionTypespanmoduleIdfunctionMatchargumentMatch))
 428                         {
 429                             functionMatch.argumentMatches.push_back(argumentMatch);
 430                             return true;
 431                         }
 432                         else
 433                         {
 434                             return false;
 435                         }
 436                     }
 437                     else
 438                     {
 439                         if (FindQualificationConversion(conversionFun->ConversionSourceType()targetTypeargumentconversionTypespanmoduleIdfunctionMatchargumentMatch))
 440                         {
 441                             functionMatch.argumentMatches.push_back(argumentMatch);
 442                             return true;
 443                         }
 444                         else
 445                         {
 446                             return false;
 447                         }
 448                     }
 449                 }
 450                 else
 451                 {
 452                     return false;
 453                 }
 454             }
 455             else
 456             {
 457                 return false;
 458             }
 459         }
 460     }
 461     return false;
 462 }
 463 
 464 bool FindConversions(BoundCompileUnit& boundCompileUnitFunctionSymbol* functionstd::std::vector<std::std::unique_ptr<BoundExpression>>&argumentsFunctionMatch&functionMatch
 465     ConversionType conversionTypeContainerScope* containerScopeBoundFunction* currentFunctionconst Span& spanconst boost::uuids::uuid& moduleId)
 466 {
 467     if (!currentFunction)
 468     {
 469         if (function->IsProject() && !function->IsBound())
 470         {
 471             Node* node = boundCompileUnit.GetSymbolTable().GetNodeNoThrow(function);
 472             if (node)
 473             {
 474                 TypeBinder typeBinder(boundCompileUnit);
 475                 typeBinder.SetContainerScope(containerScope);
 476                 typeBinder.SetCurrentFunctionSymbol(function);
 477                 node->Accept(typeBinder);
 478             }
 479         }
 480     }
 481     int arity = arguments.size();
 482     if (arity == 1 && function->GroupName() == U"@constructor" && arguments[0]->GetType()->IsReferenceType())
 483     {
 484         functionMatch.referenceMustBeInitialized = true;
 485         return false;
 486     }
 487     int n = std::min(arityfunction->Arity());
 488     if (!function->IsVarArg())
 489     {
 490         Assert(arity == function->Arity()"wrong arity");
 491     }
 492     for (int i = 0; i < n; ++i)
 493     {
 494         BoundExpression* argument = arguments[i].get();
 495         TypeSymbol* sourceType = argument->GetType();
 496         if (sourceType->RemoveConst(spanmoduleId)->IsBasicTypeSymbol())
 497         {
 498             sourceType = sourceType->RemoveConst(spanmoduleId);
 499         }
 500         ParameterSymbol* parameter = function->Parameters()[i];
 501         TypeSymbol* targetType = parameter->GetType();
 502         if (arity == 2 && function->GroupName() == U"operator=")
 503         {
 504             if (targetType->IsRvalueReferenceType() && !sourceType->IsRvalueReferenceType() && !argument->GetFlag(BoundExpressionFlags::bindToRvalueReference))
 505             {
 506                 ++functionMatch.numQualifyingConversions;
 507             }
 508             if (i == 0)
 509             {
 510                 if (targetType->IsConstType() && targetType->PointerCount() <= 1)
 511                 {
 512                     functionMatch.cannotAssignToConstObject = true;
 513                     return false;
 514                 }
 515             }
 516             if (i == 0 && TypesEqual(sourceTypetargetType))
 517             {
 518                 if (sourceType->IsReferenceType() && !function->IsConstructorDestructorOrNonstaticMemberFunction())
 519                 {
 520                     functionMatch.argumentMatches.push_back(ArgumentMatch(OperationFlags::nonenullptrOperationFlags::deref1));
 521                     ++functionMatch.numConversions;
 522                     continue;
 523                 }
 524             }
 525             else if (i == 1 && sourceType->IsReferenceType() && targetType->IsLvalueReferenceType() && TypesEqual(sourceType->RemoveReference(spanmoduleId)->RemoveConst(spanmoduleId)targetType->RemoveReference(spanmoduleId)))
 526             {
 527                 if (!function->IsConstructorDestructorOrNonstaticMemberFunction())
 528                 {
 529                     functionMatch.argumentMatches.push_back(ArgumentMatch(OperationFlags::nonenullptrOperationFlags::deref1));
 530                     ++functionMatch.numConversions;
 531                     continue;
 532                 }
 533             }
 534             else if (i == 1 && sourceType->IsReferenceType() && targetType->IsRvalueReferenceType() && TypesEqual(sourceType->RemoveReference(spanmoduleId)targetType->RemoveReference(spanmoduleId)))
 535             {
 536                 if (!function->IsConstructorDestructorOrNonstaticMemberFunction())
 537                 {
 538                     functionMatch.argumentMatches.push_back(ArgumentMatch(OperationFlags::nonenullptrOperationFlags::none0));
 539                     continue;
 540                 }
 541             }
 542             else if (i == 1 && !sourceType->IsReferenceType() && argument->IsLvalueExpression() && targetType->IsReferenceType() && TypesEqual(sourceTypetargetType->RemoveReference(spanmoduleId)))
 543             {
 544                 if (!function->IsConstructorDestructorOrNonstaticMemberFunction())
 545                 {
 546                     functionMatch.argumentMatches.push_back(ArgumentMatch(OperationFlags::nonenullptrOperationFlags::none 0));
 547                     continue;
 548                 }
 549             }
 550             else if (i == 1 && function->IsLvalueReferenceCopyAssignment() && TypesEqual(sourceTypetargetType->RemoveReference(spanmoduleId)))
 551             {
 552                 functionMatch.argumentMatches.push_back(ArgumentMatch(OperationFlags::nonenullptrOperationFlags::none0));
 553                 continue;
 554             }
 555             else if (i == 1 && function->IsLvalueReferenceCopyAssignment())
 556             {
 557                 ArgumentMatch argumentMatch;
 558                 FunctionSymbol* conversionFun = boundCompileUnit.GetConversion(sourceTypetargetType->RemoveReference(spanmoduleId)containerScopecurrentFunctionspanmoduleIdargumentMatch);
 559                 if (conversionFun&&(  conversionFun->GetConversionType() == conversionType || conversionFun->GetConversionType() == ConversionType::implicit_))
 560                 {
 561                     ++functionMatch.numConversions;
 562                     functionMatch.argumentMatches.push_back(ArgumentMatch(OperationFlags::noneconversionFunOperationFlags::none1));
 563                     continue;
 564                 }
 565             }
 566         }
 567         if (TypesEqual(sourceTypetargetType))
 568         {
 569             functionMatch.argumentMatches.push_back(ArgumentMatch());
 570         }
 571         else
 572         {
 573             if (arity == 2 && (function->GroupName() == U"@constructor" || function->GroupName() == U"operator="))
 574             {
 575                 if (i == 0)
 576                 {
 577                     return false;
 578                 }
 579             }
 580             bool qualificationConversionMatch = false;
 581             ArgumentMatch argumentMatch;
 582             if (TypesEqual(sourceType->PlainType(spanmoduleId)targetType->PlainType(spanmoduleId)))
 583             {
 584                 qualificationConversionMatch = FindQualificationConversion(sourceTypetargetTypeargumentconversionTypespanmoduleIdfunctionMatchargumentMatch);
 585                 functionMatch.argumentMatches.push_back(argumentMatch);
 586             }
 587             if (!qualificationConversionMatch)
 588             {
 589                 FunctionSymbol* conversionFun = boundCompileUnit.GetConversion(sourceTypetargetTypecontainerScopecurrentFunctionspanmoduleIdargumentMatch);
 590                 if (conversionFun)
 591                 {
 592                     if (conversionFun->GetConversionType() == conversionType || conversionFun->GetConversionType() == ConversionType::implicit_)
 593                     {
 594                         argumentMatch.conversionFun = conversionFun;
 595                         ++functionMatch.numConversions;
 596                         if (argumentMatch.preReferenceConversionFlags == OperationFlags::none)
 597                         {
 598                             if (FindQualificationConversion(sourceTypetargetTypeargumentconversionTypespanmoduleIdfunctionMatchargumentMatch))
 599                             {
 600                                 functionMatch.argumentMatches.push_back(argumentMatch);
 601                                 continue;
 602                             }
 603                             else
 604                             {
 605                                 return false;
 606                             }
 607                         }
 608                         else
 609                         {
 610                             if (FindQualificationConversion(conversionFun->ConversionSourceType()targetTypeargumentconversionTypespanmoduleIdfunctionMatchargumentMatch))
 611                             {
 612                                 functionMatch.argumentMatches.push_back(argumentMatch);
 613                                 continue;
 614                             }
 615                             else
 616                             {
 617                                 return false;
 618                             }
 619                         }
 620                     }
 621                     else
 622                     {
 623                         if (arity == 2 && i == 1 && conversionType == ConversionType::implicit_ && conversionFun->GetConversionType() == ConversionType::explicit_)
 624                         {
 625                             functionMatch.castRequired = true;
 626                             functionMatch.sourceType = sourceType;
 627                             functionMatch.targetType = targetType;
 628                         }
 629                         return false;
 630                     }
 631                 }
 632                 else
 633                 {
 634                     if (function->IsFunctionTemplate())
 635                     {
 636                         if (FindTemplateParameterMatch(sourceTypetargetTypeconversionTypeargumentboundCompileUnitfunctionMatchcontainerScopecurrentFunctionspanmoduleId))
 637                         {
 638                             continue;
 639                         }
 640                         if (FindClassTemplateSpecializationMatch(sourceTypetargetTypeconversionTypeargumentboundCompileUnitfunctionMatchcontainerScopecurrentFunctionspanmoduleId))
 641                         {
 642                             continue;
 643                         }
 644                     }
 645                     return false;
 646                 }
 647             }
 648         }
 649     }
 650     return true;
 651 }
 652 
 653 std::string MakeOverloadName(const std::u32string& groupNameconst std::std::vector<std::std::unique_ptr<BoundExpression>>&argumentsconstSpan&spanconstboost::uuids::uuid&moduleId)
 654 {
 655     std::string overloadName = ToUtf8(groupName);
 656     overloadName.append(1'(');
 657     bool first = true;
 658     for (const std::std::unique_ptr<BoundExpression>&argument : arguments)
 659     {
 660         bool wasFirst = first;
 661         if (first)
 662         {
 663             first = false;
 664         }
 665         else
 666         {
 667             overloadName.append(", ");
 668         }
 669         if (wasFirst&&(  groupName == U"@constructor" || groupName == U"operator="))
 670         {
 671             overloadName.append(ToUtf8(argument->GetType()->RemovePointer(spanmoduleId)->FullName()));
 672         }
 673         else
 674         {
 675             overloadName.append(ToUtf8(argument->GetType()->FullName()));
 676         }
 677     }
 678     overloadName.append(1')');
 679     return overloadName;
 680 }
 681 
 682 std::std::unique_ptr<BoundFunctionCall>FailWithNoViableFunction(conststd::u32string&groupNameconststd::std::vector<std::std::unique_ptr<BoundExpression>>&arguments
 683     const Span& spanconst boost::uuids::uuid& moduleIdOverloadResolutionFlags flagsstd::std::unique_ptr<Exception>&exception)
 684 {
 685     std::string overloadName = MakeOverloadName(groupNameargumentsspanmoduleId);
 686     int arity = arguments.size();
 687     if (groupName == U"@constructor" && arity == 1 && arguments[0]->GetType()->IsReferenceType())
 688     {
 689         if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
 690         {
 691             exception.reset(new NoViableFunctionException("overload resolution failed: '" + overloadName + "' not found. Note: reference must be initialized."spanmoduleId
 692                 arguments[0]->GetSpan()arguments[0]->ModuleId()));
 693             return std::unique_ptr<BoundFunctionCall>();
 694         }
 695         else
 696         {
 697             throw NoViableFunctionException("overload resolution failed: '" + overloadName + "' not found. Note: reference must be initialized."spanmoduleId
 698                 arguments[0]->GetSpan()arguments[0]->ModuleId());
 699         }
 700     }
 701     else
 702     {
 703         std::string note;
 704         if (exception)
 705         {
 706             note.append(": Note: ").append(exception->Message());
 707         }
 708         if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
 709         {
 710             exception.reset(new NoViableFunctionException("overload resolution failed: '" + overloadName + "' not found. " + 
 711                 "No viable functions taking " + std::to_string(arity) + " arguments found in function group '" + ToUtf8(groupName) + "'" + notespanmoduleId));
 712             return std::unique_ptr<BoundFunctionCall>();
 713         }
 714         else
 715         {
 716             throw NoViableFunctionException("overload resolution failed: '" + overloadName + "' not found. " + 
 717                 "No viable functions taking " + std::to_string(arity) + " arguments found in function group '" + ToUtf8(groupName) + "'" + notespanmoduleId);
 718         }
 719     }
 720 }
 721 
 722 std::std::unique_ptr<BoundFunctionCall>FailWithOverloadNotFound(Module*moduleconstViableFunctionSet&viableFunctionsconststd::u32string& groupName
 723     const std::std::vector<std::std::unique_ptr<BoundExpression>>&argumentsconststd::std::vector<FunctionMatch>&failedFunctionMatchesconstSpan&spanconstboost::uuids::uuid&moduleId
 724     OverloadResolutionFlags flagsstd::std::unique_ptr<Exception>&exception)
 725 {
 726     std::string overloadName = MakeOverloadName(groupNameargumentsspanmoduleId);
 727     bool referenceMustBeInitialized = false;
 728     bool castRequired = false;
 729     bool cannotBindConstArgToNonConstParam = false;
 730     bool cannotAssignToConstObject = false;
 731     TypeSymbol* sourceType = nullptr;
 732     TypeSymbol* targetType = nullptr;
 733     std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
 734     std::string note;
 735     if (exception)
 736     {
 737         note.append(" Note: ").append(exception->What());
 738     }
 739     if (!failedFunctionMatches.empty())
 740     {
 741         int n = failedFunctionMatches.size();
 742         for (int i = 0; i < n; ++i)
 743         {
 744             if (failedFunctionMatches[i].referenceMustBeInitialized)
 745             {
 746                 referenceMustBeInitialized = true;
 747                 break;
 748             }
 749         }
 750         if (!referenceMustBeInitialized)
 751         {
 752             for (int i = 0; i < n; ++i)
 753             {
 754                 if (failedFunctionMatches[i].castRequired)
 755                 {
 756                     castRequired = true;
 757                     sourceType = failedFunctionMatches[i].sourceType;
 758                     targetType = failedFunctionMatches[i].targetType;
 759                     references.push_back(std::make_pair(failedFunctionMatches[i].fun->GetSpan()failedFunctionMatches[i].fun->SourceModuleId()));
 760                     break;
 761                 }
 762             }
 763         }
 764         if (!referenceMustBeInitialized && !castRequired)
 765         {
 766             for (int i = 0; i < n; ++i)
 767             {
 768                 if (failedFunctionMatches[i].cannotBindConstArgToNonConstParam)
 769                 {
 770                     cannotBindConstArgToNonConstParam = true;
 771                     sourceType = failedFunctionMatches[i].sourceType;
 772                     targetType = failedFunctionMatches[i].targetType;
 773                     references.push_back(std::make_pair(failedFunctionMatches[i].fun->GetSpan()failedFunctionMatches[i].fun->SourceModuleId()));
 774                     break;
 775                 }
 776             }
 777         }
 778         if (!referenceMustBeInitialized && !castRequired && !cannotBindConstArgToNonConstParam)
 779         {
 780             for (int i = 0; i < n; ++i)
 781             {
 782                 if (failedFunctionMatches[i].cannotAssignToConstObject)
 783                 {
 784                     cannotAssignToConstObject = true;
 785                     references.push_back(std::make_pair(failedFunctionMatches[i].fun->GetSpan()failedFunctionMatches[i].fun->SourceModuleId()));
 786                     break;
 787                 }
 788             }
 789         }
 790         if (!referenceMustBeInitialized && !castRequired && !cannotBindConstArgToNonConstParam && !cannotAssignToConstObject)
 791         {
 792             for (int i = 0; i < n; ++i)
 793             {
 794                 if (failedFunctionMatches[i].conceptCheckException)
 795                 {
 796                     if (!note.empty())
 797                     {
 798                         note.append(".");
 799                     }
 800                     note.append(" Note: concept check failed: " + failedFunctionMatches[i].conceptCheckException->Message());
 801                     references.insert(references.end()failedFunctionMatches[i].conceptCheckException->References().begin()failedFunctionMatches[i].conceptCheckException->References().end());
 802                     break;
 803                 }
 804             }
 805         }
 806     }
 807     if (referenceMustBeInitialized || groupName == U"@constructor" && arguments.size() == 1 && arguments[0]->GetType()->IsReferenceType())
 808     {
 809         if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
 810         {
 811             references.push_back(std::make_pair(arguments[0]->GetSpan()arguments[0]->ModuleId()));
 812             exception.reset(new Exception("overload resolution failed: '" + overloadName + "' not found. Note: reference must be initialized."spanmoduleIdreferences));
 813             return std::unique_ptr<BoundFunctionCall>();
 814         }
 815         else
 816         {
 817             references.push_back(std::make_pair(arguments[0]->GetSpan()arguments[0]->ModuleId()));
 818             throw Exception("overload resolution failed: '" + overloadName + "' not found. Note: reference must be initialized."spanmoduleIdreferences);
 819         }
 820     }
 821     else if (castRequired)
 822     {
 823         Assert(sourceType"source type not set");
 824         Assert(targetType"target type not set");
 825         if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
 826         {
 827             exception.reset(new CastOverloadException("overload resolution failed: '" + overloadName + "' not found, or there are no acceptable conversions for all argument types. " + 
 828                 std::to_string(viableFunctions.Get().size()) + " viable functions examined. Note: cannot convert implicitly from '" + 
 829                 ToUtf8(sourceType->FullName()) + "' to '" + ToUtf8(targetType->FullName()) + "' but explicit conversion (cast) exists."spanmoduleIdreferences));
 830             return std::unique_ptr<BoundFunctionCall>();
 831         }
 832         else
 833         {
 834             throw CastOverloadException("overload resolution failed: '" + overloadName + "' not found, or there are no acceptable conversions for all argument types. " + 
 835                 std::to_string(viableFunctions.Get().size()) + " viable functions examined. Note: cannot convert implicitly from '" + 
 836                 ToUtf8(sourceType->FullName()) + "' to '" + ToUtf8(targetType->FullName()) + "' but explicit conversion (cast) exists."spanmoduleIdreferences);
 837         }
 838     }
 839     else if (cannotBindConstArgToNonConstParam)
 840     {
 841         Assert(sourceType"source type not set");
 842         Assert(targetType"target type not set");
 843         if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
 844         {
 845             exception.reset(new CannotBindConstToNonconstOverloadException("overload resolution failed: '" + overloadName + 
 846                 "' not found, or there are no acceptable conversions for all argument types. " + 
 847                 std::to_string(viableFunctions.Get().size()) + " viable functions examined. Note: cannot bind constant '" + ToUtf8(sourceType->FullName()) + "' argument " + 
 848                 " to nonconstant '" + ToUtf8(targetType->FullName()) + "' parameter"spanmoduleIdreferences));
 849             return std::unique_ptr<BoundFunctionCall>();
 850         }
 851         else
 852         {
 853             throw CannotBindConstToNonconstOverloadException("overload resolution failed: '" + overloadName + "' not found, or there are no acceptable conversions for all argument types. " + 
 854                 std::to_string(viableFunctions.Get().size()) + " viable functions examined. Note: cannot bind constant '" + ToUtf8(sourceType->FullName()) + "' argument " + 
 855                 " to nonconstant '" + ToUtf8(targetType->FullName()) + "' parameter"spanmoduleIdreferences);
 856         }
 857     }
 858     else if (cannotAssignToConstObject)
 859     {
 860         if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
 861         {
 862             exception.reset(new CannotAssignToConstOverloadException("overload resolution failed: '" + overloadName + 
 863                 "' not found, or there are no acceptable conversions for all argument types. " + 
 864                 std::to_string(viableFunctions.Get().size()) + " viable functions examined. Note: cannot assign to const object."spanmoduleIdreferences));
 865             return std::unique_ptr<BoundFunctionCall>();
 866         }
 867         else
 868         {
 869             throw CannotAssignToConstOverloadException("overload resolution failed: '" + overloadName + "' not found, or there are no acceptable conversions for all argument types. " + 
 870                 std::to_string(viableFunctions.Get().size()) + " viable functions examined. Note: cannot assign to const object. "spanmoduleIdreferences);
 871         }
 872     }
 873     else
 874     {
 875         if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
 876         {
 877             exception.reset(new Exception("overload resolution failed: '" + overloadName + "' not found, or there are no acceptable conversions for all argument types. " + 
 878                 std::to_string(viableFunctions.Get().size()) + " viable functions examined." + notespanmoduleIdreferences));
 879             return std::unique_ptr<BoundFunctionCall>();
 880         }
 881         else
 882         {
 883             throw Exception("overload resolution failed: '" + overloadName + "' not found, or there are no acceptable conversions for all argument types. " + 
 884                 std::to_string(viableFunctions.Get().size()) + " viable functions examined." + notespanmoduleIdreferences);
 885         }
 886     }
 887 }
 888 
 889 std::std::unique_ptr<BoundFunctionCall>FailWithAmbiguousOverload(conststd::u32string&groupNamestd::std::vector<std::std::unique_ptr<BoundExpression>>&arguments
 890     std::std::vector<FunctionMatch>&functionMatchesconstSpan&spanconstboost::uuids::uuid&moduleIdOverloadResolutionFlags flagsstd::std::unique_ptr<Exception>&exception)
 891 {
 892     std::string overloadName = MakeOverloadName(groupNameargumentsspanmoduleId);
 893     std::string matchedFunctionNames;
 894     bool first = true;
 895     FunctionMatch equalMatch = std::move(functionMatches[0]);
 896     std::vector<FunctionMatch> equalMatches;
 897     equalMatches.push_back(std::move(equalMatch));
 898     int n = int(functionMatches.size());
 899     for (int i = 1; i < n; ++i)
 900     {
 901         FunctionMatch match = std::move(functionMatches[i]);
 902         if (!BetterFunctionMatch()(equalMatches[0]match))
 903         {
 904             equalMatches.push_back(std::move(match));
 905         }
 906     }
 907     std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
 908     for (const FunctionMatch& match : equalMatches)
 909     {
 910         if (first)
 911         {
 912             first = false;
 913         }
 914         else
 915         {
 916             matchedFunctionNames.append(", or ");
 917         }
 918         matchedFunctionNames.append(ToUtf8(match.fun->FullName()));
 919         references.push_back(std::make_pair(match.fun->GetSpan()match.fun->SourceModuleId()));
 920     }
 921     if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
 922     {
 923         exception.reset(new Exception("overload resolution for overload name '" + overloadName + "' failed: call is ambiguous: \n" + matchedFunctionNamesspanmoduleIdreferences));
 924         return std::unique_ptr<BoundFunctionCall>();
 925     }
 926     else
 927     {
 928         throw Exception("overload resolution for overload name '" + overloadName + "' failed: call is ambiguous: \n" + matchedFunctionNamesspanmoduleIdreferences);
 929     }
 930 }
 931 
 932 std::std::unique_ptr<BoundFunctionCall>CreateBoundFunctionCall(FunctionSymbol*bestFunstd::std::vector<std::std::unique_ptr<BoundExpression>>&argumentsBoundCompileUnit&boundCompileUnit
 933     BoundFunction* boundFunctionconst FunctionMatch& bestMatchContainerScope* containerScopeconst Span& spanconst boost::uuids::uuid& moduleId)
 934 {
 935     std::unique_ptr<BoundFunctionCall> boundFunctionCall(new BoundFunctionCall(spanmoduleIdbestFun));
 936     int arity = arguments.size();
 937     int n = std::min(aritybestFun->Arity());
 938     for (int i = 0; i < n; ++i)
 939     {
 940         std::std::unique_ptr<BoundExpression>&argument=arguments[i];
 941         if (i == 0 && !bestFun->IsConstructorDestructorOrNonstaticMemberFunction() && 
 942             (bestFun->GroupName() == U"@constructor" || bestFun->GroupName() == U"operator=" || bestFun->GroupName() == U"operator->"))
 943         {
 944             if (argument->GetBoundNodeType() == BoundNodeType::boundAddressOfExpression)
 945             {
 946                 BoundAddressOfExpression* addrOf = static_cast<BoundAddressOfExpression*>(argument.get());
 947                 std::unique_ptr<BoundExpression> subject(std::move(addrOf->Subject()));
 948                 addrOf->MoveTemporaryDestructorCallsTo(*subject);
 949                 argument.reset(subject.release());
 950             }
 951         }
 952         const ArgumentMatch& argumentMatch = bestMatch.argumentMatches[i];
 953         if (argumentMatch.preReferenceConversionFlags != OperationFlags::none)
 954         {
 955             if (argumentMatch.preReferenceConversionFlags == OperationFlags::addr)
 956             {
 957                 if (!argument->IsLvalueExpression())
 958                 {
 959                     BoundLocalVariable* backingStore = nullptr;
 960                     if (boundFunction)
 961                     {
 962                         backingStore = new BoundLocalVariable(spanmoduleIdboundFunction->GetFunctionSymbol()->CreateTemporary(argument->GetType()spanmoduleId));
 963                     }
 964                     argument.reset(new BoundTemporary(std::move(argument)std::unique_ptr<BoundLocalVariable>(backingStore)));
 965                 }
 966                 TypeSymbol* type = nullptr;
 967                 if (argument->GetType()->IsClassTypeSymbol() && argument->GetFlag(BoundExpressionFlags::bindToRvalueReference))
 968                 {
 969                     type = argument->GetType()->AddRvalueReference(spanmoduleId);
 970                 }
 971                 else
 972                 {
 973                     type = argument->GetType()->AddLvalueReference(spanmoduleId);
 974                 }
 975                 BoundAddressOfExpression* addressOfExpression = new BoundAddressOfExpression(std::move(argument)type);
 976                 argument.reset(addressOfExpression);
 977             }
 978             else if (argumentMatch.preReferenceConversionFlags == OperationFlags::deref)
 979             {
 980                 TypeSymbol* type = argument->GetType()->RemoveReference(spanmoduleId);
 981                 BoundDereferenceExpression* dereferenceExpression = new BoundDereferenceExpression(std::move(argument)type);
 982                 argument.reset(dereferenceExpression);
 983             }
 984         }
 985         if (argumentMatch.conversionFun)
 986         {
 987             FunctionSymbol* conversionFun = argumentMatch.conversionFun;
 988             if (conversionFun->GetSymbolType() == SymbolType::constructorSymbol)
 989             {
 990                 if (!boundFunction)
 991                 {
 992                     return std::unique_ptr<BoundFunctionCall>();
 993                 }
 994                 BoundFunctionCall* constructorCall = new BoundFunctionCall(spanmoduleIdconversionFun);
 995                 TypeSymbol* conversionTargetType = conversionFun->ConversionTargetType();
 996                 LocalVariableSymbol* temporary = boundFunction->GetFunctionSymbol()->CreateTemporary(conversionTargetTypespanmoduleId);
 997                 constructorCall->AddArgument(std::unique_ptr<BoundExpression>(new BoundAddressOfExpression(std::unique_ptr<BoundExpression>(new BoundLocalVariable(spanmoduleIdtemporary))
 998                     conversionTargetType->AddPointer(spanmoduleId))));
 999                 if (conversionTargetType->IsClassTypeSymbol())
1000                 {
1001                     ClassTypeSymbol* classType = static_cast<ClassTypeSymbol*>(conversionTargetType);
1002                     if (classType->Destructor())
1003                     {
1004                         std::unique_ptr<BoundFunctionCall> destructorCall(new BoundFunctionCall(spanmoduleIdclassType->Destructor()));
1005                         destructorCall->AddArgument(std::unique_ptr<BoundExpression>(constructorCall->Arguments()[0]->Clone()));
1006                         boundFunction->AddTemporaryDestructorCall(std::move(destructorCall)boundFunctioncontainerScopespanmoduleId);
1007                     }
1008                 }
1009                 constructorCall->AddArgument(std::move(argument));
1010                 std::vector<LocalVariableSymbol*> temporaryLocalVariables = conversionFun->CreateTemporariesTo(boundFunction->GetFunctionSymbol());
1011                 for (LocalVariableSymbol* temporaryLocalVariable : temporaryLocalVariables)
1012                 {
1013                     constructorCall->AddTemporary(std::unique_ptr<BoundLocalVariable>(new BoundLocalVariable(spanmoduleIdtemporaryLocalVariable)));
1014                 }
1015                 BoundConstructAndReturnTemporaryExpression* conversion = new BoundConstructAndReturnTemporaryExpression(std::unique_ptr<BoundExpression>(constructorCall)
1016                     std::unique_ptr<BoundExpression>(new BoundLocalVariable(spanmoduleIdtemporary)));
1017                 argument.reset(conversion);
1018             }
1019             else if (conversionFun->GetSymbolType() == SymbolType::conversionFunctionSymbol && conversionFun->ReturnsClassInterfaceOrClassDelegateByValue())
1020             {
1021                 if (!boundFunction)
1022                 {
1023                     return std::unique_ptr<BoundFunctionCall>();
1024                 }
1025                 BoundFunctionCall* conversionFunctionCall = new BoundFunctionCall(spanmoduleIdconversionFun);
1026                 conversionFunctionCall->AddArgument(std::move(argument));
1027                 TypeSymbol* conversionTargetType = conversionFun->ConversionTargetType();
1028                 LocalVariableSymbol* temporary = boundFunction->GetFunctionSymbol()->CreateTemporary(conversionTargetTypespanmoduleId);
1029                 conversionFunctionCall->AddArgument(std::unique_ptr<BoundExpression>(new BoundAddressOfExpression(std::unique_ptr<BoundExpression>(new BoundLocalVariable(spanmoduleIdtemporary))
1030                     conversionTargetType->AddPointer(spanmoduleId))));
1031                 std::vector<LocalVariableSymbol*> temporaryLocalVariables = conversionFun->CreateTemporariesTo(boundFunction->GetFunctionSymbol());
1032                 for (LocalVariableSymbol* temporaryLocalVariable : temporaryLocalVariables)
1033                 {
1034                     conversionFunctionCall->AddTemporary(std::unique_ptr<BoundLocalVariable>(new BoundLocalVariable(spanmoduleIdtemporaryLocalVariable)));
1035                 }
1036                 BoundLocalVariable* conversionResult = new BoundLocalVariable(spanmoduleIdtemporary);
1037                 if (conversionTargetType->IsClassTypeSymbol())
1038                 {
1039                     ClassTypeSymbol* classType = static_cast<ClassTypeSymbol*>(conversionTargetType);
1040                     if (classType->Destructor())
1041                     {
1042                         std::unique_ptr<BoundFunctionCall> destructorCall(new BoundFunctionCall(spanmoduleIdclassType->Destructor()));
1043                         TypeSymbol* type = conversionResult->GetType()->AddPointer(spanmoduleId);
1044                         destructorCall->AddArgument(std::unique_ptr<BoundExpression>(new BoundAddressOfExpression(std::unique_ptr<BoundExpression>(conversionResult->Clone())type)));
1045                         boundFunction->AddTemporaryDestructorCall(std::move(destructorCall)boundFunctioncontainerScopespanmoduleId);
1046                     }
1047                 }
1048                 BoundClassOrClassDelegateConversionResult* conversion = new BoundClassOrClassDelegateConversionResult(std::unique_ptr<BoundExpression>(conversionResult)
1049                     std::unique_ptr<BoundFunctionCall>(conversionFunctionCall));
1050                 argument.reset(conversion);
1051             }
1052             else
1053             {
1054                 BoundConversion* conversion = new BoundConversion(std::move(argument)conversionFun);
1055                 std::vector<LocalVariableSymbol*> temporaryLocalVariables = conversionFun->CreateTemporariesTo(boundFunction->GetFunctionSymbol());
1056                 for (LocalVariableSymbol* temporaryLocalVariable : temporaryLocalVariables)
1057                 {
1058                     conversion->AddTemporary(std::unique_ptr<BoundLocalVariable>(new BoundLocalVariable(spanmoduleIdtemporaryLocalVariable)));
1059                 }
1060                 argument.reset(conversion);
1061             }
1062         }
1063         if (argumentMatch.postReferenceConversionFlags != OperationFlags::none)
1064         {
1065             if (argumentMatch.postReferenceConversionFlags == OperationFlags::addr)
1066             {
1067                 if (!argument->IsLvalueExpression())
1068                 {
1069                     BoundLocalVariable* backingStore = nullptr;
1070                     if (boundFunction)
1071                     {
1072                         backingStore = new BoundLocalVariable(spanmoduleIdboundFunction->GetFunctionSymbol()->CreateTemporary(argument->GetType()spanmoduleId));
1073                     }
1074                     argument.reset(new BoundTemporary(std::move(argument)std::unique_ptr<BoundLocalVariable>(backingStore)));
1075                 }
1076                 TypeSymbol* type = nullptr;
1077                 if (argument->GetType()->IsClassTypeSymbol() && argument->GetFlag(BoundExpressionFlags::bindToRvalueReference))
1078                 {
1079                     type = argument->GetType()->AddRvalueReference(spanmoduleId);
1080                 }
1081                 else
1082                 {
1083                     type = argument->GetType()->AddLvalueReference(spanmoduleId);
1084                 }
1085                 BoundAddressOfExpression* addressOfExpression = new BoundAddressOfExpression(std::move(argument)type);
1086                 argument.reset(addressOfExpression);
1087             }
1088             else if (argumentMatch.postReferenceConversionFlags == OperationFlags::deref)
1089             {
1090                 TypeSymbol* type = argument->GetType()->RemoveReference(spanmoduleId);
1091                 BoundDereferenceExpression* dereferenceExpression = new BoundDereferenceExpression(std::move(argument)type);
1092                 argument.reset(dereferenceExpression);
1093             }
1094         }
1095         if (argument->GetType()->IsClassTypeSymbol() || argument->GetType()->GetSymbolType() == SymbolType::classDelegateTypeSymbol || argument->GetType()->GetSymbolType() == SymbolType::interfaceTypeSymbol)
1096         {
1097             if (argument->GetType()->IsClassTypeSymbol())
1098             {
1099                 ClassTypeSymbol* classType = static_cast<ClassTypeSymbol*>(argument->GetType());
1100                 if (!classType->CopyConstructor())
1101                 {
1102                     try
1103                     {
1104                         boundCompileUnit.GenerateCopyConstructorFor(classTypecontainerScopeboundFunctionspanmoduleId);
1105                     }
1106                     catch (const Exception& ex;)
1107                     {
1108                         std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
1109                         references.push_back(std::make_pair(ex.Defined()ex.DefinedModuleId()));
1110                         references.insert(references.end()ex.References().begin()ex.References().end());
1111                         throw Exception("cannot pass class '" + ToUtf8(classType->FullName()) + "' by value because: " + ex.Message()argument->GetSpan()argument->ModuleId()references);
1112                     }
1113                 }
1114                 TypeSymbol* type = classType->AddConst(spanmoduleId)->AddLvalueReference(spanmoduleId);
1115                 argument.reset(new BoundAddressOfExpression(std::move(argument)type));
1116             }
1117             else if (argument->GetType()->GetSymbolType() == SymbolType::classDelegateTypeSymbol)
1118             {
1119                 TypeSymbol* type = argument->GetType()->AddConst(spanmoduleId)->AddLvalueReference(spanmoduleId);
1120                 argument.reset(new BoundAddressOfExpression(std::move(argument)type));
1121             }
1122             else if (argument->GetType()->GetSymbolType() == SymbolType::interfaceTypeSymbol)
1123             {
1124                 InterfaceTypeSymbol* interfaceTypeSymbol = static_cast<InterfaceTypeSymbol*>(argument->GetType());
1125                 if (!interfaceTypeSymbol->CopyConstructor())
1126                 {
1127                     boundCompileUnit.GenerateCopyConstructorFor(interfaceTypeSymbolcontainerScopeboundFunctionspanmoduleId);
1128                 }
1129                 TypeSymbol* type = argument->GetType()->AddConst(spanmoduleId)->AddLvalueReference(spanmoduleId);
1130                 argument.reset(new BoundAddressOfExpression(std::move(argument)type));
1131             }
1132         }
1133         boundFunctionCall->AddArgument(std::move(argument));
1134     }
1135     for (int i = n; i < arity; ++i)
1136     {
1137         std::std::unique_ptr<BoundExpression>&argument=arguments[i];
1138         boundFunctionCall->AddArgument(std::move(argument));
1139     }
1140     if (boundFunction)
1141     {
1142         std::vector<LocalVariableSymbol*> temporaryLocalVariables = bestFun->CreateTemporariesTo(boundFunction->GetFunctionSymbol());
1143         for (LocalVariableSymbol* temporaryLocalVariable : temporaryLocalVariables)
1144         {
1145             boundFunctionCall->AddTemporary(std::unique_ptr<BoundLocalVariable>(new BoundLocalVariable(spanmoduleIdtemporaryLocalVariable)));
1146         }
1147     }
1148     FunctionSymbol* functionSymbol = boundFunctionCall->GetFunctionSymbol();
1149     if (functionSymbol->GetSymbolType() == SymbolType::destructorSymbol)
1150     {
1151         DestructorSymbol* destructorSymbol = static_cast<DestructorSymbol*>(functionSymbol);
1152         if (destructorSymbol->IsGeneratedFunction() && !GetGlobalFlag(GlobalFlags::info))
1153         {
1154             if (destructorSymbol->Parent()->IsClassTypeSymbol())
1155             {
1156                 ClassTypeSymbol* classType = static_cast<ClassTypeSymbol*>(destructorSymbol->Parent());
1157                 if (!boundCompileUnit.IsGeneratedDestructorInstantiated(destructorSymbol))
1158                 {
1159                     boundCompileUnit.SetGeneratedDestructorInstantiated(destructorSymbol);
1160                     std::unique_ptr<BoundClass> boundClass(new BoundClass(classType));
1161                     GenerateDestructorImplementation(boundClass.get()destructorSymbolboundCompileUnitcontainerScopeboundFunctionspanmoduleId);
1162                     boundCompileUnit.AddBoundNode(std::move(boundClass));
1163                 }
1164             }
1165         }
1166     }
1167     return boundFunctionCall;
1168 }
1169 
1170 std::std::unique_ptr<BoundFunctionCall>SelectViableFunction(constViableFunctionSet&viableFunctionsconststd::u32string&groupName
1171     std::std::vector<std::std::unique_ptr<BoundExpression>>&argumentsContainerScope*containerScopeBoundCompileUnit&boundCompileUnitBoundFunction*boundFunction
1172     const Span& spanconst boost::uuids::uuid& moduleId
1173     OverloadResolutionFlags flagsstd::std::vector<TypeSymbol*>&templateArgumentTypesstd::std::unique_ptr<Exception>&exception)
1174 {
1175     Module* module = &boundCompileUnit.GetModule();
1176     std::vector<FunctionMatch> functionMatches;
1177     std::vector<FunctionMatch> failedFunctionMatches;
1178     std::vector<std::std::unique_ptr<Exception>>conceptCheckExceptions;
1179     std::vector<std::std::unique_ptr<BoundConstraint>>boundConstraints;
1180     for (FunctionSymbol* viableFunction : viableFunctions.Get())
1181     {
1182         if (viableFunction->GetFlag(FunctionSymbolFlags::dontReuse))
1183         {
1184             if (!boundCompileUnit.CanReuse(viableFunction))
1185             {
1186                 continue;
1187             }
1188         }
1189         if (viableFunction->IsSystemDefault())
1190         {
1191             if ((flags & OverloadResolutionFlags::includeSystemDefaultFunctions) == OverloadResolutionFlags::none)
1192             {
1193                 continue;
1194             }
1195         }
1196         FunctionMatch functionMatch(viableFunction);
1197         if (viableFunction->IsFunctionTemplate())
1198         {
1199             if ((flags & OverloadResolutionFlags::noTemplates) != OverloadResolutionFlags::none)
1200             {
1201                 continue;
1202             }
1203             int n = templateArgumentTypes.size();
1204             if (n > viableFunction->TemplateParameters().size())
1205             {
1206                 continue;
1207             }
1208             else
1209             {
1210                 for (int i = 0; i < n; ++i)
1211                 {
1212                     TemplateParameterSymbol* templateParameter = viableFunction->TemplateParameters()[i];
1213                     functionMatch.templateParameterMap[templateParameter] = templateArgumentTypes[i];
1214                 }
1215             }
1216         }
1217         else
1218         {
1219             if (!templateArgumentTypes.empty())
1220             {
1221                 continue;
1222             }
1223         }
1224         if (FindConversions(boundCompileUnitviableFunctionargumentsfunctionMatchConversionType::implicit_containerScopeboundFunctionspanmoduleId))
1225         {
1226             if (viableFunction->IsFunctionTemplate())
1227             {
1228                 bool allTemplateParametersFound = true;
1229                 int n = viableFunction->TemplateParameters().size();
1230                 for (int i = 0; i < n; ++i)
1231                 {
1232                     TemplateParameterSymbol* templateParameterSymbol = viableFunction->TemplateParameters()[i];
1233                     auto it = functionMatch.templateParameterMap.find(templateParameterSymbol);
1234                     if (it == functionMatch.templateParameterMap.cend())
1235                     {
1236                         allTemplateParametersFound = false;
1237                         break;
1238                     }
1239                 }
1240                 if (allTemplateParametersFound)
1241                 {
1242                     if (!viableFunction->Constraint())
1243                     {
1244                         Node* node = boundCompileUnit.GetSymbolTable().GetNodeNoThrow(viableFunction);
1245                         if (node)
1246                         {
1247                             Assert(node->GetNodeType() == NodeType::functionNode"function node expected");
1248                             FunctionNode* functionNode = static_cast<FunctionNode*>(node);
1249                             ConstraintNode* constraint = functionNode->WhereConstraint();
1250                             if (constraint)
1251                             {
1252                                 CloneContext cloneContext;
1253                                 viableFunction->SetConstraint(static_cast<ConstraintNode*>(constraint->Clone(cloneContext)));
1254                             }
1255                         }
1256                     }
1257                     if (viableFunction->Constraint())
1258                     {
1259                         std::unique_ptr<Exception> conceptCheckException;
1260                         std::unique_ptr<BoundConstraint> boundConstraint;
1261                         bool candidateFound = CheckConstraint(viableFunction->Constraint()viableFunction->UsingNodes()boundCompileUnitcontainerScopeboundFunction
1262                             viableFunction->TemplateParameters()functionMatch.templateParameterMapboundConstraintspanmoduleIdviableFunctionconceptCheckException);
1263                         if (candidateFound)
1264                         {
1265                             functionMatch.boundConstraint = boundConstraint.get();
1266                             functionMatches.push_back(functionMatch);
1267                             boundConstraints.push_back(std::move(boundConstraint));
1268                         }
1269                         else
1270                         {
1271                             functionMatch.conceptCheckException = conceptCheckException.get();
1272                             failedFunctionMatches.push_back(functionMatch);
1273                             conceptCheckExceptions.push_back(std::move(conceptCheckException));
1274                         }
1275                     }
1276                     else
1277                     {
1278                         functionMatches.push_back(functionMatch);
1279                     }
1280                 }
1281                 else
1282                 {
1283                     failedFunctionMatches.push_back(functionMatch);
1284                 }
1285             }
1286             else
1287             {
1288                 functionMatches.push_back(functionMatch);
1289             }
1290         }
1291         else
1292         {
1293             failedFunctionMatches.push_back(functionMatch);
1294         }
1295     }
1296     if (functionMatches.empty())
1297     {
1298         if ((flags & OverloadResolutionFlags::includeSystemDefaultFunctions) == OverloadResolutionFlags::none)
1299         {
1300             return SelectViableFunction(viableFunctionsgroupNameargumentscontainerScopeboundCompileUnitboundFunctionspanmoduleId
1301                 (flags | OverloadResolutionFlags::includeSystemDefaultFunctions)templateArgumentTypesexception);
1302         }
1303         return FailWithOverloadNotFound(moduleviableFunctionsgroupNameargumentsfailedFunctionMatchesspanmoduleIdflagsexception);
1304     }
1305     else if (functionMatches.size() > 1)
1306     {
1307         std::sort(functionMatches.begin()functionMatches.end()BetterFunctionMatch());
1308         if (BetterFunctionMatch()(functionMatches[0]functionMatches[1]))
1309         {
1310             const FunctionMatch& bestMatch = functionMatches[0];
1311             FunctionSymbol* bestFun = bestMatch.fun;
1312             if (bestFun->IsSuppressed())
1313             {
1314                 if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
1315                 {
1316                     exception.reset(new Exception("cannot call a suppressed member function '" + ToUtf8(bestFun->FullName()) + "'"spanmoduleIdbestFun->GetSpan()bestFun->SourceModuleId()));
1317                     return std::unique_ptr<BoundFunctionCall>();
1318                 }
1319                 else
1320                 {
1321                     throw Exception("cannot call a suppressed member function '" + ToUtf8(bestFun->FullName()) + "'"spanmoduleIdbestFun->GetSpan()bestFun->SourceModuleId());
1322                 }
1323             }
1324             bool instantiate = (flags & OverloadResolutionFlags::dontInstantiate) == OverloadResolutionFlags::none;
1325             if (bestFun->IsFunctionTemplate())
1326             {
1327                 if (instantiate)
1328                 {
1329                     bestFun = boundCompileUnit.InstantiateFunctionTemplate(bestFunbestMatch.templateParameterMapspanmoduleId);
1330                 }
1331                 else
1332                 {
1333                     templateArgumentTypes.clear();
1334                     for (TemplateParameterSymbol* templateParameter : bestFun->TemplateParameters())
1335                     {
1336                         auto it = bestMatch.templateParameterMap.find(templateParameter);
1337                         if (it != bestMatch.templateParameterMap.cend())
1338                         {
1339                             TypeSymbol* templateArgumentType = it->second;
1340                             templateArgumentTypes.push_back(templateArgumentType);
1341                         }
1342                     }
1343                 }
1344             }
1345             else if (!bestFun->IsGeneratedFunction() && bestFun->Parent()->GetSymbolType() == SymbolType::classTemplateSpecializationSymbol)
1346             {
1347                 if (instantiate)
1348                 {
1349                     ClassTemplateSpecializationSymbol* specialization = static_cast<ClassTemplateSpecializationSymbol*>(bestFun->Parent());
1350                     if (specialization->GetModule() != module)
1351                     {
1352                         specialization = boundCompileUnit.GetSymbolTable().GetCurrentClassTemplateSpecialization(specialization);
1353                         int index = bestFun->GetIndex();
1354                         bestFun = specialization->GetFunctionByIndex(index);
1355                     }
1356                     bool firstTry = boundCompileUnit.InstantiateClassTemplateMemberFunction(bestFuncontainerScopeboundFunctionspanmoduleId);
1357                     if (!firstTry)
1358                     {
1359                         ClassTemplateSpecializationSymbol* specialization = static_cast<ClassTemplateSpecializationSymbol*>(bestFun->Parent());
1360                         std::lock_guard<std::recursive_mutex> lock(boundCompileUnit.GetModule().GetLock());
1361                         ClassTemplateSpecializationSymbol* copy = boundCompileUnit.GetSymbolTable().CopyClassTemplateSpecialization(specialization);
1362                         boundCompileUnit.GetClassTemplateRepository().BindClassTemplateSpecialization(
1363                             copyboundCompileUnit.GetSymbolTable().GlobalNs().GetContainerScope()spanmoduleId);
1364                         int index = bestFun->GetIndex();
1365                         bestFun = copy->GetFunctionByIndex(index);
1366                         bool secondTry = boundCompileUnit.InstantiateClassTemplateMemberFunction(bestFuncontainerScopeboundFunctionspanmoduleId);
1367                         if (!secondTry)
1368                         {
1369                             throw Exception("internal error: could not instantiate member function of a class template specialization '" + ToUtf8(specialization->FullName()) + "'"
1370                                 specialization->GetSpan()specialization->SourceModuleId());
1371                         }
1372                     }
1373                 }
1374             }
1375             else if (!bestFun->IsGeneratedFunction() && GetGlobalFlag(GlobalFlags::release) && bestFun->IsInline())
1376             {
1377                 if (instantiate)
1378                 {
1379                     if (bestFun->IsTemplateSpecialization())
1380                     {
1381                         FunctionSymbol* functionTemplate = bestFun->FunctionTemplate();
1382                         std::unordered_map<TemplateParameterSymbol*TypeSymbol*> templateParameterMap;
1383                         int n = functionTemplate->TemplateParameters().size();
1384                         for (int i = 0; i < n; ++i)
1385                         {
1386                             TemplateParameterSymbol* templateParameter = functionTemplate->TemplateParameters()[i];
1387                             TypeSymbol* templateArgumentType = bestFun->TemplateArgumentTypes()[i];
1388                             templateParameterMap[templateParameter] = templateArgumentType;
1389                         }
1390                         bestFun = boundCompileUnit.InstantiateFunctionTemplate(functionTemplatetemplateParameterMapspanmoduleId);
1391                     }
1392                     else
1393                     {
1394                         bestFun = boundCompileUnit.InstantiateInlineFunction(bestFuncontainerScopespanmoduleId);
1395                     }
1396                 }
1397             }
1398             if (boundFunction && boundFunction->GetFunctionSymbol()->DontThrow() && !boundFunction->GetFunctionSymbol()->HasTry() && !bestFun->DontThrow())
1399             {
1400                 std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
1401                 references.push_back(std::make_pair(boundFunction->GetFunctionSymbol()->GetSpan()boundFunction->GetFunctionSymbol()->SourceModuleId()));
1402                 references.push_back(std::make_pair(bestFun->GetSpan()bestFun->SourceModuleId()));
1403                 if (GetGlobalFlag(GlobalFlags::strictNothrow))
1404                 {
1405                     if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
1406                     {
1407                         exception.reset(new Exception("a nothrow function cannot call a function that can throw unless it handles exceptions (compiled with --strict-nothrow)"spanmoduleIdreferences));
1408                         return std::unique_ptr<BoundFunctionCall>();
1409                     }
1410                     else
1411                     {
1412                         throw Exception("a nothrow function cannot call a function that can throw unless it handles exceptions (compiled with --strict-nothrow)"spanmoduleIdreferences);
1413                     }
1414                 }
1415                 else
1416                 {
1417                     Warning warning(module->GetCurrentProjectName()"a nothrow function calls a function that can throw and does not handle exceptions");
1418                     warning.SetDefined(spanmoduleId);
1419                     warning.SetReferences(references);
1420                     module->WarningCollection().AddWarning(warning);
1421                 }
1422             }
1423             return CreateBoundFunctionCall(bestFunargumentsboundCompileUnitboundFunctionbestMatchcontainerScopespanmoduleId);
1424         }
1425         else
1426         {
1427             return FailWithAmbiguousOverload(groupNameargumentsfunctionMatchesspanmoduleIdflagsexception);
1428         }
1429     }
1430     else
1431     {
1432         const FunctionMatch& bestMatch = functionMatches[0];
1433         FunctionSymbol* singleBest = bestMatch.fun;
1434         if (singleBest->IsSuppressed())
1435         {
1436             if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
1437             {
1438                 exception.reset(new Exception("cannot call a suppressed member function '" + ToUtf8(singleBest->FullName()) + "'"spanmoduleIdsingleBest->GetSpan()singleBest->SourceModuleId()));
1439                 return std::unique_ptr<BoundFunctionCall>();
1440             }
1441             else
1442             {
1443                 throw Exception("cannot call a suppressed member function '" + ToUtf8(singleBest->FullName()) + "'"spanmoduleIdsingleBest->GetSpan()singleBest->SourceModuleId());
1444             }
1445         }
1446         bool instantiate = (flags & OverloadResolutionFlags::dontInstantiate) == OverloadResolutionFlags::none;
1447         if (singleBest->IsFunctionTemplate())
1448         {
1449             if (instantiate)
1450             {
1451                 singleBest = boundCompileUnit.InstantiateFunctionTemplate(singleBestbestMatch.templateParameterMapspanmoduleId);
1452             }
1453             else
1454             {
1455                 templateArgumentTypes.clear();
1456                 for (TemplateParameterSymbol* templateParameter : singleBest->TemplateParameters())
1457                 {
1458                     auto it = bestMatch.templateParameterMap.find(templateParameter);
1459                     if (it != bestMatch.templateParameterMap.cend())
1460                     {
1461                         TypeSymbol* templateArgumentType = it->second;
1462                         templateArgumentTypes.push_back(templateArgumentType);
1463                     }
1464                 }
1465             }
1466         }
1467         else if (!singleBest->IsGeneratedFunction() && singleBest->Parent()->GetSymbolType() == SymbolType::classTemplateSpecializationSymbol)
1468         {
1469             if (instantiate)
1470             {
1471                 ClassTemplateSpecializationSymbol* specialization = static_cast<ClassTemplateSpecializationSymbol*>(singleBest->Parent());
1472                 if (specialization->GetModule() != module)
1473                 {
1474                     specialization = boundCompileUnit.GetSymbolTable().GetCurrentClassTemplateSpecialization(specialization);
1475                     int index = singleBest->GetIndex();
1476                     singleBest = specialization->GetFunctionByIndex(index);
1477                 }
1478                 bool firstTry = boundCompileUnit.InstantiateClassTemplateMemberFunction(singleBestcontainerScopeboundFunctionspanmoduleId);
1479                 if (!firstTry)
1480                 {
1481                     std::lock_guard<std::recursive_mutex> lock(boundCompileUnit.GetModule().Lock());
1482                     ClassTemplateSpecializationSymbol* copy = boundCompileUnit.GetSymbolTable().CopyClassTemplateSpecialization(specialization);
1483                     boundCompileUnit.GetClassTemplateRepository().BindClassTemplateSpecialization(copyboundCompileUnit.GetSymbolTable().GlobalNs().GetContainerScope()spanmoduleId);
1484                     int index = singleBest->GetIndex();
1485                     singleBest = copy->GetFunctionByIndex(index);
1486                     bool secondTry = boundCompileUnit.InstantiateClassTemplateMemberFunction(singleBestcontainerScopeboundFunctionspanmoduleId);
1487                     if (!secondTry)
1488                     {
1489                         throw Exception("internal error: could not instantiate member function of a class template specialization '" + ToUtf8(specialization->FullName()) + "'"
1490                             specialization->GetSpan()specialization->SourceModuleId());
1491                     }
1492                 }
1493             }
1494         }
1495         else if (!singleBest->IsGeneratedFunction() && GetGlobalFlag(GlobalFlags::release) && singleBest->IsInline())
1496         {
1497             if (instantiate)
1498             {
1499                 if (singleBest->IsTemplateSpecialization())
1500                 {
1501                     FunctionSymbol* functionTemplate = singleBest->FunctionTemplate();
1502                     std::unordered_map<TemplateParameterSymbol*TypeSymbol*> templateParameterMap;
1503                     int n = functionTemplate->TemplateParameters().size();
1504                     for (int i = 0; i < n; ++i)
1505                     {
1506                         TemplateParameterSymbol* templateParameter = functionTemplate->TemplateParameters()[i];
1507                         TypeSymbol* templateArgumentType = singleBest->TemplateArgumentTypes()[i];
1508                         templateParameterMap[templateParameter] = templateArgumentType;
1509                     }
1510                     singleBest = boundCompileUnit.InstantiateFunctionTemplate(functionTemplatetemplateParameterMapspanmoduleId);
1511                 }
1512                 else
1513                 {
1514                     singleBest = boundCompileUnit.InstantiateInlineFunction(singleBestcontainerScopespanmoduleId);
1515                 }
1516             }
1517         }
1518         if (boundFunction && boundFunction->GetFunctionSymbol()->DontThrow() && !boundFunction->GetFunctionSymbol()->HasTry() && !singleBest->DontThrow())
1519         {
1520             std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
1521             references.push_back(std::make_pair(boundFunction->GetFunctionSymbol()->GetSpan()boundFunction->GetFunctionSymbol()->SourceModuleId()));
1522             references.push_back(std::make_pair(singleBest->GetSpan()singleBest->SourceModuleId()));
1523             if (GetGlobalFlag(GlobalFlags::strictNothrow))
1524             {
1525                 if ((flags & OverloadResolutionFlags::dontThrow) != OverloadResolutionFlags::none)
1526                 {
1527                     exception.reset(new Exception("a nothrow function cannot call a function that can throw unless it handles exceptions (compiled with --strict-nothrow)"spanmoduleIdreferences));
1528                     return std::unique_ptr<BoundFunctionCall>();
1529                 }
1530                 else
1531                 {
1532                     throw Exception("a nothrow function cannot call a function that can throw unless it handles exceptions (compiled with --strict-nothrow)"spanmoduleIdreferences);
1533                 }
1534             }
1535             else
1536             {
1537                 Warning warning(module->GetCurrentProjectName()"a nothrow function calls a function that can throw and does not handle exceptions");
1538                 warning.SetDefined(spanmoduleId);
1539                 warning.SetReferences(references);
1540                 module->WarningCollection().AddWarning(warning);
1541             }
1542         }
1543         return CreateBoundFunctionCall(singleBestargumentsboundCompileUnitboundFunctionbestMatchcontainerScopespanmoduleId);
1544     }
1545 }
1546 
1547 void CollectViableFunctionsFromSymbolTable(int arityconst std::u32string& groupNameconst std::std::vector<FunctionScopeLookup>&functionScopeLookupsBoundCompileUnit&boundCompileUnit
1548     ViableFunctionSet& viableFunctions)
1549 {
1550     std::unordered_set<ContainerScope*> scopesLookedUp;
1551     bool fileScopesLookedUp = false;
1552     for (const FunctionScopeLookup& functionScopeLookup : functionScopeLookups)
1553     {
1554         if (functionScopeLookup.scopeLookup == ScopeLookup::fileScopes && !fileScopesLookedUp)
1555         {
1556             fileScopesLookedUp = true;
1557             for (const std::std::unique_ptr<FileScope>&fileScope : boundCompileUnit.FileScopes())
1558             {
1559                 fileScope->CollectViableFunctions(aritygroupNamescopesLookedUpviableFunctions&boundCompileUnit.GetModule());
1560             }
1561         }
1562         else
1563         {
1564             ContainerScope* scope = functionScopeLookup.scope;
1565             scope->CollectViableFunctions(aritygroupNamescopesLookedUpfunctionScopeLookup.scopeLookupviableFunctions&boundCompileUnit.GetModule());
1566         }
1567     }
1568 }
1569 
1570 std::std::unique_ptr<BoundFunctionCall>ResolveOverload(conststd::u32string&groupNameContainerScope*containerScopeconststd::std::vector<FunctionScopeLookup>&functionScopeLookups
1571     std::std::vector<std::std::unique_ptr<BoundExpression>>&argumentsBoundCompileUnit&boundCompileUnitBoundFunction*currentFunctionconstSpan&spanconstboost::uuids::uuid&moduleId)
1572 {
1573     std::unique_ptr<Exception> exception;
1574     std::vector<TypeSymbol*> templateArgumentTypes;
1575     return ResolveOverload(groupNamecontainerScopefunctionScopeLookupsargumentsboundCompileUnitcurrentFunctionspanmoduleId
1576         OverloadResolutionFlags::nonetemplateArgumentTypesexception);
1577 }
1578 
1579 std::std::unique_ptr<BoundFunctionCall>ResolveOverload(conststd::u32string&groupNameContainerScope*containerScopeconststd::std::vector<FunctionScopeLookup>&functionScopeLookups
1580     std::std::vector<std::std::unique_ptr<BoundExpression>>&argumentsBoundCompileUnit&boundCompileUnitBoundFunction*currentFunctionconstSpan&spanconstboost::uuids::uuid&moduleId
1581     OverloadResolutionFlags flagsstd::std::vector<TypeSymbol*>&templateArgumentTypesstd::std::unique_ptr<Exception>&exception)
1582 {
1583     Module* module = &boundCompileUnit.GetModule();
1584     int arity = arguments.size();
1585     ViableFunctionSet viableFunctions;
1586     if (currentFunction)
1587     {
1588         CollectFlags collectFlags = CollectFlags::none;
1589         if ((flags & OverloadResolutionFlags::noRvalueRef) != OverloadResolutionFlags::none)
1590         {
1591             collectFlags = collectFlags | CollectFlags::noRvalueRef;
1592         }
1593         boundCompileUnit.CollectViableFunctions(groupNamecontainerScopeargumentscurrentFunctionviableFunctionsexceptionspanmoduleIdcollectFlags);
1594     }
1595     if (viableFunctions.Get().empty())
1596     {
1597         if ((flags & OverloadResolutionFlags::dontThrow) == OverloadResolutionFlags::none && exception)
1598         {
1599             throw *exception;
1600         }
1601         CollectViableFunctionsFromSymbolTable(aritygroupNamefunctionScopeLookupsboundCompileUnitviableFunctions);
1602     }
1603     if (viableFunctions.Get().empty())
1604     {
1605         return FailWithNoViableFunction(groupNameargumentsspanmoduleIdflagsexception);
1606     }
1607     else
1608     {
1609         return SelectViableFunction(viableFunctionsgroupNameargumentscontainerScopeboundCompileUnitcurrentFunctionspanmoduleIdflagstemplateArgumentTypesexception);
1610     }
1611 }
1612 
1613 } } // namespace cmajor::binder