1
2
3
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(name, ScopeLookup::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(name, ScopeLookup::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* conceptIdNode, BoundCompileUnit& boundCompileUnit, ContainerScope* containerScope)
128 {
129 ConceptIdResolver conceptIdResolver(boundCompileUnit, containerScope);
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* conceptSymbol, const std::std::vector<TypeSymbol*>&typeArguments, BoundCompileUnit&boundCompileUnit, ContainerScope*containerScope,
143 BoundFunction* currentFunction, std::std::unique_ptr<BoundConstraint>&boundConstraint, constSpan&span, constboost::uuids::uuid&modukeId, std::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& moduleId, std::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(derivationRec, type->DerivationRec());
253 if (!unifiedDerivationRec.derivations.empty())
254 {
255 type = boundCompileUnit.GetSymbolTable().MakeDerivedType(type->BaseType(), unifiedDerivationRec, span, moduleId);
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
380 }
381
382 void ConstraintChecker::Visit(IdentifierNode& identifierNode)
383 {
384 Reset();
385 const std::u32string& name = identifierNode.Str();
386 Symbol* symbol = containerScope->Lookup(name, ScopeLookup::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(span, moduleId, new IdentifierNode(span, moduleId, ns->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(&templateIdNode, boundCompileUnit, containerScope);
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(name, ScopeLookup::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(span, moduleId, new IdentifierNode(span, moduleId, ns->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(span, moduleId, false));
554 if (!exception)
555 {
556 exception.reset(new Exception(ex));
557 }
558 }
559 catch (...)
560 {
561 left = false;
562 leftBoundConstraint.reset(new BoundAtomicConstraint(span, moduleId, false));
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(span, moduleId, false));
575 if (!exception)
576 {
577 exception.reset(new Exception(ex));
578 }
579 }
580 catch (...)
581 {
582 right = false;
583 rightBoundConstraint.reset(new BoundAtomicConstraint(span, moduleId, false));
584 }
585 result = left || right;
586 boundConstraint.reset(new BoundDisjunctiveConstraint(span, moduleId, leftBoundConstraint.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(span, moduleId, false));
610 if (!exception)
611 {
612 exception.reset(new Exception(ex));
613 }
614 }
615 catch (...)
616 {
617 left = false;
618 leftBoundConstraint.reset(new BoundAtomicConstraint(span, moduleId, false));
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(span, moduleId, false));
631 if (!exception)
632 {
633 exception.reset(new Exception(ex));
634 }
635 }
636 catch (...)
637 {
638 right = false;
639 rightBoundConstraint.reset(new BoundAtomicConstraint(span, moduleId, false));
640 }
641 result = left && right;
642 boundConstraint.reset(new BoundConjunctiveConstraint(span, moduleId, leftBoundConstraint.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(invokeExprNode, symbolTable.GetTypeByName(U"bool"), containerScope, boundCompileUnit, false, currentFunction,
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(span, moduleId);
677 TypeSymbol* rightPlainType = rightType->PlainType(span, moduleId);
678 if (TypesEqual(leftPlainType, rightPlainType))
679 {
680 result = true;
681 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
682 }
683 else
684 {
685 result = false;
686 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, false));
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(conceptSymbol, typeArguments);
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(span, moduleId, U"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(conceptSymbol, typeArguments, boundCompileUnit, containerScope, currentFunction, constraint, span, moduleId, exception);
712 if (boundConcept)
713 {
714 result = true;
715 boundConstraint.reset(constraint.release());
716 boundCompileUnit.GetConceptRepository().AddBoundConcept(key, std::move(boundConcept));
717 }
718 else
719 {
720 result = false;
721 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, false));
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(conceptSymbol, typeArguments);
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(span, moduleId, U"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(conceptSymbol, typeArguments, boundCompileUnit, containerScope, currentFunction, constraint, span, moduleId, exception);
769 if (boundConcept)
770 {
771 result = true;
772 boundConstraint.reset(constraint.release());
773 boundCompileUnit.GetConceptRepository().AddBoundConcept(key, std::move(boundConcept));
774 }
775 else
776 {
777 result = false;
778 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, false));
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(span, moduleId, result));
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(span, moduleId, firstTypeArgument->AddPointer(span, moduleId))));
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(), boundCompileUnit, containerScope);
807 parameterTypes.push_back(parameterType);
808 arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(span, moduleId, parameterType)));
809 }
810 std::vector<FunctionScopeLookup> lookups;
811 lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parent, containerScope));
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", containerScope, lookups, arguments, boundCompileUnit, currentFunction, span, moduleId,
816 OverloadResolutionFlags::dontInstantiate | OverloadResolutionFlags::dontThrow, templateArgumentTypes, exception);
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<Span, boost::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(message, span, moduleId, references);
844 }
845 else
846 {
847 result = true;
848 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
849 }
850 }
851
852 void ConstraintChecker::Visit(DestructorConstraintNode& destructorConstraintNode)
853 {
854 result = true;
855 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
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(span, moduleId, firstType->AddPointer(span, moduleId))));
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(), boundCompileUnit, containerScope);
871 parameterTypes.push_back(parameterType);
872 arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(span, moduleId, parameterType)));
873 }
874 std::vector<FunctionScopeLookup> lookups;
875 lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parent, containerScope));
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(), containerScope, lookups, arguments, boundCompileUnit, currentFunction, span, moduleId,
880 OverloadResolutionFlags::dontInstantiate | OverloadResolutionFlags::dontThrow | OverloadResolutionFlags::noTemplates, templateArgumentTypes, exception);
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<Span, boost::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(message, span, moduleId, references);
908 }
909 else
910 {
911 result = true;
912 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
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(span, moduleId, firstTypeArgument->AddPointer(span, moduleId))));
920 std::vector<TypeSymbol*> parameterTypes;
921 std::vector<FunctionScopeLookup> lookups;
922 lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parent, containerScope));
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(span, moduleId, true));
935 return;
936 }
937 for (int i = 0; i < n; ++i)
938 {
939 ParameterNode* parameterNode = functionConstraintNode.Parameters()[i];
940 TypeSymbol* parameterType = ResolveType(parameterNode->TypeExpr(), boundCompileUnit, containerScope);
941 lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parent, containerScope));
942 parameterTypes.push_back(parameterType);
943 arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(span, moduleId, parameterType)));
944 }
945 std::vector<TypeSymbol*> templateArgumentTypes;
946 std::unique_ptr<Exception> exception;
947 std::unique_ptr<BoundFunctionCall> functionCall = ResolveOverload(functionConstraintNode.GroupId(), containerScope, lookups, arguments, boundCompileUnit, currentFunction, span, moduleId,
948 OverloadResolutionFlags::dontInstantiate | OverloadResolutionFlags::dontThrow, templateArgumentTypes, exception);
949 if (!functionCall)
950 {
951 arguments.clear();
952 parameterTypes.clear();
953 arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(span, moduleId, firstTypeArgument->AddPointer(span, moduleId))));
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(), boundCompileUnit, containerScope);
960 parameterTypes.push_back(parameterType);
961 arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(span, moduleId, parameterType)));
962 }
963 std::vector<TypeSymbol*> templateArgumentTypes;
964 std::unique_ptr<Exception> exception;
965 std::unique_ptr<BoundFunctionCall> functionCall = ResolveOverload(functionConstraintNode.GroupId(), containerScope, lookups, arguments, boundCompileUnit, currentFunction, span, moduleId,
966 OverloadResolutionFlags::dontInstantiate | OverloadResolutionFlags::dontThrow, templateArgumentTypes, exception);
967 if (!functionCall)
968 {
969 arguments.clear();
970 lookups.clear();
971 lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parent, containerScope));
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(), boundCompileUnit, containerScope);
978 lookups.push_back(FunctionScopeLookup(ScopeLookup::this_and_base_and_parent, parameterType->BaseType()->ClassInterfaceEnumDelegateOrNsScope()));
979 parameterTypes.push_back(parameterType);
980 arguments.push_back(std::unique_ptr<BoundExpression>(new BoundTypeExpression(span, moduleId, parameterType)));
981 }
982 std::vector<TypeSymbol*> templateArgumentTypes;
983 std::unique_ptr<Exception> exception;
984 std::unique_ptr<BoundFunctionCall> functionCall = ResolveOverload(functionConstraintNode.GroupId(), containerScope, lookups, arguments, boundCompileUnit, currentFunction, span, moduleId,
985 OverloadResolutionFlags::dontInstantiate | OverloadResolutionFlags::dontThrow, templateArgumentTypes, exception);
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<Span, boost::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(message, span, moduleId, references);
1013 }
1014 else
1015 {
1016 result = true;
1017 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
1018 }
1019 }
1020 else
1021 {
1022 result = true;
1023 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
1024 }
1025 }
1026 else
1027 {
1028 result = true;
1029 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
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", span, moduleId, conceptIdNode.GetSpan(), conceptIdNode.ModuleId());
1055 }
1056 }
1057 BoundConceptKey key(conceptSymbol, typeArguments);
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(span, moduleId, U"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(conceptSymbol, typeArguments, boundCompileUnit, containerScope, currentFunction, constraint, span, moduleId, exception);
1075 if (boundConcept)
1076 {
1077 result = true;
1078 boundConstraint.reset(constraint.release());
1079 boundCompileUnit.GetConceptRepository().AddBoundConcept(key, std::move(boundConcept));
1080 }
1081 else
1082 {
1083 result = false;
1084 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, false));
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(span, moduleId, true);
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(firstTypeArgument, secondTypeArgument);
1129 if (!same)
1130 {
1131 throw Exception("type '" + ToUtf8(firstTypeArgument->FullName()) + "' is not same type as '" + ToUtf8(secondTypeArgument->FullName()) + "'", span, moduleId);
1132 }
1133 else
1134 {
1135 result = true;
1136 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
1137 }
1138 }
1139 else
1140 {
1141 throw Exception("the same type constraint needs two type arguments", span, moduleId);
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()) + "'", span, moduleId);
1159 }
1160 else
1161 {
1162 result = true;
1163 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
1164 }
1165 }
1166 else
1167 {
1168 throw Exception("the derivded type constraint needs two type arguments", span, moduleId);
1169 }
1170 }
1171
1172 void ConstraintChecker::Visit(ConvertibleConstraintNode& convertibleConstraintNode)
1173 {
1174 if (firstTypeArgument && secondTypeArgument)
1175 {
1176 ArgumentMatch argumentMatch;
1177 FunctionSymbol* conversion = boundCompileUnit.GetConversion(firstTypeArgument, secondTypeArgument, containerScope, currentFunction, span, moduleId, argumentMatch);
1178 if (!conversion || conversion->GetConversionType() == ConversionType::explicit_)
1179 {
1180 throw Exception("type '" + ToUtf8(firstTypeArgument->FullName()) + "' is not implicitly convertible to '" + ToUtf8(secondTypeArgument->FullName()) + "'", span, moduleId);
1181 }
1182 else
1183 {
1184 result = true;
1185 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
1186 }
1187 }
1188 else
1189 {
1190 throw Exception("the convertible constraint needs two type arguments", span, moduleId);
1191 }
1192 }
1193
1194 void ConstraintChecker::Visit(ExplicitlyConvertibleConstraintNode& explicitlyConvertibleConstraintNode)
1195 {
1196 if (firstTypeArgument && secondTypeArgument)
1197 {
1198 ArgumentMatch argumentMatch;
1199 FunctionSymbol* conversion = boundCompileUnit.GetConversion(firstTypeArgument, secondTypeArgument, containerScope, currentFunction, span, moduleId, argumentMatch);
1200 if (!conversion || conversion->GetConversionType() != ConversionType::explicit_)
1201 {
1202 throw Exception("type '" + ToUtf8(firstTypeArgument->FullName()) + "' is not explicitly convertible to '" + ToUtf8(secondTypeArgument->FullName()) + "'", span, moduleId);
1203 }
1204 else
1205 {
1206 result = true;
1207 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
1208 }
1209 }
1210 else
1211 {
1212 throw Exception("the explicitly convertible constraint needs two type arguments", span, moduleId);
1213 }
1214 }
1215
1216 void ConstraintChecker::Visit(CommonConstraintNode& commonConstraintNode)
1217 {
1218 if (firstTypeArgument && secondTypeArgument)
1219 {
1220 BoundTemplateParameterSymbol* commonType = new BoundTemplateParameterSymbol(span, moduleId, U"CommonType");
1221 bool same = TypesEqual(firstTypeArgument, secondTypeArgument);
1222 if (same)
1223 {
1224 commonType->SetType(firstTypeArgument);
1225 }
1226 else
1227 {
1228 ArgumentMatch argumentMatch;
1229 FunctionSymbol* conversion = boundCompileUnit.GetConversion(firstTypeArgument, secondTypeArgument, containerScope, currentFunction, span, moduleId, argumentMatch);
1230 if (conversion && conversion->GetConversionType() == ConversionType::implicit_)
1231 {
1232 commonType->SetType(secondTypeArgument);
1233 }
1234 else
1235 {
1236 ArgumentMatch argumentMatch;
1237 FunctionSymbol* conversion = boundCompileUnit.GetConversion(secondTypeArgument, firstTypeArgument, containerScope, currentFunction, span, moduleId, argumentMatch);
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", span, moduleId);
1245 }
1246 }
1247 }
1248 containerScope->Install(commonType);
1249 boundTemplateParameters.push_back(std::unique_ptr<BoundTemplateParameterSymbol>(commonType));
1250 result = true;
1251 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
1252 }
1253 else
1254 {
1255 throw Exception("the common constraint needs two type arguments", span, moduleId);
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", span, moduleId);
1267 }
1268 else
1269 {
1270 result = true;
1271 boundConstraint.reset(new BoundAtomicConstraint(span, moduleId, true));
1272 }
1273 }
1274 else
1275 {
1276 throw Exception("the nonreference type constraint needs one type argument", span, moduleId);
1277 }
1278 }
1279
1280 std::std::unique_ptr<BoundConcept>Instantiate(ConceptSymbol*conceptSymbol, conststd::std::vector<TypeSymbol*>&typeArguments, BoundCompileUnit&boundCompileUnit, ContainerScope*containerScope,
1281 BoundFunction* currentFunction, std::std::unique_ptr<BoundConstraint>&boundConstraint, constSpan&span, constboost::uuids::uuid&moduleId, std::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", span, moduleId, conceptSymbol->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(span, moduleId)->IsBasicTypeSymbol())
1305 {
1306 typeArgument = typeArgument->RemoveConst(span, moduleId);
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(span, moduleId, templateParameterSymbol->Name());
1317 boundTemplateParameter->SetType(typeArgument);
1318 boundTemplateParameters.push_back(std::unique_ptr<BoundTemplateParameterSymbol>(boundTemplateParameter));
1319 instantiationScope.Install(boundTemplateParameter);
1320 }
1321 ConstraintChecker checker(firstTypeArgument, secondTypeArgument, boundCompileUnit, &instantiationScope, currentFunction, span, moduleId, exception);
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(conceptSymbol, typeArguments, span, moduleId);
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", span, moduleId, commonTypeSymbol->GetSpan(), commonTypeSymbol->SourceModuleId());
1337 }
1338 BoundTemplateParameterSymbol* commonType = static_cast<BoundTemplateParameterSymbol*>(commonTypeSymbol);
1339 BoundTemplateParameterSymbol* commonTypeClone = new BoundTemplateParameterSymbol(span, moduleId, U"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<Span, boost::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(message, span, moduleId, references);
1384 }
1385 }
1386
1387 bool CheckConstraint(ConstraintNode* constraint, const NodeList<Node>& usingNodes, BoundCompileUnit& boundCompileUnit, ContainerScope* containerScope, BoundFunction* currentFunction,
1388 const std::std::vector<TemplateParameterSymbol*>&templateParameters, conststd::std::unordered_map<TemplateParameterSymbol*, TypeSymbol*>&templateParameterMap,
1389 std::std::unique_ptr<BoundConstraint>&boundConstraint, constSpan&span, constboost::uuids::uuid&moduleId, FunctionSymbol* viableFunction, std::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(containerScope, aliasNode);
1405 break;
1406 }
1407 case NodeType::namespaceImportNode:
1408 {
1409 NamespaceImportNode* importNode = static_cast<NamespaceImportNode*>(usingNode);
1410 fileScope->InstallNamespaceImport(containerScope, importNode);
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(span, moduleId, templateParameterSymbol->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", span, moduleId, viableFunction->GetSpan(), viableFunction->SourceModuleId());
1448 }
1449 }
1450 boundCompileUnit.AddFileScope(fileScope.release());
1451 fileScopeAdded = true;
1452 ConstraintChecker constraintChecker(firstTypeArgument, secondTypeArgument, boundCompileUnit, &constraintCheckScope, currentFunction, span, moduleId, conceptCheckException);
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 } }