diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 3 | ||||
-rw-r--r-- | compiler/evals.nim | 32 | ||||
-rw-r--r-- | compiler/sem.nim | 6 | ||||
-rw-r--r-- | compiler/semdata.nim | 6 | ||||
-rw-r--r-- | compiler/semexprs.nim | 51 | ||||
-rw-r--r-- | compiler/semtypes.nim | 16 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 62 |
7 files changed, 135 insertions, 41 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 49e050f6c..04ac88c1c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -689,6 +689,7 @@ type # for enum types a list of symbols # for tyInt it can be the int literal # for procs and tyGenericBody, it's the + # the body of the user-defined type class # formal param list # else: unused destructor*: PSym # destructor. warning: nil here may not necessary @@ -701,6 +702,7 @@ type # -1 means that the size is unkwown align*: int # the type's alignment requirements loc*: TLoc + testeeName*: PIdent # the test variable in user-defined type classes TPair*{.final.} = object key*, val*: PObject @@ -1075,6 +1077,7 @@ proc assignType(dest, src: PType) = dest.size = src.size dest.align = src.align dest.destructor = src.destructor + dest.testeeName = src.testeeName # this fixes 'type TLock = TSysLock': if src.sym != nil: if dest.sym != nil: diff --git a/compiler/evals.nim b/compiler/evals.nim index 053068ea4..7bd74b04a 100644 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -53,7 +53,8 @@ type features: TSandboxFlags globals*: TIdNodeTable # state of global vars getType*: proc(n: PNode): PNode {.closure.} - + handleIsOperator*: proc(n: PNode): PNode {.closure.} + PEvalContext* = ref TEvalContext TEvalFlag = enum @@ -916,33 +917,6 @@ proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode = else: internalAssert false -proc evalIsOp*(n: PNode): PNode = - InternalAssert n.sonsLen == 3 and - n[1].kind == nkSym and n[1].sym.kind == skType and - n[2].kind in {nkStrLit..nkTripleStrLit, nkType} - - let t1 = n[1].sym.typ - - if n[2].kind in {nkStrLit..nkTripleStrLit}: - case n[2].strVal.normalize - of "closure": - let t = skipTypes(t1, abstractRange) - result = newIntNode(nkIntLit, ord(t.kind == tyProc and - t.callConv == ccClosure and - tfIterator notin t.flags)) - of "iterator": - let t = skipTypes(t1, abstractRange) - result = newIntNode(nkIntLit, ord(t.kind == tyProc and - t.callConv == ccClosure and - tfIterator in t.flags)) - else: - let t2 = n[2].typ - var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1) - else: sameType(t1, t2) - result = newIntNode(nkIntLit, ord(match)) - - result.typ = n.typ - proc expectString(n: PNode) = if n.kind notin nkStrKinds: GlobalError(n.info, errStringLiteralExpected) @@ -1038,7 +1012,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = result = evalTypeTrait(n[0], operand, c.module) of mIs: n.sons[1] = evalAux(c, n.sons[1], {}) - result = evalIsOp(n) + result = c.handleIsOperator(n) of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module) of mStaticExec: let cmd = evalAux(c, n.sons[1], {}) diff --git a/compiler/sem.nim b/compiler/sem.nim index 4396a9093..c411d8ac4 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -198,6 +198,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = #GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0])) dec(evalTemplateCounter) +proc IsOpImpl(c: PContext, n: PNode): PNode + proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, semCheck: bool = true): PNode = markUsed(n, sym) @@ -215,6 +217,9 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, else: result = symNodeFromType(c, e.typ, n.info) + c.evalContext.handleIsOperator = proc (n: PNode): PNode = + result = IsOpImpl(c, n) + result = evalMacroCall(c.evalContext, n, nOrig, sym) if semCheck: result = semAfterMacroCall(c, result, sym) @@ -250,6 +255,7 @@ proc myOpen(module: PSym): PPassContext = if c.p != nil: InternalError(module.info, "sem.myOpen") c.semConstExpr = semConstExpr c.semExpr = semExpr + c.semTryExpr = tryExpr c.semOperand = semOperand c.semConstBoolExpr = semConstBoolExpr c.semOverloadedCall = semOverloadedCall diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 8b04f4af5..4c066f5fa 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -72,6 +72,7 @@ type libs*: TLinkedList # all libs used by this module semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} + semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, @@ -204,6 +205,11 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType = result = newTypeS(tyTypeDesc, c) result.addSonSkipIntLit(typ.AssertNotNil) +proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = + let typedesc = makeTypeDesc(c, typ) + let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc) + return newSymNode(sym, info) + proc newTypeS(kind: TTypeKind, c: PContext): PType = result = newType(kind, getCurrOwner()) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index ebda31501..d80a1cb5a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -295,6 +295,39 @@ proc semOf(c: PContext, n: PNode): PNode = n.typ = getSysType(tyBool) result = n +proc IsOpImpl(c: PContext, n: PNode): PNode = + InternalAssert n.sonsLen == 3 and + n[1].kind == nkSym and n[1].sym.kind == skType and + n[2].kind in {nkStrLit..nkTripleStrLit, nkType} + + let t1 = n[1].sym.typ.skipTypes({tyTypeDesc}) + + if n[2].kind in {nkStrLit..nkTripleStrLit}: + case n[2].strVal.normalize + of "closure": + let t = skipTypes(t1, abstractRange) + result = newIntNode(nkIntLit, ord(t.kind == tyProc and + t.callConv == ccClosure and + tfIterator notin t.flags)) + of "iterator": + let t = skipTypes(t1, abstractRange) + result = newIntNode(nkIntLit, ord(t.kind == tyProc and + t.callConv == ccClosure and + tfIterator in t.flags)) + else: + var match: bool + let t2 = n[2].typ + if t2.kind == tyTypeClass: + var m: TCandidate + InitCandidate(m, t2) + match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil + else: + match = sameType(t1, t2) + + result = newIntNode(nkIntLit, ord(match)) + + result.typ = n.typ + proc semIs(c: PContext, n: PNode): PNode = if sonsLen(n) != 3: LocalError(n.info, errXExpectsTwoArguments, "is") @@ -303,21 +336,21 @@ proc semIs(c: PContext, n: PNode): PNode = n.typ = getSysType(tyBool) n.sons[1] = semExprWithType(c, n[1], {efDetermineType}) - if n[1].typ.kind != tyTypeDesc: - LocalError(n[0].info, errTypeExpected) - + if n[2].kind notin {nkStrLit..nkTripleStrLit}: let t2 = semTypeNode(c, n[2], nil) n.sons[2] = newNodeIT(nkType, n[2].info, t2) - if n[1].typ.sonsLen == 0: + if n[1].typ.kind != tyTypeDesc: + n.sons[1] = makeTypeSymNode(c, n[1].typ, n[1].info) + elif n[1].typ.sonsLen == 0: # this is a typedesc variable, leave for evals return - else: - let t1 = n[1].typ.sons[0] - # BUGFIX: don't evaluate this too early: ``T is void`` - if not containsGenericType(t1): result = evalIsOp(n) - + + let t1 = n[1].typ.sons[0] + # BUGFIX: don't evaluate this too early: ``T is void`` + if not containsGenericType(t1): result = IsOpImpl(c, n) + proc semOpAux(c: PContext, n: PNode) = const flags = {efDetermineType} for i in countup(1, n.sonsLen-1): diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index b02fa7c31..e9541997f 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -871,6 +871,21 @@ proc freshType(res, prev: PType): PType {.inline.} = else: result = res +proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = + # if n.sonsLen == 0: return newConstraint(c, tyTypeClass) + result = newOrPrevType(tyTypeClass, prev, c) + result.testeeName = considerAcc(n[0]) + result.n = n[3] + + let + pragmas = n[1] + inherited = n[2] + + if inherited.kind != nkEmpty: + for n in inherited.sons: + let typ = semTypeNode(c, n, nil) + result.sons.safeAdd(typ) + proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = nil if gCmd == cmdIdeTools: suggestExpr(c, n) @@ -973,6 +988,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyError, prev, c) of nkObjectTy: result = semObjectNode(c, n, prev) of nkTupleTy: result = semTuple(c, n, prev) + of nkTypeClassTy: result = semTypeClass(c, n, prev) of nkRefTy: result = semAnyRef(c, n, tyRef, prev) of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev) of nkVarTy: result = semVarType(c, n, prev) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 5766aa164..25d0d8004 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -40,7 +40,9 @@ type # be instantiated typedescMatched: bool inheritancePenalty: int # to prefer closest father object type - + errors*: seq[string] # additional clarifications to be displayed to the + # user if overload resolution fails + TTypeRelation* = enum # order is important! isNone, isConvertible, isIntConv, @@ -750,11 +752,55 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, result.typ = getInstantiatedType(c, arg, m, base(f)) m.baseTypeMatch = true +proc matchUserTypeClass*(c: PContext, m: var TCandidate, + arg: PNode, f, a: PType): PNode = + if f.n == nil: + let r = typeRel(m, f, a) + return if r == isGeneric: arg else: nil + + var prev = PType(idTableGet(m.bindings, f)) + if prev != nil: + if sameType(prev, a): return arg + else: return nil + + # pushInfoContext(arg.info) + openScope(c) + + var testee = newSym(skParam, f.testeeName, f.sym, f.sym.info) + testee.typ = a + addDecl(c, testee) + + for stmt in f.n: + var e = c.semTryExpr(c, copyTree(stmt)) + if e == nil: + let expStr = renderTree(stmt, {renderNoComments}) + m.errors.safeAdd("can't compile " & expStr & " for " & a.typeToString) + return nil + case e.kind + of nkReturnStmt: + nil + of nkTypeSection: nil + of nkConstDef: nil + else: + if e.typ.kind == tyBool: + let verdict = c.semConstExpr(c, e) + if verdict.intVal == 0: + let expStr = renderTree(stmt, {renderNoComments}) + m.errors.safeAdd(expStr & " doesn't hold for " & a.typeToString) + return nil + + closeScope(c) + + result = arg + put(m.bindings, f, a) + proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, - arg, argOrig: PNode): PNode = + argSemantized, argOrig: PNode): PNode = + var arg = argSemantized var r: TTypeRelation let fMaybeExpr = f.skipTypes({tyDistinct}) - if fMaybeExpr.kind == tyExpr: + case fMaybeExpr.kind + of tyExpr: if fMaybeExpr.sonsLen == 0: r = isGeneric else: @@ -776,6 +822,16 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, if r == isGeneric: put(m.bindings, f, arg.typ) + of tyTypeClass: + if fMaybeExpr.n != nil: + let match = matchUserTypeClass(c, m, arg, fMaybeExpr, a) + if match != nil: + r = isGeneric + arg = match + else: + r = isNone + else: + r = typeRel(m, f, a) else: r = typeRel(m, f, a) |