Advanced type safety checks beyond greycat-lang lint
Performs advanced type safety checks to catch issues beyond standard linting.
/plugin marketplace add datathings/marketplace/plugin install greycat@datathingsPurpose: Catch type safety issues and anti-patterns that greycat-lang lint doesn't detect
Run After: Each sprint, before releases, when modifying type definitions
This command performs advanced type safety analysis in 5 categories:
Ensure all API response types are marked @volatile.
# Extract all @expose functions and their return types
grep -rn "@expose" backend/src/api/ --include="*.gcl" -A 5 | grep "fn.*:" | sed 's/.*: //' | sed 's/ {.*//'
For each return type found:
📍 backend/src/api/search_api.gcl:63
⚠️ MISSING @volatile: API response type not marked as volatile
Function:
@expose
fn semanticSearch(...): PaginatedResult<SearchResultView> {
Type Definition (backend/src/api/api_types.gcl:45):
type PaginatedResult<T> { ← Missing @volatile
items: Array<T>;
total: int;
}
Issue:
- API response type should be @volatile (not persisted)
- Missing decorator causes unnecessary database storage
Fix:
@volatile
type PaginatedResult<T> {
items: Array<T>;
total: int;
}
Priority: MEDIUM
Impact: Database bloat, performance
Detect misuse of persistent collections (nodeList/nodeIndex/nodeTime/nodeGeo) in temporary contexts.
# Find all persistent collection declarations
grep -rn "nodeList\|nodeIndex\|nodeTime\|nodeGeo" backend/src/ --include="*.gcl" -B 3 -A 3
For each occurrence, determine context:
✅ LEGITIMATE (Global variable):
// In backend/src/model/data.gcl (module-level)
var documents: nodeList<node<Document>>;
✅ LEGITIMATE (Type field):
type Document {
chunks: nodeIndex<node<Chunk>, bool>;
}
⚠️ SUSPICIOUS (Local variable):
fn buildResults() {
var results = nodeList<T> {}; ← Should be Array
}
⚠️ SUSPICIOUS (Function parameter):
fn process(items: nodeList<T>) { ← Should be Array
// ...
}
📍 backend/src/service/builder.gcl:34
⚠️ TYPE SAFETY: Local variable using persistent collection
Code:
32: fn buildResults(items: Array<Item>): Array<Result> {
33: var results = nodeList<node<Result>> {};
34: for (i, item in items) {
35: results.add(node<Result>{ ... });
36: }
37: return results; ← Type error!
38: }
Problem:
- Using nodeList for temporary local variable
- Function returns Array but creates nodeList
- Unnecessary persistence overhead
Fix:
var results = Array<node<Result>> {};
Priority: HIGH
Impact: Type mismatch, performance overhead
Find potential null pointer dereferences and missing null checks.
# Find .resolve() chains without null checks
grep -rn "\.resolve()\..*\." backend/src/ --include="*.gcl"
# Find arrow operator chains
grep -rn "->.*->" backend/src/ --include="*.gcl"
Check if null checking exists before dereference:
if (x == null) before usage?.!!📍 backend/src/service/document_service.gcl:67
⚠️ NULL SAFETY: Potential null pointer dereference
Code:
65: fn getDocumentAuthor(docId: String): String {
66: var doc_node = documents_by_id.get(docId);
67: return doc_node.resolve().author.resolve().name;
68: }
Problem:
- No null check on doc_node (docId might not exist)
- No null check on author (document might not have author)
- Will throw runtime error if any step fails
Fix Option 1 (Null checks):
fn getDocumentAuthor(docId: String): String {
var doc_node = documents_by_id.get(docId);
if (doc_node == null) {
throw "Document not found: ${docId}";
}
var doc = doc_node.resolve();
if (doc.author == null) {
throw "Document has no author";
}
return doc.author.resolve().name;
}
Fix Option 2 (Optional chaining):
fn getDocumentAuthor(docId: String): String? {
return documents_by_id.get(docId)?.resolve().author?.resolve().name;
}
Priority: MEDIUM
Impact: Runtime errors
Ensure proper type usage patterns across codebase.
Find non-nullable collections that might not be initialized:
# Find type fields with collections
grep -rn "^\s*[a-z_]*:\s*\(Array\|Map\|nodeList\|nodeIndex\)" backend/src/model/ --include="*.gcl"
Check if they're nullable or always initialized.
📍 backend/src/model/document.gcl:12
⚠️ TYPE SAFETY: Non-nullable collection not always initialized
Type:
type Document {
id: String;
chunks: nodeList<node<Chunk>>; ← Non-nullable
}
Usage (backend/src/service/import.gcl:45):
var doc = Document {
id: "123"
// chunks not initialized ← RUNTIME ERROR
};
Problem:
- Non-nullable collection must be initialized on creation
- Missing initialization causes runtime error
Fix Option 1 (Make nullable):
chunks: nodeList<node<Chunk>>?;
Fix Option 2 (Always initialize):
var doc = Document {
id: "123",
chunks: nodeList<node<Chunk>> {}
};
Priority: HIGH
Impact: Runtime errors
Find collections storing objects instead of node references:
# Find nodeList/nodeIndex not storing nodes
grep -rn "nodeList<[^n]" backend/src/ --include="*.gcl"
grep -rn "nodeIndex<.*,\s*[^n]" backend/src/ --include="*.gcl"
📍 backend/src/model/data.gcl:8
⚠️ TYPE SAFETY: Storing objects directly in persistent collection
Code:
var items: nodeList<Item>; ← Should be nodeList<node<Item>>
Problem:
- nodeList should store node references, not objects
- Direct object storage breaks persistence model
Fix:
var items: nodeList<node<Item>>;
// When adding:
items.add(node<Item>{ Item { ... } });
Priority: HIGH
Impact: Persistence errors
Detect generic type parameters on static functions (not allowed in GreyCat).
# Find static fn with <T> syntax
grep -rn "static fn.*<.*>.*(" backend/src/ --include="*.gcl"
📍 backend/src/service/utils.gcl:12
❌ TYPE ERROR: Generic type parameter on static function
Code:
abstract type Utils {
static fn process<T>(value: T): T { ← NOT ALLOWED
return value;
}
}
Problem:
- Generic type parameters (<T>) not allowed on static functions in GreyCat
- Will cause compilation error
Fix Option 1 (Remove static):
type Utils<T> {
fn process(value: T): T {
return value;
}
}
// Usage: Utils<int>{}.process(42)
Fix Option 2 (Make concrete):
abstract type Utils {
static fn processInt(value: int): int { ... }
static fn processString(value: String): String { ... }
}
Priority: CRITICAL
Impact: Compilation error
===============================================================================
GREYCAT TYPE SAFETY ANALYSIS
===============================================================================
Files Analyzed: 45 .gcl files
Analysis Date: 2026-01-08
ISSUES FOUND:
CRITICAL (Compilation Errors):
[ ] 2 static functions with generic type parameters
HIGH (Runtime Errors):
[ ] 5 uninitialized non-nullable collections
[ ] 4 incorrect node storage in persistent collections
[ ] 3 local variables using persistent types
MEDIUM (Safety Issues):
[ ] 8 missing @volatile on API response types
[ ] 6 potential null pointer dereferences
[ ] 4 unsafe type casts
LOW (Best Practices):
[ ] 12 missing type annotations (could be inferred)
[ ] 7 overly broad types (Object vs specific)
TOTAL ISSUES: 51
ESTIMATED FIX TIME:
Critical: 30 minutes (fix immediately)
High: 2 hours (fix this sprint)
Medium: 3 hours (fix next sprint)
Low: 1 hour (nice to have)
===============================================================================
===============================================================================
CRITICAL ISSUES (Fix Immediately)
===============================================================================
1. COMPILATION ERROR: Generic static function
📍 backend/src/service/utils.gcl:12
[Details above]
2. COMPILATION ERROR: Generic static function
📍 backend/src/service/helper.gcl:34
[Details above]
===============================================================================
HIGH PRIORITY ISSUES
===============================================================================
1. RUNTIME ERROR: Uninitialized collection
📍 backend/src/model/document.gcl:12
[Details above]
...
===============================================================================
After fixes, verify:
# 1. Run greycat-lang lint (should pass)
greycat-lang lint
# 2. Run this type check again
/typecheck
# 3. Run tests
greycat test
# 4. Build project
greycat build
✓ All files scanned (.gcl files in backend/src/) ✓ Volatile decorators checked on API response types ✓ Collection usage validated (persistent vs non-persistent) ✓ Null safety analyzed (potential NPEs) ✓ Type consistency verified (initialization, node storage) ✓ Generic types checked (no generics on static functions) ✓ Report generated with prioritized issues ✓ Zero CRITICAL issues before release
# 1. Run type safety check
/typecheck
# 2. Review report (51 issues found)
# - 2 CRITICAL
# - 12 HIGH
# - 18 MEDIUM
# - 19 LOW
# 3. Fix CRITICAL immediately
# - Remove generic params from static functions
# 4. Verify fix
greycat-lang lint # ✓ Passes
greycat build # ✓ Builds successfully
# 5. Fix HIGH priority issues
# - Initialize collections
# - Fix node storage
# - Replace nodeList with Array in local vars
# 6. Re-run check
/typecheck
# → CRITICAL: 0
# → HIGH: 0
# → MEDIUM: 18 (to address next sprint)
# 7. Commit
git add backend/
git commit -m "fix: resolve type safety issues (CRITICAL+HIGH)"
Use Before:
/apicheck - Fix type issues before API review/backend - Type check before general cleanup/docs - Ensure types are correct before documentationUse After:
Detection: Function returns custom type, type lacks @volatile Fix: Add @volatile decorator to type Frequency: Common in new API endpoints
Detection: Variable declared inside function with nodeList type Fix: Change to Array Frequency: Very common antipattern
Detection: Non-nullable collection field, object created without initializing it Fix: Either make nullable or always initialize Frequency: Common in model types
Detection: Multiple .resolve() or -> without null checks Fix: Add null checks or use optional chaining Frequency: Common in service layer
Detection: static fn with <T> syntax Fix: Remove static or remove generics Frequency: Rare, but critical error