# # # The Nim Compiler # (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## Implements type sanity checking for ASTs resulting from macros. Lots of ## room for improvement here. import ast, msgs, types, options, trees, nimsets type FieldTracker = object index: int remaining: int constr: PNode delete: bool # to delete fields from inactive case branches FieldInfo = ref object sym: PSym delete: bool proc caseBranchMatchesExpr(branch, matched: PNode): bool = # copied from sem result = false for i in 0 ..< branch.len-1: if branch[i].kind == nkRange: if overlap(branch[i], matched): return true elif exprStructuralEquivalent(branch[i], matched): return true proc ithField(n: PNode, field: var FieldTracker): FieldInfo = result = nil case n.kind of nkRecList: for i in 0..= x.kidsLen: globalError conf, n.info, "invalid field at index " & $i else: annotateType(n[i], x[i], conf, producedClosure) elif x.kind == tyProc and x.callConv == ccClosure: n.typ = t if n.len > 1 and n[1].kind notin {nkEmpty, nkNilLit}: producedClosure = true elif x.kind == tyOpenArray: # `opcSlice` transforms slices into tuples if n.kind == nkTupleConstr: let bracketExpr = newNodeI(nkBracket, n.info) left = int n[1].intVal right = int n[2].intVal bracketExpr.flags = n.flags case n[0].kind # is this a string slice or a array slice of nkStrKinds: for i in left..right: bracketExpr.add newIntNode(nkCharLit, BiggestInt n[0].strVal[i]) annotateType(bracketExpr[^1], x.elementType, conf, producedClosure) of nkBracket: for i in left..right: bracketExpr.add n[0][i] annotateType(bracketExpr[^1], x.elementType, conf, producedClosure) else: globalError(conf, n.info, "Incorrectly generated tuple constr") n[] = bracketExpr[] n.typ = t else: globalError(conf, n.info, "() must have a tuple type") of nkBracket: if x.kind in {tyArray, tySequence, tyOpenArray}: n.typ = t for m in n: annotateType(m, x.elemType, conf, producedClosure) else: globalError(conf, n.info, "[] must have some form of array type") of nkCurly: if x.kind in {tySet}: n.typ = t for m in n: if m.kind == nkRange: annotateType(m[0], x.elemType, conf, producedClosure) annotateType(m[1], x.elemType, conf, producedClosure) else: annotateType(m, x.elemType, conf, producedClosure) else: globalError(conf, n.info, "{} must have the set type") of nkFloatLit..nkFloat128Lit: if x.kind in {tyFloat..tyFloat128}: n.typ = t else: globalError(conf, n.info, "float literal must have some float type") of nkCharLit..nkUInt64Lit: if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}: n.typ = t else: globalError(conf, n.info, "integer literal must have some int type") of nkStrLit..nkTripleStrLit: if x.kind in {tyString, tyCstring}: n.typ = t else: globalError(conf, n.info, "string literal must be of some string type") of nkNilLit: if x.kind in NilableTypes+{tyString, tySequence}: n.typ = t else: globalError(conf, n.info, "nil literal must be of some pointer type") else: discard