Phase 11b — Validation & Conflict Completion: - Step 297: Subject 2-4 validation rules E0600-E0805 (12/12) - Step 298: Subject 5-8 validation rules E0900-E1202 (12/12) - Step 299: Cross-type conflict detection, 6 conflict pairs (12/12) - Step 300: TransformEngineExtended — float folding, dead var, annotation-aware (12/12) - Step 301: Phase 11b integration tests (8/8) Phase 11c — Parser Deepening (start): - Step 302: New AST nodes — ClassDeclaration, InterfaceDeclaration, MethodDeclaration, GenericType, TypeParameter with JSON roundtrip (12/12) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
91 lines
3.5 KiB
C++
91 lines
3.5 KiB
C++
#pragma once
|
|
// Step 299: Cross-type annotation conflict detection
|
|
//
|
|
// Detects conflicts between different annotation types on the same node.
|
|
// This extends AnnotationConflict.h which handles same-family parent/child
|
|
// conflicts. This file detects semantic conflicts across annotation families.
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <functional>
|
|
#include "ast/ASTNode.h"
|
|
#include "ast/Annotation.h"
|
|
#include "AnnotationConflict.h"
|
|
|
|
struct CrossTypeConflict {
|
|
std::string type1;
|
|
std::string type2;
|
|
std::string message;
|
|
std::string nodeId;
|
|
};
|
|
|
|
inline void collectCrossTypeConflicts(const ASTNode* node,
|
|
std::vector<CrossTypeConflict>& out) {
|
|
if (!node) return;
|
|
auto annos = node->getChildren("annotations");
|
|
|
|
// Build a set of annotation types present on this node
|
|
std::map<std::string, const ASTNode*> present;
|
|
for (const auto* a : annos) {
|
|
present[a->conceptType] = a;
|
|
}
|
|
|
|
// Check conflict pairs
|
|
auto checkPair = [&](const std::string& t1, const std::string& t2,
|
|
const std::string& msg,
|
|
std::function<bool()> condition = nullptr) {
|
|
if (present.count(t1) && present.count(t2)) {
|
|
if (!condition || condition()) {
|
|
out.push_back({t1, t2, msg, node->id});
|
|
}
|
|
}
|
|
};
|
|
|
|
// 1. @Pure + @Blocking → "Pure function cannot be blocking"
|
|
checkPair("PureAnnotation", "BlockingAnnotation",
|
|
"Pure function cannot be blocking");
|
|
|
|
// 2. @Atomic + @Sync → "Atomic operations conflict with sync primitives"
|
|
checkPair("AtomicAnnotation", "SyncAnnotation",
|
|
"Atomic operations conflict with sync primitives");
|
|
|
|
// 3. @Capture(move) + @Owner(Shared_ARC) → "Move capture conflicts with shared ownership"
|
|
checkPair("CaptureAnnotation", "OwnerAnnotation",
|
|
"Move capture conflicts with shared ownership",
|
|
[&]() {
|
|
auto* cap = static_cast<const CaptureAnnotation*>(present["CaptureAnnotation"]);
|
|
auto* own = static_cast<const OwnerAnnotation*>(present["OwnerAnnotation"]);
|
|
return cap->strategy == "move" && own->strategy == "Shared_ARC";
|
|
});
|
|
|
|
// 4. @ConstExpr + @Exec(async) → "Compile-time eval conflicts with async execution"
|
|
checkPair("ConstExprAnnotation", "ExecAnnotation",
|
|
"Compile-time eval conflicts with async execution",
|
|
[&]() {
|
|
auto* exec = static_cast<const ExecAnnotation*>(present["ExecAnnotation"]);
|
|
return exec->mode == "async";
|
|
});
|
|
|
|
// 5. @Inline(Always) + @TailCall → "Always-inline conflicts with tail call optimization"
|
|
checkPair("InlineAnnotation", "TailCallAnnotation",
|
|
"Always-inline conflicts with tail call optimization",
|
|
[&]() {
|
|
auto* inl = static_cast<const InlineAnnotation*>(present["InlineAnnotation"]);
|
|
return inl->mode == "Always";
|
|
});
|
|
|
|
// 6. @Pack + @Layout(aligned) → "Packed layout conflicts with alignment"
|
|
checkPair("PackAnnotation", "LayoutAnnotation",
|
|
"Packed layout conflicts with alignment",
|
|
[&]() {
|
|
auto* lay = static_cast<const LayoutAnnotation*>(present["LayoutAnnotation"]);
|
|
return lay->mode == "aligned";
|
|
});
|
|
|
|
// Recurse into children
|
|
for (auto* child : node->allChildren()) {
|
|
collectCrossTypeConflicts(child, out);
|
|
}
|
|
}
|