1 // =================================
   2 // Copyright (c) 2021 Seppo Laakko
   3 // Distributed under the MIT license
   4 // =================================
   5 
   6 #include <cmajor/binder/Concept.hpp>
   7 #include <cmajor/binder/BoundCompileUnit.hpp>
   8 #include <cmajor/binder/TypeResolver.hpp>
   9 #include <cmajor/binder/BoundConstraint.hpp>
  10 #include <cmajor/binder/BoundFunction.hpp>
  11 #include <cmajor/binder/OverloadResolution.hpp>
  12 #include <cmajor/binder/Evaluator.hpp>
  13 #include <cmajor/symbols/TypedefSymbol.hpp>
  14 #include <cmajor/symbols/ConceptSymbol.hpp>
  15 #include <sngcm/ast/Visitor.hpp>
  16 #include <sngcm/ast/Identifier.hpp>
  17 #include <sngcm/ast/Expression.hpp>
  18 #include <soulng/util/Unicode.hpp>
  19 
  20 namespace cmajor { namespace binder {
  21 
  22 using namespace soulng::unicode;
  23 
  24 class ConceptIdResolver public Visitor
  25 {
  26 public:
  27     ConceptIdResolver(BoundCompileUnit& boundCompileUnit_ContainerScope* containerScope_);
  28     ConceptSymbol* GetConcept() const { return conceptSymbol; }
  29     void Visit(ConceptIdNode& conceptIdNode) override;
  30     void Visit(IdentifierNode& identifierNode) override;
  31     void Visit(DotNode& dotNode) override;
  32 private:
  33     BoundCompileUnit& boundCompileUnit;
  34     ContainerScope* containerScope;
  35     ConceptGroupSymbol* conceptGroup;
  36     ConceptSymbol* conceptSymbol;
  37     NamespaceSymbol* ns;
  38 };
  39 
  40 ConceptIdResolver::ConceptIdResolver(BoundCompileUnit& boundCompileUnit_ContainerScope* containerScope_) :
  41     boundCompileUnit(boundCompileUnit_)containerScope(containerScope_)conceptGroup(nullptr)conceptSymbol(nullptr)ns(nullptr)
  42 {
  43 }
  44 
  45 void ConceptIdResolver::Visit(ConceptIdNode& conceptIdNode)
  46 {
  47     conceptIdNode.Id()->Accept(*this);
  48     if (conceptGroup)
  49     {
  50         int arity = conceptIdNode.Arity();
  51         conceptSymbol = conceptGroup->GetConcept(arity);
  52         MapIdentifierToSymbolDefinition(conceptIdNode.Id()conceptSymbol);
  53     }
  54     else
  55     {
  56         throw Exception("concept symbol '" + conceptIdNode.Id()->ToString() + "' not found"conceptIdNode.GetSpan()conceptIdNode.ModuleId());
  57     }
  58 }
  59 
  60 void ConceptIdResolver::Visit(IdentifierNode& identifierNode)
  61 {
  62     const std::u32string& name = identifierNode.Str();
  63     Symbol* symbol = containerScope->Lookup(nameScopeLookup::this_and_base_and_parent);
  64     if (!symbol)
  65     {
  66         for (const std::std::unique_ptr<FileScope>&fileScope : boundCompileUnit.FileScopes())
  67         {
  68             symbol = fileScope->Lookup(name);
  69             if (symbol)
  70             {
  71                 break;
  72             }
  73         }
  74     }
  75     if (symbol)
  76     {
  77         if (symbol->GetSymbolType() == SymbolType::conceptGroupSymbol)
  78         {
  79             conceptGroup = static_cast<ConceptGroupSymbol*>(symbol);
  80         }
  81         else if (symbol->GetSymbolType() == SymbolType::namespaceSymbol)
  82         {
  83             ns = static_cast<NamespaceSymbol*>(symbol);
  84         }
  85         else
  86         {
  87             throw Exception("symbol '" + ToUtf8(name) + "' does not denote a concept"identifierNode.GetSpan()identifierNode.ModuleId());
  88         }
  89     }
  90     else
  91     {
  92         throw Exception("concept symbol '" + ToUtf8(name) + "' not found"identifierNode.GetSpan()identifierNode.ModuleId());
  93     }
  94 }
  95 
  96 void ConceptIdResolver::Visit(DotNode& dotNode)
  97 {
  98     dotNode.Subject()->Accept(*this);
  99     if (!ns)
 100     {
 101         throw Exception("concept symbol '" + dotNode.ToString() + "' not found"dotNode.GetSpan()dotNode.ModuleId());
 102     }
 103     ContainerScope* containerScope = ns->GetContainerScope();
 104     const std::u32string& name = dotNode.MemberId()->Str();
 105     Symbol* symbol = containerScope->Lookup(nameScopeLookup::this_);
 106     if (symbol)
 107     {
 108         if (symbol->GetSymbolType() == SymbolType::conceptGroupSymbol)
 109         {
 110             conceptGroup = static_cast<ConceptGroupSymbol*>(symbol);
 111         }
 112         else if (symbol->GetSymbolType() == SymbolType::namespaceSymbol)
 113         {
 114             ns = static_cast<NamespaceSymbol*>(symbol);
 115         }
 116         else
 117         {
 118             throw Exception("symbol '" + ToUtf8(name) + "' does not denote a concept"dotNode.GetSpan()dotNode.ModuleId());
 119         }
 120     }
 121     else
 122     {
 123         throw Exception("concept symbol '" + ToUtf8(name) + "' not found"dotNode.GetSpan()dotNode.ModuleId());
 124     }
 125 }
 126 
 127 ConceptSymbol* ResolveConceptId(ConceptIdNode* conceptIdNodeBoundCompileUnit& boundCompileUnitContainerScope* containerScope)
 128 {
 129     ConceptIdResolver conceptIdResolver(boundCompileUnitcontainerScope);
 130     conceptIdNode->Accept(conceptIdResolver);
 131     ConceptSymbol* conceptSymbol = conceptIdResolver.GetConcept();
 132     if (conceptSymbol)
 133     {
 134         return conceptSymbol;
 135     }
 136     else
 137     {
 138         throw Exception("concept symbol '" + conceptIdNode->Id()->ToString() + "' not found"conceptIdNode->GetSpan()conceptIdNode->ModuleId());
 139     }
 140 }
 141 
 142 std::unique_ptr<BoundConcept> Instantiate(ConceptSymbol* conceptSymbolconst std::std::vector<TypeSymbol*>&typeArgumentsBoundCompileUnit&boundCompileUnitContainerScope*containerScope
 143     BoundFunction* currentFunctionstd::std::unique_ptr<BoundConstraint>&boundConstraintconstSpan&spanconstboost::uuids::uuid&modukeIdstd::std::unique_ptr<Exception>&exception);
 144 
 145 class ConstraintChecker public Visitor
 146 {
 147 public:
 148     ConstraintChecker(TypeSymbol* firstTypeArgument_TypeSymbol* secondTypeArgument_BoundCompileUnit& boundCompileUnit_ContainerScope* containerScope_BoundFunction* currentFunction_
 149         const Span& span_const boost::uuids::uuid& moduleIdstd::std::unique_ptr<Exception>&exception_);
 150     ~ConstraintChecker();
 151     bool Result() const { return result; }
 152     std::std::unique_ptr<BoundConstraint>GetBoundConstraint(){returnstd::move(boundConstraint);}
 153     void Visit(BoolNode& boolNode) override;
 154     void Visit(SByteNode& sbyteNode) override;
 155     void Visit(ByteNode& byteNode) override;
 156     void Visit(ShortNode& shortNode) override;
 157     void Visit(UShortNode& ushortNode) override;
 158     void Visit(IntNode& intNode) override;
 159     void Visit(UIntNode& uintNode) override;
 160     void Visit(LongNode& longNode) override;
 161     void Visit(ULongNode& ulongNode) override;
 162     void Visit(FloatNode& floatNode) override;
 163     void Visit(DoubleNode& doubleNode) override;
 164     void Visit(CharNode& charNode) override;
 165     void Visit(WCharNode& wcharNode) override;
 166     void Visit(UCharNode& ucharNode) override;
 167     void Visit(VoidNode& voidNode) override;
 168     void Visit(ConstNode& constNode) override;
 169     void Visit(LValueRefNode& lvalueRefNode) override;
 170     void Visit(RValueRefNode& rvalueRefNode) override;
 171     void Visit(PointerNode& pointerNode) override;
 172     void Visit(ArrayNode& arrayNode) override;
 173     void Visit(IdentifierNode& identifierNode) override;
 174     void Visit(TemplateIdNode& templateIdNode) override;
 175     void Visit(DotNode& dotNode) override;
 176 
 177     void Visit(ParenthesizedConstraintNode& parenthesizedConstraintNode) override;
 178     void Visit(DisjunctiveConstraintNode& disjunctiveConstraintNode) override;
 179     void Visit(ConjunctiveConstraintNode& conjunctiveConstraintNode) override;
 180     void Visit(WhereConstraintNode& whereConstraintNode) override;
 181     void Visit(PredicateConstraintNode& predicateConstraintNode) override;
 182     void Visit(IsConstraintNode& isConstraintNode) override;
 183     void Visit(MultiParamConstraintNode& multiParamConstraintNode) override;
 184     void Visit(TypeNameConstraintNode& typeNameConstraintNode) override;
 185     void Visit(ConstructorConstraintNode& constructorConstraintNode) override;
 186     void Visit(DestructorConstraintNode& destructorConstraintNode) override;
 187     void Visit(MemberFunctionConstraintNode& memberFunctionConstraintNode) override;
 188     void Visit(FunctionConstraintNode& functionConstraintNode) override;
 189     void Visit(ConceptIdNode& conceptIdNode) override;
 190     void Visit(ConceptNode& conceptNode) override;
 191 
 192     void Visit(SameConstraintNode& sameConstraintNode) override;
 193     void Visit(DerivedConstraintNode& derivedConstraintNode) override;
 194     void Visit(ConvertibleConstraintNode& convertibleConstraintNode) override;
 195     void Visit(ExplicitlyConvertibleConstraintNode& explicitlyConvertibleConstraintNode) override;
 196     void Visit(CommonConstraintNode& commonConstraintNode) override;
 197     void Visit(NonreferenceTypeConstraintNode& nonreferenceTypeConstraintNode) override;
 198 private:
 199     TypeSymbol* firstTypeArgument;
 200     TypeSymbol* secondTypeArgument;
 201     BoundCompileUnit& boundCompileUnit;
 202     SymbolTable& symbolTable;
 203     ContainerScope* containerScope;
 204     BoundFunction* currentFunction;
 205     Span span;
 206     boost::uuids::uuid moduleId;
 207     TypeSymbol* type;
 208     TypeDerivationRec derivationRec;
 209     ConceptGroupSymbol* conceptGroup;
 210     bool result;
 211     std::unique_ptr<BoundConstraint> boundConstraint;
 212     int fileScopesAdded;
 213     std::vector<std::std::unique_ptr<NamespaceTypeSymbol>>namespaceTypeSymbols;
 214     std::vector<std::std::unique_ptr<BoundTemplateParameterSymbol>>boundTemplateParameters;
 215     std::std::unique_ptr<Exception>&exception;
 216     void Reset();
 217     TypeSymbol* GetType();
 218 };
 219 
 220 ConstraintChecker::ConstraintChecker(TypeSymbol* firstTypeArgument_TypeSymbol* secondTypeArgument_BoundCompileUnit& boundCompileUnit_ContainerScope* containerScope_
 221     BoundFunction* currentFunction_const Span& span_const boost::uuids::uuid& moduleId_std::std::unique_ptr<Exception>&exception_):
 222     firstTypeArgument(firstTypeArgument_)secondTypeArgument(secondTypeArgument_)boundCompileUnit(boundCompileUnit_)symbolTable(boundCompileUnit.GetSymbolTable())
 223     containerScope(containerScope_)currentFunction(currentFunction_)span(span_)moduleId(moduleId_)type(nullptr)derivationRec()conceptGroup(nullptr)result(false)boundConstraint()fileScopesAdded(0)
 224     exception(exception_)
 225 {
 226 }
 227 
 228 ConstraintChecker::~ConstraintChecker()
 229 {
 230     for (int i = 0; i < fileScopesAdded; ++i)
 231     {
 232         boundCompileUnit.RemoveLastFileScope();
 233     }
 234 }
 235 
 236 void ConstraintChecker::Reset()
 237 {
 238     type = nullptr;
 239     derivationRec = TypeDerivationRec();
 240     conceptGroup = nullptr;
 241 }
 242 
 243 TypeSymbol* ConstraintChecker::GetType()
 244 {
 245     if (type && type->GetSymbolType() == SymbolType::classGroupTypeSymbol)
 246     {
 247         ClassGroupTypeSymbol* classGroup = static_cast<ClassGroupTypeSymbol*>(type);
 248         type = classGroup->GetClass(0);
 249     }
 250     if (type && !derivationRec.IsEmpty())
 251     {
 252         TypeDerivationRec unifiedDerivationRec = UnifyDerivations(derivationRectype->DerivationRec());
 253         if (!unifiedDerivationRec.derivations.empty())
 254         {
 255             type = boundCompileUnit.GetSymbolTable().MakeDerivedType(type->BaseType()unifiedDerivationRecspanmoduleId);
 256         }
 257     }
 258     return type;
 259 }
 260 
 261 void ConstraintChecker::Visit(BoolNode& boolNode)
 262 {
 263     type = symbolTable.GetTypeByName(U"bool");
 264 }
 265 
 266 void ConstraintChecker::Visit(SByteNode& sbyteNode)
 267 {
 268     type = symbolTable.GetTypeByName(U"sbyte");
 269 }
 270 
 271 void ConstraintChecker::Visit(ByteNode& byteNode)
 272 {
 273     type = symbolTable.GetTypeByName(U"byte");
 274 }
 275 
 276 void ConstraintChecker::Visit(ShortNode& shortNode)
 277 {
 278     type = symbolTable.GetTypeByName(U"short");
 279 }
 280 
 281 void ConstraintChecker::Visit(UShortNode& ushortNode)
 282 {
 283     type = symbolTable.GetTypeByName(U"ushort");
 284 }
 285 
 286 void ConstraintChecker::Visit(IntNode& intNode)
 287 {
 288     type = symbolTable.GetTypeByName(U"int");
 289 }
 290 
 291 void ConstraintChecker::Visit(UIntNode& uintNode)
 292 {
 293     type = symbolTable.GetTypeByName(U"uint");
 294 }
 295 
 296 void ConstraintChecker::Visit(LongNode& longNode)
 297 {
 298     type = symbolTable.GetTypeByName(U"long");
 299 }
 300 
 301 void ConstraintChecker::Visit(ULongNode& ulongNode)
 302 {
 303     type = symbolTable.GetTypeByName(U"ulong");
 304 }
 305 
 306 void ConstraintChecker::Visit(FloatNode& floatNode)
 307 {
 308     type = symbolTable.GetTypeByName(U"float");
 309 }
 310 
 311 void ConstraintChecker::Visit(DoubleNode& doubleNode)
 312 {
 313     type = symbolTable.GetTypeByName(U"double");
 314 }
 315 
 316 void ConstraintChecker::Visit(CharNode& charNode)
 317 {
 318     type = symbolTable.GetTypeByName(U"char");
 319 }
 320 
 321 void ConstraintChecker::Visit(WCharNode& wcharNode)
 322 {
 323     type = symbolTable.GetTypeByName(U"wchar");
 324 }
 325 
 326 void ConstraintChecker::Visit(UCharNode& ucharNode)
 327 {
 328     type = symbolTable.GetTypeByName(U"uchar");
 329 }
 330 
 331 void ConstraintChecker::Visit(VoidNode& voidNode)
 332 {
 333     type = symbolTable.GetTypeByName(U"void");
 334 }
 335 
 336 void ConstraintChecker::Visit(ConstNode& constNode)
 337 {
 338     derivationRec.derivations.push_back(Derivation::constDerivation);
 339     constNode.Subject()->Accept(*this);
 340 }
 341 
 342 void ConstraintChecker::Visit(LValueRefNode& lvalueRefNode)
 343 {
 344     lvalueRefNode.Subject()->Accept(*this);
 345     if (HasReferenceDerivation(derivationRec.derivations))
 346     {
 347         throw Exception("cannot have reference to reference type"lvalueRefNode.GetSpan()lvalueRefNode.ModuleId());
 348     }
 349     derivationRec.derivations.push_back(Derivation::lvalueRefDerivation);
 350 }
 351 
 352 void ConstraintChecker::Visit(RValueRefNode& rvalueRefNode)
 353 {
 354     rvalueRefNode.Subject()->Accept(*this);
 355     if (HasReferenceDerivation(derivationRec.derivations))
 356     {
 357         throw Exception("cannot have reference to reference type"rvalueRefNode.GetSpan()rvalueRefNode.ModuleId());
 358     }
 359     derivationRec.derivations.push_back(Derivation::rvalueRefDerivation);
 360 }
 361 
 362 void ConstraintChecker::Visit(PointerNode& pointerNode)
 363 {
 364     pointerNode.Subject()->Accept(*this);
 365     if (HasReferenceDerivation(derivationRec.derivations))
 366     {
 367         throw Exception("cannot have pointer to reference type"pointerNode.GetSpan()pointerNode.ModuleId());
 368     }
 369     derivationRec.derivations.push_back(Derivation::pointerDerivation);
 370 }
 371 
 372 void ConstraintChecker::Visit(ArrayNode& arrayNode)
 373 {
 374     arrayNode.Subject()->Accept(*this);
 375     if (HasReferenceDerivation(derivationRec.derivations))
 376     {
 377         throw Exception("cannot have array of reference type"arrayNode.GetSpan()arrayNode.ModuleId());
 378     }
 379     // todo: evaluate size
 380 }
 381 
 382 void ConstraintChecker::Visit(IdentifierNode& identifierNode)
 383 {
 384     Reset();
 385     const std::u32string& name = identifierNode.Str();
 386     Symbol* symbol = containerScope->Lookup(nameScopeLookup::this_and_base_and_parent);
 387     if (!symbol)
 388     {
 389         for (const std::std::unique_ptr<FileScope>&fileScope : boundCompileUnit.FileScopes())
 390         {
 391             symbol = fileScope->Lookup(name);
 392             if (symbol)
 393             {
 394                 break;
 395             }
 396         }
 397     }
 398     if (symbol)
 399     {
 400         if (symbol->IsTypeSymbol())
 401         {
 402             type = static_cast<TypeSymbol*>(symbol);
 403         }
 404         else
 405         {
 406             switch (symbol->GetSymbolType())
 407             {
 408                 case SymbolType::typedefSymbol:
 409                 {
 410                     TypedefSymbol* typedefSymbol = static_cast<TypedefSymbol*>(symbol);
 411                     type = typedefSymbol->GetType();
 412                     break;
 413                 }
 414                 case SymbolType::boundTemplateParameterSymbol:
 415                 {
 416                     BoundTemplateParameterSymbol* boundTemplateParameterSymbol = static_cast<BoundTemplateParameterSymbol*>(symbol);
 417                     type = boundTemplateParameterSymbol->GetType();
 418                     break;
 419                 }
 420                 case SymbolType::conceptGroupSymbol:
 421                 {
 422                     conceptGroup = static_cast<ConceptGroupSymbol*>(symbol);
 423                     break;
 424                 }
 425                 case SymbolType::namespaceSymbol:
 426                 {
 427                     NamespaceSymbol* ns = static_cast<NamespaceSymbol*>(symbol);
 428                     NamespaceTypeSymbol* namespaceTypeSymbol = new NamespaceTypeSymbol(ns);
 429                     boundCompileUnit.GetSymbolTable().SetTypeIdFor(namespaceTypeSymbol);
 430                     namespaceTypeSymbols.push_back(std::unique_ptr<NamespaceTypeSymbol>(namespaceTypeSymbol));
 431                     type = namespaceTypeSymbol;
 432                     FileScope* fileScope = new FileScope();
 433                     NamespaceImportNode importNode(spanmoduleIdnew IdentifierNode(spanmoduleIdns->FullName()));
 434                     fileScope->InstallNamespaceImport(containerScope&importNode);
 435                     boundCompileUnit.AddFileScope(fileScope);
 436                     ++fileScopesAdded;
 437                     break;
 438                 }
 439                 default:
 440                 {
 441                     throw Exception("symbol '" + ToUtf8(symbol->FullName()) + "' does not denote a type or a concept"symbol->GetSpan()symbol->SourceModuleId());
 442                 }
 443             }
 444         }
 445     }
 446     else
 447     {
 448         throw Exception("type or concept symbol '" + ToUtf8(name) + "' not found"identifierNode.GetSpan()identifierNode.ModuleId());
 449     }
 450 }
 451 
 452 void ConstraintChecker::Visit(TemplateIdNode& templateIdNode)
 453 {
 454     type = ResolveType(&templateIdNodeboundCompileUnitcontainerScope);
 455 }
 456 
 457 void ConstraintChecker::Visit(DotNode& dotNode)
 458 {
 459     Reset();
 460     dotNode.Subject()->Accept(*this);
 461     TypeSymbol* subjectType = GetType();
 462     if (!subjectType)
 463     {
 464         throw Exception("symbol '" + dotNode.Subject()->ToString() + "' does not denote a type"dotNode.Subject()->GetSpan()dotNode.Subject()->ModuleId());
 465     }
 466     Scope* typeContainerScope = nullptr;
 467     if (subjectType->IsPointerType())
 468     {
 469         typeContainerScope = subjectType->GetContainerScope();
 470     }
 471     else
 472     {
 473         typeContainerScope = subjectType->BaseType()->GetContainerScope();
 474     }
 475     if (subjectType->GetSymbolType() == SymbolType::namespaceTypeSymbol)
 476     {
 477         NamespaceTypeSymbol* nsTypeSymbol = static_cast<NamespaceTypeSymbol*>(subjectType);
 478         typeContainerScope = nsTypeSymbol->Ns()->GetContainerScope();
 479     }
 480     Reset();
 481     const std::u32string& name = dotNode.MemberId()->Str();
 482     Symbol* symbol = typeContainerScope->Lookup(nameScopeLookup::this_and_base);
 483     if (symbol)
 484     {
 485         switch (symbol->GetSymbolType())
 486         {
 487             case SymbolType::typedefSymbol:
 488             {
 489                 TypedefSymbol* typedefSymbol = static_cast<TypedefSymbol*>(symbol);
 490                 type = typedefSymbol->GetType();
 491                 break;
 492             }
 493             case SymbolType::boundTemplateParameterSymbol:
 494             {
 495                 BoundTemplateParameterSymbol* boundTemplateParameterSymbol = static_cast<BoundTemplateParameterSymbol*>(symbol);
 496                 type = boundTemplateParameterSymbol->GetType();
 497                 break;
 498             }
 499             case SymbolType::conceptGroupSymbol:
 500             {
 501                 conceptGroup = static_cast<ConceptGroupSymbol*>(symbol);
 502                 break;
 503             }
 504             case SymbolType::namespaceSymbol:
 505             {
 506                 NamespaceSymbol* ns = static_cast<NamespaceSymbol*>(symbol);
 507                 NamespaceTypeSymbol* namespaceTypeSymbol = new NamespaceTypeSymbol(ns);
 508                 boundCompileUnit.GetSymbolTable().SetTypeIdFor(namespaceTypeSymbol);
 509                 namespaceTypeSymbols.push_back(std::unique_ptr<NamespaceTypeSymbol>(namespaceTypeSymbol));
 510                 type = namespaceTypeSymbol;
 511                 FileScope* fileScope = new FileScope();
 512                 NamespaceImportNode importNode(spanmoduleIdnew IdentifierNode(spanmoduleIdns->FullName()));
 513                 fileScope->InstallNamespaceImport(containerScope&importNode);
 514                 boundCompileUnit.AddFileScope(fileScope);
 515                 ++fileScopesAdded;
 516                 break;
 517             }
 518             default:
 519             {
 520                 throw Exception("symbol '" + ToUtf8(symbol->FullName()) + "' does not denote a type or a concept"symbol->GetSpan()symbol->SourceModuleId());
 521             }
 522         }
 523     }
 524     else
 525     {
 526         throw Exception("type or concept symbol '" + ToUtf8(name) + "' not found"dotNode.GetSpan()dotNode.ModuleId());
 527     }
 528 }
 529 
 530 void ConstraintChecker::Visit(ParenthesizedConstraintNode& parenthesizedConstraintNode)
 531 {
 532     Reset();
 533     parenthesizedConstraintNode.Constraint()->Accept(*this);
 534 }
 535 
 536 void ConstraintChecker::Visit(DisjunctiveConstraintNode& disjunctiveConstraintNode)
 537 {
 538     bool exceptionWasSet = exception != nullptr;
 539     bool left = false;
 540     bool right = false;
 541     std::unique_ptr<BoundConstraint> leftBoundConstraint;
 542     std::unique_ptr<BoundConstraint> rightBoundConstraint;
 543     Reset();
 544     try
 545     {
 546         disjunctiveConstraintNode.Left()->Accept(*this);
 547         left = result;
 548         leftBoundConstraint = std::move(boundConstraint);
 549     }
 550     catch (const Exception& ex;)
 551     {
 552         left = false;
 553         leftBoundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
 554         if (!exception)
 555         {
 556             exception.reset(new Exception(ex));
 557         }
 558     }
 559     catch (...)
 560     {
 561         left = false;
 562         leftBoundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
 563     }
 564     Reset();
 565     try
 566     {
 567         disjunctiveConstraintNode.Right()->Accept(*this);
 568         right = result;
 569         rightBoundConstraint = std::move(boundConstraint);
 570     }
 571     catch (const Exception& ex;)
 572     {
 573         right = false;
 574         rightBoundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
 575         if (!exception)
 576         {
 577             exception.reset(new Exception(ex));
 578         }
 579     }
 580     catch (...)
 581     {
 582         right = false;
 583         rightBoundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
 584     }
 585     result = left || right;
 586     boundConstraint.reset(new BoundDisjunctiveConstraint(spanmoduleIdleftBoundConstraint.release()rightBoundConstraint.release()));
 587     if (result && !exceptionWasSet)
 588     {
 589         exception.reset();
 590     }
 591 }
 592 
 593 void ConstraintChecker::Visit(ConjunctiveConstraintNode& conjunctiveConstraintNode)
 594 {
 595     bool left = false;
 596     bool right = false;
 597     std::unique_ptr<BoundConstraint> leftBoundConstraint;
 598     std::unique_ptr<BoundConstraint> rightBoundConstraint;
 599     Reset();
 600     try
 601     {
 602         conjunctiveConstraintNode.Left()->Accept(*this);
 603         left = result;
 604         leftBoundConstraint = std::move(boundConstraint);
 605     }
 606     catch (const Exception& ex;)
 607     {
 608         left = false;
 609         leftBoundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
 610         if (!exception)
 611         {
 612             exception.reset(new Exception(ex));
 613         }
 614     }
 615     catch (...)
 616     {
 617         left = false;
 618         leftBoundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
 619     }
 620     Reset();
 621     try
 622     {
 623         conjunctiveConstraintNode.Right()->Accept(*this);
 624         right = result;
 625         rightBoundConstraint = std::move(boundConstraint);
 626     }
 627     catch (const Exception& ex;)
 628     {
 629         right = false;
 630         rightBoundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
 631         if (!exception)
 632         {
 633             exception.reset(new Exception(ex));
 634         }
 635     }
 636     catch (...)
 637     {
 638         right = false;
 639         rightBoundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
 640     }
 641     result = left && right;
 642     boundConstraint.reset(new BoundConjunctiveConstraint(spanmoduleIdleftBoundConstraint.release()rightBoundConstraint.release()));
 643 }
 644 
 645 void ConstraintChecker::Visit(WhereConstraintNode& whereConstraintNode)
 646 {
 647     Reset();
 648     whereConstraintNode.Constraint()->Accept(*this);
 649 }
 650 
 651 void ConstraintChecker::Visit(PredicateConstraintNode& predicateConstraintNode)
 652 {
 653     Reset();
 654     Node* invokeExprNode = predicateConstraintNode.InvokeExpr();
 655     std::unique_ptr<Value> evaluationResult = Evaluate(invokeExprNodesymbolTable.GetTypeByName(U"bool")containerScopeboundCompileUnitfalsecurrentFunction
 656         predicateConstraintNode.GetSpan()predicateConstraintNode.ModuleId());
 657     BoolValue* boolResult = static_cast<BoolValue*>(evaluationResult.get());
 658     result = boolResult->GetValue();
 659     boundConstraint.reset(new BoundAtomicConstraint(predicateConstraintNode.GetSpan()predicateConstraintNode.ModuleId()result));
 660 }
 661 
 662 void ConstraintChecker::Visit(IsConstraintNode& isConstraintNode)
 663 {
 664     Reset();
 665     isConstraintNode.TypeExpr()->Accept(*this);
 666     TypeSymbol* leftType = GetType();
 667     if (!leftType)
 668     {
 669         throw Exception("left operand of 'is' must be a type"isConstraintNode.TypeExpr()->GetSpan()isConstraintNode.TypeExpr()->ModuleId());
 670     }
 671     Reset();
 672     isConstraintNode.ConceptOrTypeName()->Accept(*this);
 673     TypeSymbol* rightType = GetType();
 674     if (rightType)
 675     {
 676         TypeSymbol* leftPlainType = leftType->PlainType(spanmoduleId);
 677         TypeSymbol* rightPlainType = rightType->PlainType(spanmoduleId);
 678         if (TypesEqual(leftPlainTyperightPlainType))
 679         {
 680             result = true;
 681             boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
 682         }
 683         else
 684         {
 685             result = false;
 686             boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
 687         }
 688     }
 689     else if (conceptGroup)
 690     {
 691         ConceptSymbol* conceptSymbol = conceptGroup->GetConcept(1);
 692         std::vector<TypeSymbol*> typeArguments;
 693         typeArguments.push_back(leftType);
 694         BoundConceptKey key(conceptSymboltypeArguments);
 695         BoundConcept* boundConcept = boundCompileUnit.GetConceptRepository().GetBoundConcept(key);
 696         if (boundConcept)
 697         {
 698             result = true;
 699             boundConstraint.reset(boundConcept->GetBoundConstraint()->Clone());
 700             if (boundConcept->CommonType())
 701             {
 702                 BoundTemplateParameterSymbol* boundCommonTypeSymbol = new BoundTemplateParameterSymbol(spanmoduleIdU"CommonType");
 703                 boundCommonTypeSymbol->SetType(boundConcept->CommonType());
 704                 containerScope->Install(boundCommonTypeSymbol);
 705                 boundConcept->AddBoundTemplateParameter(std::unique_ptr<BoundTemplateParameterSymbol>(boundCommonTypeSymbol));
 706             }
 707         }
 708         else
 709         {
 710             std::unique_ptr<BoundConstraint> constraint;
 711             std::unique_ptr<BoundConcept> boundConcept = Instantiate(conceptSymboltypeArgumentsboundCompileUnitcontainerScopecurrentFunctionconstraintspanmoduleIdexception);
 712             if (boundConcept)
 713             {
 714                 result = true;
 715                 boundConstraint.reset(constraint.release());
 716                 boundCompileUnit.GetConceptRepository().AddBoundConcept(keystd::move(boundConcept));
 717             }
 718             else
 719             {
 720                 result = false;
 721                 boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
 722             }
 723         }
 724     }
 725 }
 726 
 727 void ConstraintChecker::Visit(MultiParamConstraintNode& multiParamConstraintNode)
 728 {
 729     Reset();
 730     multiParamConstraintNode.ConceptId()->Accept(*this);
 731     if (conceptGroup)
 732     {
 733         int n = multiParamConstraintNode.TypeExprs().Count();
 734         ConceptSymbol* conceptSymbol = conceptGroup->GetConcept(n);
 735         std::vector<TypeSymbol*> typeArguments;
 736         for (int i = 0; i < n; ++i)
 737         {
 738             Node* typeExprNode = multiParamConstraintNode.TypeExprs()[i];
 739             Reset();
 740             typeExprNode->Accept(*this);
 741             TypeSymbol* resolvedType = GetType();
 742             if (resolvedType)
 743             {
 744                 typeArguments.push_back(resolvedType);
 745             }
 746             else
 747             {
 748                 throw Exception("type parameter '" + typeExprNode->ToString() + "' is not bound to a type"typeExprNode->GetSpan()typeExprNode->ModuleId());
 749             }
 750         }
 751         BoundConceptKey key(conceptSymboltypeArguments);
 752         BoundConcept* boundConcept = boundCompileUnit.GetConceptRepository().GetBoundConcept(key);
 753         if (boundConcept)
 754         {
 755             result = true;
 756             boundConstraint.reset(boundConcept->GetBoundConstraint()->Clone());
 757             if (boundConcept->CommonType())
 758             {
 759                 BoundTemplateParameterSymbol* boundCommonTypeSymbol = new BoundTemplateParameterSymbol(spanmoduleIdU"CommonType");
 760                 boundCommonTypeSymbol->SetType(boundConcept->CommonType());
 761                 containerScope->Install(boundCommonTypeSymbol);
 762                 boundConcept->AddBoundTemplateParameter(std::unique_ptr<BoundTemplateParameterSymbol>(boundCommonTypeSymbol));
 763             }
 764         }
 765         else
 766         {
 767             std::unique_ptr<BoundConstraint> constraint;
 768             std::unique_ptr<BoundConcept> boundConcept = Instantiate(conceptSymboltypeArgumentsboundCompileUnitcontainerScopecurrentFunctionconstraintspanmoduleIdexception);
 769             if (boundConcept)
 770             {
 771                 result = true;
 772                 boundConstraint.reset(constraint.release());
 773                 boundCompileUnit.GetConceptRepository().AddBoundConcept(keystd::move(boundConcept));
 774             }
 775             else
 776             {
 777                 result = false;
 778                 boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
 779             }
 780         }
 781     }
 782     else
 783     {
 784         throw Exception("symbol '" + multiParamConstraintNode.ConceptId()->ToString() + "' does not denote a concept"multiParamConstraintNode.ConceptId()->GetSpan()multiParamConstraintNode.ConceptId()->ModuleId());
 785     }
 786 }
 787 
 788 void ConstraintChecker::Visit(TypeNameConstraintNode& typeNameConstraintNode)
 789 {
 790     Reset();
 791     typeNameConstraintNode.TypeId()->Accept(*this);
 792     TypeSymbol* resolvedType = GetType();
 793     result = resolvedType != nullptr;
 794     boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdresult));
 795 }
 796 
 797 void ConstraintChecker::Visit(ConstructorConstraintNode& constructorConstraintNode)
 798 {
 799     std::vector<std::std::unique_ptr<BoundExpression>>arguments;
 800     arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(spanmoduleIdfirstTypeArgument->AddPointer(spanmoduleId))));
 801     std::vector<TypeSymbol*> parameterTypes;
 802     int n = constructorConstraintNode.Parameters().Count();
 803     for (int i = 0; i < n; ++i)
 804     {
 805         ParameterNode* parameterNode = constructorConstraintNode.Parameters()[i];
 806         TypeSymbol* parameterType = ResolveType(parameterNode->TypeExpr()boundCompileUnitcontainerScope);
 807         parameterTypes.push_back(parameterType);
 808         arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(spanmoduleIdparameterType)));
 809     }
 810     std::vector<FunctionScopeLookup> lookups;
 811     lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parentcontainerScope));
 812     lookups.push_back(FunctionScopeLookup(ScopeLookup::this_firstTypeArgument->BaseType()->ClassInterfaceEnumDelegateOrNsScope()));
 813     std::vector<TypeSymbol*> templateArgumentTypes;
 814     std::unique_ptr<Exception> exception;
 815     std::unique_ptr<BoundFunctionCall> constructorCall = ResolveOverload(U"@constructor"containerScopelookupsargumentsboundCompileUnitcurrentFunctionspanmoduleId
 816         OverloadResolutionFlags::dontInstantiate | OverloadResolutionFlags::dontThrowtemplateArgumentTypesexception);
 817     if (!constructorCall)
 818     {
 819         std::string signature;
 820         signature.append(ToUtf8(firstTypeArgument->FullName()) + "." + ToUtf8(firstTypeArgument->Name()).append(1'('));
 821         bool first = true;
 822         for (TypeSymbol* parameterType : parameterTypes)
 823         {
 824             if (first)
 825             {
 826                 first = false;
 827             }
 828             else
 829             {
 830                 signature.append(", ");
 831             }
 832             signature.append(ToUtf8(parameterType->FullName()));
 833         }
 834         signature.append(1')');
 835         std::string message = "constructor signature '" + signature + "' not found";
 836         std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
 837         if (exception)
 838         {
 839             message.append(": ").append(exception->Message());
 840             references.push_back(std::make_pair(exception->Defined()exception->DefinedModuleId()));
 841             references.insert(references.end()exception->References().begin()exception->References().end());
 842         }
 843         throw Exception(messagespanmoduleIdreferences);
 844     }
 845     else
 846     {
 847         result = true;
 848         boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
 849     }
 850 }
 851 
 852 void ConstraintChecker::Visit(DestructorConstraintNode& destructorConstraintNode)
 853 {
 854     result = true;
 855     boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
 856 }
 857 
 858 void ConstraintChecker::Visit(MemberFunctionConstraintNode& memberFunctionConstraintNode)
 859 {
 860     Reset();
 861     memberFunctionConstraintNode.TypeParamId()->Accept(*this);
 862     TypeSymbol* firstType = GetType();
 863     std::vector<std::std::unique_ptr<BoundExpression>>arguments;
 864     arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(spanmoduleIdfirstType->AddPointer(spanmoduleId))));
 865     std::vector<TypeSymbol*> parameterTypes;
 866     int n = memberFunctionConstraintNode.Parameters().Count();
 867     for (int i = 0; i < n; ++i)
 868     {
 869         ParameterNode* parameterNode = memberFunctionConstraintNode.Parameters()[i];
 870         TypeSymbol* parameterType = ResolveType(parameterNode->TypeExpr()boundCompileUnitcontainerScope);
 871         parameterTypes.push_back(parameterType);
 872         arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(spanmoduleIdparameterType)));
 873     }
 874     std::vector<FunctionScopeLookup> lookups;
 875     lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parentcontainerScope));
 876     lookups.push_back(FunctionScopeLookup(ScopeLookup::this_firstType->BaseType()->ClassInterfaceOrNsScope()));
 877     std::vector<TypeSymbol*> templateArgumentTypes;
 878     std::unique_ptr<Exception> exception;
 879     std::unique_ptr<BoundFunctionCall> memberFunctionCall = ResolveOverload(memberFunctionConstraintNode.GroupId()containerScopelookupsargumentsboundCompileUnitcurrentFunctionspanmoduleId
 880         OverloadResolutionFlags::dontInstantiate | OverloadResolutionFlags::dontThrow | OverloadResolutionFlags::noTemplatestemplateArgumentTypesexception);
 881     if (!memberFunctionCall)
 882     {
 883         std::string signature;
 884         signature.append(ToUtf8(firstType->FullName()) + "." + ToUtf8(memberFunctionConstraintNode.GroupId()).append(1'('));
 885         bool first = true;
 886         for (TypeSymbol* parameterType : parameterTypes)
 887         {
 888             if (first)
 889             {
 890                 first = false;
 891             }
 892             else
 893             {
 894                 signature.append(", ");
 895             }
 896             signature.append(ToUtf8(parameterType->FullName()));
 897         }
 898         signature.append(1')');
 899         std::string message = "member function signature '" + signature + "' not found";
 900         std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
 901         if (exception)
 902         {
 903             message.append(": ").append(exception->Message());
 904             references.push_back(std::make_pair(exception->Defined()exception->DefinedModuleId()));
 905             references.insert(references.end()exception->References().begin()exception->References().end());
 906         }
 907         throw Exception(messagespanmoduleIdreferences);
 908     }
 909     else
 910     {
 911         result = true;
 912         boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
 913     }
 914 }
 915 
 916 void ConstraintChecker::Visit(FunctionConstraintNode& functionConstraintNode)
 917 {
 918     std::vector<std::std::unique_ptr<BoundExpression>>arguments;
 919     arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(spanmoduleIdfirstTypeArgument->AddPointer(spanmoduleId))));
 920     std::vector<TypeSymbol*> parameterTypes;
 921     std::vector<FunctionScopeLookup> lookups;
 922     lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parentcontainerScope));
 923     lookups.push_back(FunctionScopeLookup(ScopeLookup::this_firstTypeArgument->BaseType()->ClassInterfaceEnumDelegateOrNsScope()));
 924     int n = functionConstraintNode.Parameters().Count();
 925     if (firstTypeArgument->IsPointerType() && 
 926         ((n == 0 && 
 927             (functionConstraintNode.GroupId() == U"operator*" || 
 928             functionConstraintNode.GroupId() == U"operator++" || 
 929             functionConstraintNode.GroupId() == U"operator--")) || 
 930         (n == 1 && 
 931             functionConstraintNode.GroupId() == U"operator[]")))
 932     {
 933         result = true;
 934         boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
 935         return;
 936     }
 937     for (int i = 0; i < n; ++i)
 938     {
 939         ParameterNode* parameterNode = functionConstraintNode.Parameters()[i];
 940         TypeSymbol* parameterType = ResolveType(parameterNode->TypeExpr()boundCompileUnitcontainerScope);
 941         lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parentcontainerScope));
 942         parameterTypes.push_back(parameterType);
 943         arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(spanmoduleIdparameterType)));
 944     }
 945     std::vector<TypeSymbol*> templateArgumentTypes;
 946     std::unique_ptr<Exception> exception;
 947     std::unique_ptr<BoundFunctionCall> functionCall = ResolveOverload(functionConstraintNode.GroupId()containerScopelookupsargumentsboundCompileUnitcurrentFunctionspanmoduleId
 948         OverloadResolutionFlags::dontInstantiate | OverloadResolutionFlags::dontThrowtemplateArgumentTypesexception);
 949     if (!functionCall)
 950     {
 951         arguments.clear();
 952         parameterTypes.clear();
 953         arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(spanmoduleIdfirstTypeArgument->AddPointer(spanmoduleId))));
 954         std::vector<TypeSymbol*> parameterTypes;
 955         int n = functionConstraintNode.Parameters().Count();
 956         for (int i = 1; i < n; ++i)
 957         {
 958             ParameterNode* parameterNode = functionConstraintNode.Parameters()[i];
 959             TypeSymbol* parameterType = ResolveType(parameterNode->TypeExpr()boundCompileUnitcontainerScope);
 960             parameterTypes.push_back(parameterType);
 961             arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(spanmoduleIdparameterType)));
 962         }
 963         std::vector<TypeSymbol*> templateArgumentTypes;
 964         std::unique_ptr<Exception> exception;
 965         std::unique_ptr<BoundFunctionCall> functionCall = ResolveOverload(functionConstraintNode.GroupId()containerScopelookupsargumentsboundCompileUnitcurrentFunctionspanmoduleId
 966             OverloadResolutionFlags::dontInstantiate | OverloadResolutionFlags::dontThrowtemplateArgumentTypesexception);
 967         if (!functionCall)
 968         {
 969             arguments.clear();
 970             lookups.clear();
 971             lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parentcontainerScope));
 972             parameterTypes.clear();
 973             int n = functionConstraintNode.Parameters().Count();
 974             for (int i = 0; i < n; ++i)
 975             {
 976                 ParameterNode* parameterNode = functionConstraintNode.Parameters()[i];
 977                 TypeSymbol* parameterType = ResolveType(parameterNode->TypeExpr()boundCompileUnitcontainerScope);
 978                 lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parentparameterType->BaseType()->ClassInterfaceEnumDelegateOrNsScope()));
 979                 parameterTypes.push_back(parameterType);
 980                 arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(spanmoduleIdparameterType)));
 981             }
 982             std::vector<TypeSymbol*> templateArgumentTypes;
 983             std::unique_ptr<Exception> exception;
 984             std::unique_ptr<BoundFunctionCall> functionCall = ResolveOverload(functionConstraintNode.GroupId()containerScopelookupsargumentsboundCompileUnitcurrentFunctionspanmoduleId
 985                 OverloadResolutionFlags::dontInstantiate | OverloadResolutionFlags::dontThrowtemplateArgumentTypesexception);
 986             if (!functionCall)
 987             {
 988                 std::string signature;
 989                 signature.append(ToUtf8(functionConstraintNode.GroupId())).append(1'(');
 990                 bool first = true;
 991                 for (TypeSymbol* parameterType : parameterTypes)
 992                 {
 993                     if (first)
 994                     {
 995                         first = false;
 996                     }
 997                     else
 998                     {
 999                         signature.append(", ");
1000                     }
1001                     signature.append(ToUtf8(parameterType->FullName()));
1002                 }
1003                 signature.append(1')');
1004                 std::string message = "function signature '" + signature + "' not found";
1005                 std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
1006                 if (exception)
1007                 {
1008                     message.append(": ").append(exception->Message());
1009                     references.push_back(std::make_pair(exception->Defined()exception->DefinedModuleId()));
1010                     references.insert(references.end()exception->References().begin()exception->References().end());
1011                 }
1012                 throw Exception(messagespanmoduleIdreferences);
1013             }
1014             else
1015             {
1016                 result = true;
1017                 boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
1018             }
1019         }
1020         else
1021         {
1022             result = true;
1023             boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
1024         }
1025     }
1026     else
1027     {
1028         result = true;
1029         boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
1030     }
1031 }
1032 
1033 void ConstraintChecker::Visit(ConceptIdNode& conceptIdNode)
1034 {
1035     Reset();
1036     conceptIdNode.Id()->Accept(*this);
1037     if (conceptGroup)
1038     {
1039         int n = conceptIdNode.Arity();
1040         ConceptSymbol* conceptSymbol = conceptGroup->GetConcept(n);
1041         std::vector<TypeSymbol*> typeArguments;
1042         for (int i = 0; i < n; ++i)
1043         {
1044             Node* typeParameterNode = conceptIdNode.TypeParameters()[i];
1045             Reset();
1046             typeParameterNode->Accept(*this);
1047             TypeSymbol* resolvedType = GetType();
1048             if (resolvedType)
1049             {
1050                 typeArguments.push_back(resolvedType);
1051             }
1052             else
1053             {
1054                 throw Exception("type parameter " + std::to_string(i) + " does not denote a type"spanmoduleIdconceptIdNode.GetSpan()conceptIdNode.ModuleId());
1055             }
1056         }
1057         BoundConceptKey key(conceptSymboltypeArguments);
1058         BoundConcept* boundConcept = boundCompileUnit.GetConceptRepository().GetBoundConcept(key);
1059         if (boundConcept)
1060         {
1061             result = true;
1062             boundConstraint = std::unique_ptr<BoundConstraint>(boundConcept->GetBoundConstraint()->Clone());
1063             if (boundConcept->CommonType())
1064             {
1065                 BoundTemplateParameterSymbol* boundCommonTypeSymbol = new BoundTemplateParameterSymbol(spanmoduleIdU"CommonType");
1066                 boundCommonTypeSymbol->SetType(boundConcept->CommonType());
1067                 containerScope->Install(boundCommonTypeSymbol);
1068                 boundConcept->AddBoundTemplateParameter(std::unique_ptr<BoundTemplateParameterSymbol>(boundCommonTypeSymbol));
1069             }
1070         }
1071         else
1072         {
1073             std::unique_ptr<BoundConstraint> constraint;
1074             std::unique_ptr<BoundConcept> boundConcept = Instantiate(conceptSymboltypeArgumentsboundCompileUnitcontainerScopecurrentFunctionconstraintspanmoduleIdexception);
1075             if (boundConcept)
1076             {
1077                 result = true;
1078                 boundConstraint.reset(constraint.release());
1079                 boundCompileUnit.GetConceptRepository().AddBoundConcept(keystd::move(boundConcept));
1080             }
1081             else
1082             {
1083                 result = false;
1084                 boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdfalse));
1085             }
1086         }
1087     }
1088     else
1089     {
1090         throw Exception(conceptIdNode.Id()->ToString() + " does not denote a concept"conceptIdNode.Id()->GetSpan()conceptIdNode.Id()->ModuleId());
1091     }
1092 }
1093 
1094 void ConstraintChecker::Visit(ConceptNode& conceptNode)
1095 {
1096     Reset();
1097     conceptNode.Id()->Accept(*this);
1098     if (!conceptGroup)
1099     {
1100         throw Exception("symbol '" + conceptNode.Id()->ToString() + "' does not denote a concept"conceptNode.Id()->GetSpan()conceptNode.Id()->ModuleId());
1101     }
1102     int arity = conceptNode.Arity();
1103     ConceptSymbol* conceptSymbol = conceptGroup->GetConcept(arity);
1104     if (conceptNode.Refinement())
1105     {
1106         Reset();
1107         conceptNode.Refinement()->Accept(*this);
1108         if (!result) return;
1109     }
1110     int n = conceptNode.Constraints().Count();
1111     for (int i = 0; i < n; ++i)
1112     {
1113         ConstraintNode* constraintNode = conceptNode.Constraints()[i];
1114         Reset();
1115         constraintNode->Accept(*this);
1116         if (!result) return;
1117     }
1118     result = true;
1119     BoundAtomicConstraint* atomicConstraint = new BoundAtomicConstraint(spanmoduleIdtrue);
1120     atomicConstraint->SetConcept(conceptSymbol);
1121     boundConstraint.reset(atomicConstraint);
1122 }
1123 
1124 void ConstraintChecker::Visit(SameConstraintNode& sameConstraintNode)
1125 {
1126     if (firstTypeArgument && secondTypeArgument)
1127     {
1128         bool same = TypesEqual(firstTypeArgumentsecondTypeArgument);
1129         if (!same)
1130         {
1131             throw Exception("type '" + ToUtf8(firstTypeArgument->FullName()) + "' is not same type as '" + ToUtf8(secondTypeArgument->FullName()) + "'"spanmoduleId);
1132         }
1133         else
1134         {
1135             result = true;
1136             boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
1137         }
1138     }
1139     else
1140     {
1141         throw Exception("the same type constraint needs two type arguments"spanmoduleId);
1142     }
1143 }
1144 
1145 void ConstraintChecker::Visit(DerivedConstraintNode& derivedConstraintNode)
1146 {
1147     if (firstTypeArgument && secondTypeArgument)
1148     {
1149         bool derived = false;
1150         if (firstTypeArgument->IsClassTypeSymbol() && secondTypeArgument->IsClassTypeSymbol())
1151         {
1152             ClassTypeSymbol* firstClassType = static_cast<ClassTypeSymbol*>(firstTypeArgument);
1153             ClassTypeSymbol* secondClassType = static_cast<ClassTypeSymbol*>(secondTypeArgument);
1154             derived = firstClassType->HasBaseClass(secondClassType);
1155         }
1156         if (!derived)
1157         {
1158             throw Exception("type '" + ToUtf8(firstTypeArgument->FullName()) + "' is not derived from '" + ToUtf8(secondTypeArgument->FullName()) + "'"spanmoduleId);
1159         }
1160         else
1161         {
1162             result = true;
1163             boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
1164         }
1165     }
1166     else
1167     {
1168         throw Exception("the derivded type constraint needs two type arguments"spanmoduleId);
1169     }
1170 }
1171 
1172 void ConstraintChecker::Visit(ConvertibleConstraintNode& convertibleConstraintNode)
1173 {
1174     if (firstTypeArgument && secondTypeArgument)
1175     {
1176         ArgumentMatch argumentMatch;
1177         FunctionSymbol* conversion = boundCompileUnit.GetConversion(firstTypeArgumentsecondTypeArgumentcontainerScopecurrentFunctionspanmoduleIdargumentMatch);
1178         if (!conversion || conversion->GetConversionType() == ConversionType::explicit_)
1179         {
1180             throw Exception("type '" + ToUtf8(firstTypeArgument->FullName()) + "' is not implicitly convertible to '" + ToUtf8(secondTypeArgument->FullName()) + "'"spanmoduleId);
1181         }
1182         else
1183         {
1184             result = true;
1185             boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
1186         }
1187     }
1188     else
1189     {
1190         throw Exception("the convertible constraint needs two type arguments"spanmoduleId);
1191     }
1192 }
1193 
1194 void ConstraintChecker::Visit(ExplicitlyConvertibleConstraintNode& explicitlyConvertibleConstraintNode)
1195 {
1196     if (firstTypeArgument && secondTypeArgument)
1197     {
1198         ArgumentMatch argumentMatch;
1199         FunctionSymbol* conversion = boundCompileUnit.GetConversion(firstTypeArgumentsecondTypeArgumentcontainerScopecurrentFunctionspanmoduleIdargumentMatch);
1200         if (!conversion || conversion->GetConversionType() != ConversionType::explicit_)
1201         {
1202             throw Exception("type '" + ToUtf8(firstTypeArgument->FullName()) + "' is not explicitly convertible to '" + ToUtf8(secondTypeArgument->FullName()) + "'"spanmoduleId);
1203         }
1204         else
1205         {
1206             result = true;
1207             boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
1208         }
1209     }
1210     else
1211     {
1212         throw Exception("the explicitly convertible constraint needs two type arguments"spanmoduleId);
1213     }
1214 }
1215 
1216 void ConstraintChecker::Visit(CommonConstraintNode& commonConstraintNode)
1217 {
1218     if (firstTypeArgument && secondTypeArgument)
1219     {
1220         BoundTemplateParameterSymbol* commonType = new BoundTemplateParameterSymbol(spanmoduleIdU"CommonType");
1221         bool same = TypesEqual(firstTypeArgumentsecondTypeArgument);
1222         if (same)
1223         {
1224             commonType->SetType(firstTypeArgument);
1225         }
1226         else
1227         {
1228             ArgumentMatch argumentMatch;
1229             FunctionSymbol* conversion = boundCompileUnit.GetConversion(firstTypeArgumentsecondTypeArgumentcontainerScopecurrentFunctionspanmoduleIdargumentMatch);
1230             if (conversion && conversion->GetConversionType() == ConversionType::implicit_)
1231             {
1232                 commonType->SetType(secondTypeArgument);
1233             }
1234             else
1235             {
1236                 ArgumentMatch argumentMatch;
1237                 FunctionSymbol* conversion = boundCompileUnit.GetConversion(secondTypeArgumentfirstTypeArgumentcontainerScopecurrentFunctionspanmoduleIdargumentMatch);
1238                 if (conversion && conversion->GetConversionType() == ConversionType::implicit_)
1239                 {
1240                     commonType->SetType(firstTypeArgument);
1241                 }
1242                 else
1243                 {
1244                     throw Exception("type '" + ToUtf8(firstTypeArgument->FullName()) + "' is not same or convertible to type '" + ToUtf8(secondTypeArgument->FullName()) + "' or vice versa"spanmoduleId);
1245                 }
1246             }
1247         }
1248         containerScope->Install(commonType);
1249         boundTemplateParameters.push_back(std::unique_ptr<BoundTemplateParameterSymbol>(commonType));
1250         result = true;
1251         boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
1252     }
1253     else
1254     {
1255         throw Exception("the common constraint needs two type arguments"spanmoduleId);
1256     }
1257 }
1258 
1259 void ConstraintChecker::Visit(NonreferenceTypeConstraintNode& nonreferenceTypeConstraintNode)
1260 {
1261     if (firstTypeArgument)
1262     {
1263         bool referenceType = firstTypeArgument->IsReferenceType();
1264         if (referenceType)
1265         {
1266             throw Exception("type '" + ToUtf8(firstTypeArgument->FullName()) + "' is a reference type"spanmoduleId);
1267         }
1268         else
1269         {
1270             result = true;
1271             boundConstraint.reset(new BoundAtomicConstraint(spanmoduleIdtrue));
1272         }
1273     }
1274     else
1275     {
1276         throw Exception("the nonreference type constraint needs one type argument"spanmoduleId);
1277     }
1278 }
1279 
1280 std::std::unique_ptr<BoundConcept>Instantiate(ConceptSymbol*conceptSymbolconststd::std::vector<TypeSymbol*>&typeArgumentsBoundCompileUnit&boundCompileUnitContainerScope*containerScope
1281     BoundFunction* currentFunctionstd::std::unique_ptr<BoundConstraint>&boundConstraintconstSpan&spanconstboost::uuids::uuid&moduleIdstd::std::unique_ptr<Exception>&exception)
1282 {
1283     ConceptNode* conceptNode = conceptSymbol->GetConceptNode();
1284     if (!conceptNode)
1285     {
1286         Node* node = boundCompileUnit.GetSymbolTable().GetNode(conceptSymbol);
1287         Assert(node->IsConceptNode()"concept node expected");
1288         conceptNode = static_cast<ConceptNode*>(node);
1289     }
1290     int n = conceptSymbol->Arity();
1291     if (n != typeArguments.size())
1292     {
1293         throw Exception("number of type arguments does not match number of template parameters of concept symbol"spanmoduleIdconceptSymbol->GetSpan()conceptSymbol->SourceModuleId());
1294     }
1295     ContainerScope instantiationScope;
1296     instantiationScope.SetParentScope(containerScope);
1297     std::vector<std::std::unique_ptr<BoundTemplateParameterSymbol>>boundTemplateParameters;
1298     TypeSymbol* firstTypeArgument = nullptr;
1299     TypeSymbol* secondTypeArgument = nullptr;
1300     for (int i = 0; i < n; ++i)
1301     {
1302         TemplateParameterSymbol* templateParameterSymbol = conceptSymbol->TemplateParameters()[i];
1303         TypeSymbol* typeArgument = typeArguments[i];
1304         if (typeArgument->RemoveConst(spanmoduleId)->IsBasicTypeSymbol())
1305         {
1306             typeArgument = typeArgument->RemoveConst(spanmoduleId);
1307         }
1308         if (i == 0)
1309         {
1310             firstTypeArgument = typeArgument;
1311         }
1312         else if (i == 1)
1313         {
1314             secondTypeArgument = typeArgument;
1315         }
1316         BoundTemplateParameterSymbol* boundTemplateParameter = new BoundTemplateParameterSymbol(spanmoduleIdtemplateParameterSymbol->Name());
1317         boundTemplateParameter->SetType(typeArgument);
1318         boundTemplateParameters.push_back(std::unique_ptr<BoundTemplateParameterSymbol>(boundTemplateParameter));
1319         instantiationScope.Install(boundTemplateParameter);
1320     }
1321     ConstraintChecker checker(firstTypeArgumentsecondTypeArgumentboundCompileUnit&instantiationScopecurrentFunctionspanmoduleIdexception);
1322     try
1323     {
1324         conceptNode->Accept(checker);
1325         bool result = checker.Result();
1326         boundConstraint = std::move(checker.GetBoundConstraint());
1327         if (result)
1328         {
1329             BoundConcept* boundConcept = new BoundConcept(conceptSymboltypeArgumentsspanmoduleId);
1330             boundConcept->SetBoundConstraint(std::unique_ptr<BoundConstraint>(boundConstraint->Clone()));
1331             Symbol* commonTypeSymbol = instantiationScope.Lookup(U"CommonType");
1332             if (commonTypeSymbol)
1333             {
1334                 if (commonTypeSymbol->GetSymbolType() != SymbolType::boundTemplateParameterSymbol)
1335                 {
1336                     throw Exception("'CommonType' symbol found from concept instantiation scope is not bound template parameter"spanmoduleIdcommonTypeSymbol->GetSpan()commonTypeSymbol->SourceModuleId());
1337                 }
1338                 BoundTemplateParameterSymbol* commonType = static_cast<BoundTemplateParameterSymbol*>(commonTypeSymbol);
1339                 BoundTemplateParameterSymbol* commonTypeClone = new BoundTemplateParameterSymbol(spanmoduleIdU"CommonType");
1340                 commonTypeClone->SetType(commonType->GetType());
1341                 boundConcept->AddBoundTemplateParameter(std::unique_ptr<BoundTemplateParameterSymbol>(commonTypeClone));
1342                 containerScope->Install(commonTypeClone);
1343                 boundConcept->SetCommonType(commonType->GetType());
1344             }
1345             return std::unique_ptr<BoundConcept>(boundConcept);
1346         }
1347         else
1348         {
1349             return std::unique_ptr<BoundConcept>(nullptr);
1350         }
1351     }
1352     catch (const Exception& ex;)
1353     {
1354         std::string message;
1355         if (typeArguments.size() == 1)
1356         {
1357             message.append("type '" + ToUtf8(firstTypeArgument->FullName()) + "' does not fulfill the requirements of concept '");
1358         }
1359         else
1360         {
1361             message.append("types (");
1362             bool first = true;
1363             for (TypeSymbol* typeArgument : typeArguments)
1364             {
1365                 if (first)
1366                 {
1367                     first = false;
1368                 }
1369                 else
1370                 {
1371                     message.append(", ");
1372                 }
1373                 message.append("'" + ToUtf8(typeArgument->FullName()) + "'");
1374             }
1375             message.append(") do not fulfill the requirements of concept '");
1376         }
1377         message.append(ToUtf8(conceptSymbol->FullName())).append("' because:\n");
1378         message.append(ex.Message());
1379         std::vector<std::std::pair<Spanboost::uuids::uuid>>references;
1380         references.push_back(std::make_pair(conceptSymbol->GetSpan()conceptSymbol->SourceModuleId()));
1381         references.push_back(std::make_pair(ex.Defined()ex.DefinedModuleId()));
1382         references.insert(references.end()ex.References().begin()ex.References().end());
1383         throw Exception(messagespanmoduleIdreferences);
1384     }
1385 }
1386 
1387 bool CheckConstraint(ConstraintNode* constraintconst NodeList<Node>& usingNodesBoundCompileUnit& boundCompileUnitContainerScope* containerScopeBoundFunction* currentFunction
1388     const std::std::vector<TemplateParameterSymbol*>&templateParametersconststd::std::unordered_map<TemplateParameterSymbol*TypeSymbol*>&templateParameterMap
1389     std::std::unique_ptr<BoundConstraint>&boundConstraintconstSpan&spanconstboost::uuids::uuid&moduleIdFunctionSymbol* viableFunctionstd::std::unique_ptr<Exception>&conceptCheckException)
1390 {
1391     bool fileScopeAdded = false;
1392     try
1393     {
1394         std::unique_ptr<FileScope> fileScope(new FileScope());
1395         int nu = usingNodes.Count();
1396         for (int i = 0; i < nu; ++i)
1397         {
1398             Node* usingNode = usingNodes[i];
1399             switch (usingNode->GetNodeType())
1400             {
1401                 case NodeType::aliasNode:
1402                 {
1403                     AliasNode* aliasNode = static_cast<AliasNode*>(usingNode);
1404                     fileScope->InstallAlias(containerScopealiasNode);
1405                     break;
1406                 }
1407                 case NodeType::namespaceImportNode:
1408                 {
1409                     NamespaceImportNode* importNode = static_cast<NamespaceImportNode*>(usingNode);
1410                     fileScope->InstallNamespaceImport(containerScopeimportNode);
1411                     break;
1412                 }
1413                 default:
1414                 {
1415                     throw Exception("unknown using node type"usingNode->GetSpan()usingNode->ModuleId());
1416                 }
1417             }
1418         }
1419         ContainerScope constraintCheckScope;
1420         constraintCheckScope.SetParentScope(containerScope);
1421         std::vector<std::std::unique_ptr<BoundTemplateParameterSymbol>>boundTemplateParameters;
1422         TypeSymbol* firstTypeArgument = nullptr;
1423         TypeSymbol* secondTypeArgument = nullptr;
1424         int n = templateParameters.size();
1425         for (int i = 0; i < n; ++i)
1426         {
1427             TemplateParameterSymbol* templateParameterSymbol = templateParameters[i];
1428             auto it = templateParameterMap.find(templateParameterSymbol);
1429             if (it != templateParameterMap.cend())
1430             {
1431                 TypeSymbol* templateArgumentType = it->second;
1432                 if (i == 0)
1433                 {
1434                     firstTypeArgument = templateArgumentType;
1435                 }
1436                 else if (i == 1)
1437                 {
1438                     secondTypeArgument = templateArgumentType;
1439                 }
1440                 BoundTemplateParameterSymbol* boundTemplateParameterSymbol = new BoundTemplateParameterSymbol(spanmoduleIdtemplateParameterSymbol->Name());
1441                 boundTemplateParameterSymbol->SetType(templateArgumentType);
1442                 boundTemplateParameters.push_back(std::unique_ptr<BoundTemplateParameterSymbol>(boundTemplateParameterSymbol));
1443                 constraintCheckScope.Install(boundTemplateParameterSymbol);
1444             }
1445             else
1446             {
1447                 throw Exception("template parameter symbol '" + ToUtf8(templateParameterSymbol->Name()) + "' not found from template parameter map"spanmoduleIdviableFunction->GetSpan()viableFunction->SourceModuleId());
1448             }
1449         }
1450         boundCompileUnit.AddFileScope(fileScope.release());
1451         fileScopeAdded = true;
1452         ConstraintChecker constraintChecker(firstTypeArgumentsecondTypeArgumentboundCompileUnit&constraintCheckScopecurrentFunctionspanmoduleIdconceptCheckException);
1453         constraint->Accept(constraintChecker);
1454         boundCompileUnit.RemoveLastFileScope();
1455         bool result = constraintChecker.Result();
1456         boundConstraint = std::move(constraintChecker.GetBoundConstraint());
1457         return result;
1458     }
1459     catch (const Exception& ex;)
1460     {
1461         if (fileScopeAdded)
1462         {
1463             boundCompileUnit.RemoveLastFileScope();
1464         }
1465         conceptCheckException.reset(new Exception(ex));
1466         return false;
1467     }
1468 }
1469 
1470 } } // namespace cmajor::binder