mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-01 10:52:14 +00:00
expr params implemented for procs; paving the way for type classes
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#
|
||||
|
||||
# This module implements the instantiation of generic procs.
|
||||
# included from sem.nim
|
||||
|
||||
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
entry: var TInstantiatedSymbol) =
|
||||
@@ -106,6 +107,35 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||
s.ast.sons[genericParamsPos].kind == nkEmpty:
|
||||
c.threadEntries.add(s)
|
||||
|
||||
template nimdbg: expr = c.filename.endsWith"nimdbg.nim"
|
||||
|
||||
proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType =
|
||||
# XXX: This is intended to replace the use of semParamList in generateInstance.
|
||||
# The results of semParamList's analysis are already encoded in the original
|
||||
# proc type and any concrete types may be aplied directly over it.
|
||||
# Besides being more efficient, it will remove the awkward case of
|
||||
# genericParams == nil in semParamList.
|
||||
# Currenly, it fails in some cases such as:
|
||||
# proc inc2*[T](x: var ordinal[T], y = 1) {.magic: "Inc", noSideEffect.}
|
||||
let sig = genericProc.typ
|
||||
result = copyType(sig, getCurrOwner(), false)
|
||||
result.n = sig.n.shallowCopy
|
||||
|
||||
for i in countup(0, sig.len - 1):
|
||||
let tOrig = sig.sons[i]
|
||||
if tOrig == nil: continue
|
||||
let oGenParams = genericProc.ast.sons[genericParamsPos]
|
||||
if skipTypes(tOrig, skipPtrs).kind in {tyGenericParam}:
|
||||
var tConcrete = concTypes[tOrig.sym.position]
|
||||
if i > 0:
|
||||
let param = sig.n.sons[i].sym.copySym
|
||||
param.typ = tConcrete
|
||||
result.n.sons[i] = newSymNode(param)
|
||||
result.sons[i] = tConcrete
|
||||
else:
|
||||
result.sons[i] = tOrig
|
||||
if i > 0: result.n.sons[i] = sig.n.sons[i]
|
||||
|
||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
info: TLineInfo): PSym =
|
||||
# generates an instantiated proc
|
||||
@@ -133,12 +163,14 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry)
|
||||
n.sons[genericParamsPos] = ast.emptyNode
|
||||
# semantic checking for the parameters:
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
removeDefaultParamValues(n.sons[ParamsPos])
|
||||
semParamList(c, n.sons[ParamsPos], nil, result)
|
||||
# XXX: obsoleted - happens in semParamList #
|
||||
# addParams(c, result.typ.n)
|
||||
else:
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
if false and nimdbg:
|
||||
result.typ = applyConcreteTypesToSig(fn, entry.concreteTypes)
|
||||
addParams(c, result.typ.n, fn.kind)
|
||||
else:
|
||||
removeDefaultParamValues(n.sons[ParamsPos])
|
||||
semParamList(c, n.sons[ParamsPos], nil, result)
|
||||
else:
|
||||
result.typ = newTypeS(tyProc, c)
|
||||
addSon(result.typ, nil)
|
||||
result.typ.callConv = fn.typ.callConv
|
||||
|
||||
@@ -641,8 +641,6 @@ proc semLambda(c: PContext, n: PNode): PNode =
|
||||
illFormedAst(n) # process parameters:
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
semParamList(c, n.sons[ParamsPos], nil, s)
|
||||
# XXX: obsoleted - happens in semParamList
|
||||
# addParams(c, s.typ.n)
|
||||
ParamsTypeCheck(c, s.typ)
|
||||
else:
|
||||
s.typ = newTypeS(tyProc, c)
|
||||
@@ -690,7 +688,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
# we have a list of implicit type parameters:
|
||||
n.sons[genericParamsPos] = gp
|
||||
# check for semantics again:
|
||||
semParamList(c, n.sons[ParamsPos], nil, s)
|
||||
# semParamList(c, n.sons[ParamsPos], nil, s)
|
||||
else:
|
||||
s.typ = newTypeS(tyProc, c)
|
||||
addSon(s.typ, nil)
|
||||
|
||||
@@ -520,6 +520,9 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
||||
else:
|
||||
addDecl(c, param)
|
||||
|
||||
proc isTypeClass(c: PContext, t: PType): bool =
|
||||
return t.kind in {tyExpr}
|
||||
|
||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
prev: PType, kind: TSymKind): PType =
|
||||
var
|
||||
@@ -536,7 +539,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
addSon(result.n, res)
|
||||
var check = initIntSet()
|
||||
var counter = 0
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
for i in countup(1, n.len - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind != nkIdentDefs: IllFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
@@ -569,6 +572,21 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
for j in countup(0, length-3):
|
||||
var arg = newSymS(skParam, a.sons[j], c)
|
||||
arg.typ = typ
|
||||
if kind notin {skTemplate, skMacro} and isTypeClass(c, typ):
|
||||
let typeClassParamId = getIdent(":tcls_" & $i & "_" & $j)
|
||||
if genericParams == nil:
|
||||
# genericParams is nil when the proc is being instantiated
|
||||
# the resolved type will be in scope then
|
||||
var s = SymtabGet(c.tab, typeClassParamId)
|
||||
arg.typ = s.typ
|
||||
else:
|
||||
var s = newSym(skType, typeClassParamId, getCurrOwner())
|
||||
s.typ = newTypeS(tyGenericParam, c)
|
||||
s.typ.sym = s
|
||||
s.position = genericParams.len
|
||||
genericParams.addSon(newSymNode(s))
|
||||
arg.typ = s.typ
|
||||
|
||||
arg.position = counter
|
||||
inc(counter)
|
||||
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
||||
@@ -831,10 +849,14 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||
s = newSymS(skType, a.sons[j], c)
|
||||
s.typ = newTypeS(tyGenericParam, c)
|
||||
of tyExpr:
|
||||
echo "GENERIC EXPR ", a.info.toFileLineCol
|
||||
# not a type param, but an expression
|
||||
# proc foo[x: expr](bar: int) what is this?
|
||||
s = newSymS(skGenericParam, a.sons[j], c)
|
||||
s.typ = typ
|
||||
else:
|
||||
# This handles cases like proc foo[t: tuple]
|
||||
# XXX: we want to turn that into a type class
|
||||
s = newSymS(skType, a.sons[j], c)
|
||||
s.typ = typ
|
||||
if def.kind != nkEmpty: s.ast = def
|
||||
|
||||
@@ -463,14 +463,8 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
result = isGeneric
|
||||
else:
|
||||
result = typeRel(mapping, x, a) # check if it fits
|
||||
of tyExpr, tyStmt, tyTypeDesc:
|
||||
if a.kind == f.kind:
|
||||
result = isEqual
|
||||
else:
|
||||
case a.kind
|
||||
of tyExpr, tyStmt, tyTypeDesc: result = isGeneric
|
||||
of tyNil: result = isSubtype
|
||||
else: nil
|
||||
of tyExpr, tyStmt, tyTypeDesc:
|
||||
result = isGeneric
|
||||
else: internalError("typeRel(" & $f.kind & ')')
|
||||
|
||||
proc cmpTypes*(f, a: PType): TTypeRelation =
|
||||
@@ -514,9 +508,6 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
|
||||
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||
arg, argOrig: PNode): PNode =
|
||||
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate} and
|
||||
f.kind in {tyExpr, tyStmt, tyTypeDesc}:
|
||||
return argOrig
|
||||
var r = typeRel(m.bindings, f, a)
|
||||
case r
|
||||
of isConvertible:
|
||||
@@ -528,14 +519,17 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||
of isSubtype:
|
||||
inc(m.subtypeMatches)
|
||||
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
|
||||
of isGeneric:
|
||||
of isGeneric:
|
||||
inc(m.genericMatches)
|
||||
result = copyTree(arg)
|
||||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
# BUG: f may not be the right key!
|
||||
if skipTypes(result.typ, abstractVar).kind in {tyTuple}:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
# BUGFIX: use ``result.typ`` and not `f` here
|
||||
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
|
||||
result = argOrig
|
||||
else:
|
||||
result = copyTree(arg)
|
||||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
# BUG: f may not be the right key!
|
||||
if skipTypes(result.typ, abstractVar).kind in {tyTuple}:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
# BUGFIX: use ``result.typ`` and not `f` here
|
||||
of isEqual:
|
||||
inc(m.exactMatches)
|
||||
result = copyTree(arg)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
import uclosures, utemplates
|
||||
import uclosures, utemplates, uexpr
|
||||
|
||||
|
||||
13
tests/run/uexpr.nim
Normal file
13
tests/run/uexpr.nim
Normal file
@@ -0,0 +1,13 @@
|
||||
import unittest
|
||||
|
||||
proc concat(a, b): string =
|
||||
result = $a & $b
|
||||
|
||||
test "if proc param types are not supplied, the params are assumed to be generic":
|
||||
check concat(1, "test") == "1test"
|
||||
check concat(1, 20) == "120"
|
||||
check concat("foo", "bar") == "foobar"
|
||||
|
||||
test "explicit param types can still be specified":
|
||||
check concat[cstring, cstring]("x", "y") == "xy"
|
||||
|
||||
Reference in New Issue
Block a user