diff options
author | Araq <rumpf_a@web.de> | 2012-12-06 07:10:19 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-12-06 07:10:19 +0100 |
commit | 1d842e8b75aa95670386b2ac4613932d2e01b9a3 (patch) | |
tree | 0c664c8676a53cbeb709d8a1377cac8906492932 /compiler | |
parent | b602c04c4adc803b432e360d33cf54dad0b02def (diff) | |
parent | 6431e602160a5f2e1323a057e9c0166431e5a002 (diff) | |
download | Nim-1d842e8b75aa95670386b2ac4613932d2e01b9a3.tar.gz |
Merge branch 'master' of github.com:Araq/Nimrod
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 2 | ||||
-rwxr-xr-x | compiler/docgen.nim | 3 | ||||
-rw-r--r-- | compiler/parampatterns.nim | 4 | ||||
-rw-r--r-- | compiler/patterns.nim | 4 | ||||
-rwxr-xr-x | compiler/rodread.nim | 6 | ||||
-rwxr-xr-x | compiler/rodwrite.nim | 6 | ||||
-rwxr-xr-x | compiler/semcall.nim | 12 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 4 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 27 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 25 |
10 files changed, 66 insertions, 27 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index f4ba1ef70..82a20c312 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -624,6 +624,7 @@ type loc*: TLoc annex*: PLib # additional fields (seldom used, so we use a # reference to another object to safe space) + constraint*: PNode # additional constraints like 'lit|result' TTypeSeq* = seq[PType] TType* = object of TIdObj # types are identical iff they have the @@ -650,7 +651,6 @@ type align*: int # the type's alignment requirements containerID*: int # used for type checking of generics loc*: TLoc - constraint*: PNode # additional constraints like 'lit|result' TPair*{.final.} = object key*, val*: PObject diff --git a/compiler/docgen.nim b/compiler/docgen.nim index e06277f91..aff77cc1f 100755 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -145,6 +145,9 @@ proc isVisible(n: PNode): bool = var v = n.sons[0].ident result = v.id == ord(wStar) or v.id == ord(wMinus) elif n.kind == nkSym: + # we cannot generate code for forwarded symbols here as we have no + # exception tracking information here. Instead we copy over the comment + # from the proc header. result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported} elif n.kind == nkPragmaExpr: result = isVisible(n.sons[0]) diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index ee1f69818..21c7faf19 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -48,8 +48,8 @@ proc add(code: var TPatternCode, op: TOpcode) {.inline.} = add(code, chr(ord(op))) proc whichAlias*(p: PSym): TAliasRequest = - if p.typ.constraint != nil: - result = TAliasRequest(p.typ.constraint.strVal[0].ord) + if p.constraint != nil: + result = TAliasRequest(p.constraint.strVal[0].ord) proc compileConstraints(p: PNode, result: var TPatternCode) = case p.kind diff --git a/compiler/patterns.nim b/compiler/patterns.nim index af259c916..b7792100f 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -71,8 +71,8 @@ proc inSymChoice(sc, x: PNode): bool = proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool = # check param constraints first here as this is quite optimized: - if p.typ.constraint != nil: - result = matchNodeKinds(p.typ.constraint, n) + if p.constraint != nil: + result = matchNodeKinds(p.constraint, n) if not result: return if isNil(n.typ): result = p.typ.kind in {tyEmpty, tyStmt} diff --git a/compiler/rodread.nim b/compiler/rodread.nim index 4461641db..722887299 100755 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -330,9 +330,6 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType = if r.s[r.pos] == '@': inc(r.pos) result.containerID = decodeVInt(r.s, r.pos) - if r.s[r.pos] == '`': - inc(r.pos) - result.constraint = decodeNode(r, UnknownLineInfo()) decodeLoc(r, result.loc, info) while r.s[r.pos] == '^': inc(r.pos) @@ -423,6 +420,9 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym = result.offset = - 1 decodeLoc(r, result.loc, result.info) result.annex = decodeLib(r, info) + if r.s[r.pos] == '#': + inc(r.pos) + result.constraint = decodeNode(r, UnknownLineInfo()) if r.s[r.pos] == '(': if result.kind in routineKinds: result.ast = decodeNodeLazyBody(r, result.info, result) diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 5be9a2439..0a361d4dd 100755 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -233,9 +233,6 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) = if t.containerID != 0: add(result, '@') encodeVInt(t.containerID, result) - if t.constraint != nil: - add(result, '`') - encodeNode(w, UnknownLineInfo(), t.constraint, result) encodeLoc(w, t.loc, result) for i in countup(0, sonsLen(t) - 1): if t.sons[i] == nil: @@ -295,6 +292,9 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) = encodeVInt(s.offset, result) encodeLoc(w, s.loc, result) if s.annex != nil: encodeLib(w, s.annex, s.info, result) + if s.constraint != nil: + add(result, '#') + encodeNode(w, UnknownLineInfo(), s.constraint, result) # lazy loading will soon reload the ast lazily, so the ast needs to be # the last entry of a symbol: if s.ast != nil: diff --git a/compiler/semcall.nim b/compiler/semcall.nim index a5107bf64..962e4d3cc 100755 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -84,6 +84,16 @@ proc resolveOverloads(c: PContext, n, orig: PNode, getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym), args]) +proc instantiateGenericConverters(c: PContext, n: PNode, x: TCandidate) {. + noinline.}= + for i in 1 .. <n.len: + var a = n.sons[i] + if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym and + isGenericRoutine(a.sons[0].sym): + let finalCallee = generateInstance(c, a.sons[0].sym, x.bindings, n.info) + a.sons[0].sym = finalCallee + a.sons[0].typ = finalCallee.typ + proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = assert x.state == csMatch var finalCallee = x.calleeSym @@ -101,6 +111,8 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = if ContainsGenericType(result.typ): result.typ = errorType(c) return result = x.call + if x.genericConverter: + instantiateGenericConverters(c, result, x) result.sons[0] = newSymNode(finalCallee, result.sons[0].info) result.typ = finalCallee.typ.sons[0] diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d68d0da1a..68d485f48 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -780,6 +780,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, n.sons[pragmasPos] = proto.ast.sons[pragmasPos] if n.sons[namePos].kind != nkSym: InternalError(n.info, "semProcAux") n.sons[namePos].sym = proto + if gCmd == cmdDoc and not isNil(proto.ast.comment): + n.comment = proto.ast.comment proto.ast = n # needed for code generation popOwner() pushOwner(s) @@ -869,8 +871,6 @@ proc semMethod(c: PContext, n: PNode): PNode = proc semConverterDef(c: PContext, n: PNode): PNode = if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter") checkSonsLen(n, bodyPos + 1) - if n.sons[genericParamsPos].kind != nkEmpty: - LocalError(n.info, errNoGenericParamsAllowedForX, "converter") result = semProcAux(c, n, skConverter, converterPragmas) var s = result.sons[namePos].sym var t = s.typ diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 9efeba5b7..3da2a95b7 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -635,6 +635,13 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, genericParams.addSon(newSymNode(s)) result = typeClass +proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType = + if n.kind == nkCurlyExpr: + result = semTypeNode(c, n.sons[0], nil) + constraint = semNodeKindConstraints(n) + else: + result = semTypeNode(c, n, nil) + proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType, kind: TSymKind): PType = var @@ -660,13 +667,14 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, checkMinSonsLen(a, 3) var typ: PType = nil - def: PNode = nil + def: PNode = nil + constraint: PNode = nil length = sonsLen(a) hasType = a.sons[length-2].kind != nkEmpty hasDefault = a.sons[length-1].kind != nkEmpty if hasType: - typ = semTypeNode(c, a.sons[length-2], nil) + typ = semParamType(c, a.sons[length-2], constraint) if hasDefault: def = semExprWithType(c, a.sons[length-1]) @@ -689,6 +697,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, arg.name.s, arg.info).skipIntLit arg.typ = finalType arg.position = counter + arg.constraint = constraint inc(counter) if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def) if ContainsOrIncl(check, arg.name.id): @@ -787,6 +796,12 @@ proc semTypeExpr(c: PContext, n: PNode): PType = else: LocalError(n.info, errTypeExpected, n.renderTree) +proc freshType(res, prev: PType): PType {.inline.} = + if prev.isNil: + result = copyType(result, result.owner, keepId=false) + else: + result = res + proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = nil if gCmd == cmdIdeTools: suggestExpr(c, n) @@ -825,7 +840,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = checkSonsLen(n, 3) result = semTypeNode(c, n.sons[1], prev) if result.kind in NilableTypes and n.sons[2].kind == nkNilLit: - # XXX this is wrong for tyString at least + result = freshType(result, prev) result.flags.incl(tfNotNil) else: LocalError(n.info, errGenerated, "invalid type") @@ -833,11 +848,6 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = semTypeExpr(c, n) else: result = semTypeExpr(c, n) - of nkCurlyExpr: - result = semTypeNode(c, n.sons[0], nil) - if result != nil: - result = copyType(result, getCurrOwner(), true) - result.constraint = semNodeKindConstraints(n) of nkWhenStmt: var whenResult = semWhen(c, n, false) if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType @@ -920,6 +930,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkSharedTy: checkSonsLen(n, 1) result = semTypeNode(c, n.sons[0], prev) + result = freshType(result, prev) result.flags.incl(tfShared) else: LocalError(n.info, errTypeExpected) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 799622355..c48434eb7 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -33,6 +33,8 @@ type baseTypeMatch: bool # needed for conversions from T to openarray[T] # for example proxyMatch*: bool # to prevent instantiations + genericConverter*: bool # true if a generic converter needs to + # be instantiated inheritancePenalty: int # to prefer closest father object type TTypeRelation* = enum # order is important! @@ -57,6 +59,7 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} = c.callee = callee c.call = nil c.baseTypeMatch = false + c.genericConverter = false c.inheritancePenalty = 0 proc initCandidate*(c: var TCandidate, callee: PType) = @@ -571,16 +574,26 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, for i in countup(0, len(c.converters) - 1): var src = c.converters[i].typ.sons[1] var dest = c.converters[i].typ.sons[0] - if (typeRel(m, f, dest) == isEqual) and - (typeRel(m, src, a) == isEqual): + # for generic type converters we need to check 'src <- a' before + # 'f <- dest' in order to not break the unification: + # see tests/tgenericconverter: + let srca = typeRel(m, src, a) + if srca notin {isEqual, isGeneric}: continue + + let destIsGeneric = containsGenericType(dest) + if destIsGeneric: + dest = generateTypeInstance(c, m.bindings, arg, dest) + let fdest = typeRel(m, f, dest) + if fdest in {isEqual, isGeneric}: markUsed(arg, c.converters[i]) var s = newSymNode(c.converters[i]) s.typ = c.converters[i].typ s.info = arg.info - result = newNodeIT(nkHiddenCallConv, arg.info, s.typ.sons[0]) + result = newNodeIT(nkHiddenCallConv, arg.info, dest) addSon(result, s) addSon(result, copyTree(arg)) inc(m.convMatches) + m.genericConverter = srca == isGeneric or destIsGeneric return proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, @@ -837,10 +850,10 @@ proc matchesAux*(c: PContext, n, nOrig: PNode, m.baseTypeMatch = false var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, n.sons[a], nOrig.sons[a]) - if arg == nil: + if arg == nil: m.state = csNoMatch - return - if m.baseTypeMatch: + return + if m.baseTypeMatch: assert(container == nil) container = newNodeI(nkBracket, n.sons[a].info) addSon(container, arg) |