implicit generics types as return types. removed the error message for capturing incorrect uses of `proc`
This commit is contained in:
parent
2f4ae65917
commit
251c44ff04
6 changed files with 67 additions and 60 deletions
|
|
@ -190,7 +190,11 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
# This is a typedesc param. is it already bound?
|
# This is a typedesc param. is it already bound?
|
||||||
# it's not bound when it's also used as return type for example
|
# it's not bound when it's also used as return type for example
|
||||||
if result.typ.sonsLen > 0:
|
if result.typ.sonsLen > 0:
|
||||||
return result.typ.sons[0].sym
|
let bound = result.typ.sons[0].sym
|
||||||
|
if bound != nil:
|
||||||
|
return bound
|
||||||
|
else:
|
||||||
|
return result.typ.sym
|
||||||
else:
|
else:
|
||||||
return result.typ.sym
|
return result.typ.sym
|
||||||
if result.kind != skType: GlobalError(n.info, errTypeExpected)
|
if result.kind != skType: GlobalError(n.info, errTypeExpected)
|
||||||
|
|
@ -536,6 +540,36 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
|
||||||
result.typ = copyType(paramType, getCurrOwner(), false)
|
result.typ = copyType(paramType, getCurrOwner(), false)
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
|
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
|
paramType: PType, paramName: string): PType =
|
||||||
|
## Params having implicit generic types or pseudo types such as 'expr'
|
||||||
|
## need to be added to the generic params lists.
|
||||||
|
## 'expr' is different from 'expr{string}' so we must first call
|
||||||
|
## paramTypeClass to get the actual type we are going to use.
|
||||||
|
result = paramType
|
||||||
|
var (typeClass, paramTypId) = paramTypeClass(c, paramType, procKind)
|
||||||
|
let isAnon = paramTypId == nil
|
||||||
|
if typeClass != nil:
|
||||||
|
if isAnon: paramTypId = getIdent(paramName & ":type")
|
||||||
|
if genericParams == nil:
|
||||||
|
# genericParams is nil when the proc is being instantiated
|
||||||
|
# the resolved type will be in scope then
|
||||||
|
result = SymtabGet(c.tab, paramTypId).AssertNotNil.typ
|
||||||
|
else:
|
||||||
|
block addImplicitGeneric:
|
||||||
|
# is this a bindOnce type class already present in the param list?
|
||||||
|
for i in countup(0, genericParams.len - 1):
|
||||||
|
if genericParams.sons[i].sym.name == paramTypId:
|
||||||
|
result = genericParams.sons[i].typ
|
||||||
|
break addImplicitGeneric
|
||||||
|
|
||||||
|
var s = newSym(skType, paramTypId, getCurrOwner())
|
||||||
|
if isAnon: s.flags.incl(sfAnon)
|
||||||
|
s.linkTo(typeClass)
|
||||||
|
s.position = genericParams.len
|
||||||
|
genericParams.addSon(newSymNode(s))
|
||||||
|
result = typeClass
|
||||||
|
|
||||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
prev: PType, kind: TSymKind): PType =
|
prev: PType, kind: TSymKind): PType =
|
||||||
var
|
var
|
||||||
|
|
@ -583,37 +617,15 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
var arg = newSymS(skParam, a.sons[j], c)
|
var arg = newSymS(skParam, a.sons[j], c)
|
||||||
var endingType = typ
|
var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s)
|
||||||
var (typeClass, paramTypId) = paramTypeClass(c, typ, kind)
|
arg.typ = finalType
|
||||||
if typeClass != nil:
|
|
||||||
if paramTypId == nil: paramTypId = getIdent(arg.name.s & ":type")
|
|
||||||
if genericParams == nil:
|
|
||||||
# genericParams is nil when the proc is being instantiated
|
|
||||||
# the resolved type will be in scope then
|
|
||||||
endingType = SymtabGet(c.tab, paramTypId).AssertNotNil.typ
|
|
||||||
else:
|
|
||||||
block addImplicitGeneric:
|
|
||||||
# is this a bindOnce type class already present in the param list?
|
|
||||||
for i in countup(0, genericParams.len - 1):
|
|
||||||
if genericParams.sons[i].sym.name == paramTypId:
|
|
||||||
endingType = genericParams.sons[i].typ
|
|
||||||
break addImplicitGeneric
|
|
||||||
|
|
||||||
var s = newSym(skType, paramTypId, getCurrOwner())
|
|
||||||
s.flags.incl(sfAnon)
|
|
||||||
s.linkTo(typeClass)
|
|
||||||
s.position = genericParams.len
|
|
||||||
genericParams.addSon(newSymNode(s))
|
|
||||||
endingType = typeClass
|
|
||||||
|
|
||||||
arg.typ = endingType
|
|
||||||
arg.position = counter
|
arg.position = counter
|
||||||
inc(counter)
|
inc(counter)
|
||||||
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
||||||
if ContainsOrIncl(check, arg.name.id):
|
if ContainsOrIncl(check, arg.name.id):
|
||||||
LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
|
LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
|
||||||
addSon(result.n, newSymNode(arg))
|
addSon(result.n, newSymNode(arg))
|
||||||
addSon(result, endingType)
|
addSon(result, finalType)
|
||||||
addParamOrResult(c, arg, kind)
|
addParamOrResult(c, arg, kind)
|
||||||
|
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
|
|
@ -621,6 +633,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
# turn explicit 'void' return type into 'nil' because the rest of the
|
# turn explicit 'void' return type into 'nil' because the rest of the
|
||||||
# compiler only checks for 'nil':
|
# compiler only checks for 'nil':
|
||||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||||
|
if r.sym == nil or sfAnon notin r.sym.flags:
|
||||||
|
r = liftParamType(c, kind, genericParams, r, "result")
|
||||||
result.sons[0] = r
|
result.sons[0] = r
|
||||||
res.typ = result.sons[0]
|
res.typ = result.sons[0]
|
||||||
|
|
||||||
|
|
@ -778,6 +792,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of nkVarTy: result = semVarType(c, n, prev)
|
of nkVarTy: result = semVarType(c, n, prev)
|
||||||
of nkDistinctTy: result = semDistinct(c, n, prev)
|
of nkDistinctTy: result = semDistinct(c, n, prev)
|
||||||
of nkProcTy:
|
of nkProcTy:
|
||||||
|
if n.sonsLen == 0: return newConstraint(c, tyProc)
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
openScope(c.tab)
|
openScope(c.tab)
|
||||||
result = semProcTypeNode(c, n.sons[0], nil, prev, skProc)
|
result = semProcTypeNode(c, n.sons[0], nil, prev, skProc)
|
||||||
|
|
@ -785,7 +800,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c)
|
var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c)
|
||||||
s.typ = result
|
s.typ = result
|
||||||
pragma(c, s, n.sons[1], procTypePragmas)
|
pragma(c, s, n.sons[1], procTypePragmas)
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
of nkEnumTy: result = semEnum(c, n, prev)
|
of nkEnumTy: result = semEnum(c, n, prev)
|
||||||
of nkType: result = n.typ
|
of nkType: result = n.typ
|
||||||
of nkStmtListType: result = semStmtListType(c, n, prev)
|
of nkStmtListType: result = semStmtListType(c, n, prev)
|
||||||
|
|
@ -836,14 +851,11 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||||
else: GlobalError(m.info, errTypeExpected)
|
else: GlobalError(m.info, errTypeExpected)
|
||||||
|
|
||||||
proc semGenericConstraints(c: PContext, n: PNode, result: PType) =
|
proc semGenericConstraints(c: PContext, n: PNode, result: PType) =
|
||||||
case n.kind
|
var x = semTypeNode(c, n, nil)
|
||||||
of nkProcTy: result.addSon(newConstraint(c, tyProc))
|
if x.kind in StructuralEquivTypes and (
|
||||||
else:
|
sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
|
||||||
var x = semTypeNode(c, n, nil)
|
x = newConstraint(c, x.kind)
|
||||||
if x.kind in StructuralEquivTypes and (
|
result.addSon(x)
|
||||||
sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
|
|
||||||
x = newConstraint(c, x.kind)
|
|
||||||
result.addSon(x)
|
|
||||||
|
|
||||||
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ proc checkPartialConstructedType(info: TLineInfo, t: PType) =
|
||||||
elif t.kind == tyVar and t.sons[0].kind == tyVar:
|
elif t.kind == tyVar and t.sons[0].kind == tyVar:
|
||||||
LocalError(info, errVarVarTypeNotAllowed)
|
LocalError(info, errVarVarTypeNotAllowed)
|
||||||
|
|
||||||
proc checkConstructedType*(info: TLineInfo, t: PType) =
|
proc checkConstructedType*(info: TLineInfo, typ: PType) =
|
||||||
|
var t = typ.skipTypes({tyDistinct})
|
||||||
if t.kind in {tyTypeClass}: nil
|
if t.kind in {tyTypeClass}: nil
|
||||||
elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
|
elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
|
||||||
LocalError(info, errInvalidPragmaX, "acyclic")
|
LocalError(info, errInvalidPragmaX, "acyclic")
|
||||||
|
|
|
||||||
|
|
@ -459,33 +459,22 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||||
if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
|
if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
|
||||||
InternalError("wrong instantiated type!")
|
InternalError("wrong instantiated type!")
|
||||||
put(mapping, f.sons[i], x)
|
put(mapping, f.sons[i], x)
|
||||||
of tyGenericParam:
|
of tyGenericParam, tyTypeClass:
|
||||||
var x = PType(idTableGet(mapping, f))
|
var x = PType(idTableGet(mapping, f))
|
||||||
if x == nil:
|
if x == nil:
|
||||||
if sonsLen(f) == 0:
|
result = matchTypeClass(mapping, f, a)
|
||||||
# no constraints
|
if result == isGeneric:
|
||||||
var concrete = concreteType(mapping, a)
|
var concrete = concreteType(mapping, a)
|
||||||
if concrete != nil:
|
if concrete == nil:
|
||||||
|
result = isNone
|
||||||
|
else:
|
||||||
put(mapping, f, concrete)
|
put(mapping, f, concrete)
|
||||||
result = isGeneric
|
elif a.kind == tyEmpty:
|
||||||
else:
|
|
||||||
# check constraints:
|
|
||||||
for i in countup(0, sonsLen(f) - 1):
|
|
||||||
if typeRel(mapping, f.sons[i], a) >= isSubtype:
|
|
||||||
var concrete = concreteType(mapping, a)
|
|
||||||
if concrete != nil:
|
|
||||||
put(mapping, f, concrete)
|
|
||||||
result = isGeneric
|
|
||||||
break
|
|
||||||
elif a.kind == tyEmpty:
|
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
elif x.kind == tyGenericParam:
|
elif x.kind == tyGenericParam:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(mapping, x, a) # check if it fits
|
result = typeRel(mapping, x, a) # check if it fits
|
||||||
of tyTypeClass:
|
|
||||||
result = matchTypeClass(mapping, f, a)
|
|
||||||
if result == isGeneric: put(mapping, f, a)
|
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
if a.kind == tyTypeDesc:
|
if a.kind == tyTypeDesc:
|
||||||
if f.sonsLen == 0:
|
if f.sonsLen == 0:
|
||||||
|
|
|
||||||
|
|
@ -1374,7 +1374,8 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
|
||||||
## `op` to every item in `data`.
|
## `op` to every item in `data`.
|
||||||
for i in 0..data.len-1: op(data[i])
|
for i in 0..data.len-1: op(data[i])
|
||||||
|
|
||||||
iterator fields*[T: tuple](x: T): expr {.magic: "Fields", noSideEffect.}
|
iterator fields*[T: tuple](x: T): TObject {.
|
||||||
|
magic: "Fields", noSideEffect.}
|
||||||
## iterates over every field of `x`. Warning: This really transforms
|
## iterates over every field of `x`. Warning: This really transforms
|
||||||
## the 'for' and unrolls the loop. The current implementation also has a bug
|
## the 'for' and unrolls the loop. The current implementation also has a bug
|
||||||
## that affects symbol binding in the loop body.
|
## that affects symbol binding in the loop body.
|
||||||
|
|
@ -1384,7 +1385,8 @@ iterator fields*[S: tuple, T: tuple](x: S, y: T): tuple[a, b: expr] {.
|
||||||
## Warning: This is really transforms the 'for' and unrolls the loop.
|
## Warning: This is really transforms the 'for' and unrolls the loop.
|
||||||
## The current implementation also has a bug that affects symbol binding
|
## The current implementation also has a bug that affects symbol binding
|
||||||
## in the loop body.
|
## in the loop body.
|
||||||
iterator fieldPairs*[T: tuple](x: T): expr {.magic: "FieldPairs", noSideEffect.}
|
iterator fieldPairs*[T: tuple](x: T): TObject {.
|
||||||
|
magic: "FieldPairs", noSideEffect.}
|
||||||
## iterates over every field of `x`. Warning: This really transforms
|
## iterates over every field of `x`. Warning: This really transforms
|
||||||
## the 'for' and unrolls the loop. The current implementation also has a bug
|
## the 'for' and unrolls the loop. The current implementation also has a bug
|
||||||
## that affects symbol binding in the loop body.
|
## that affects symbol binding in the loop body.
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ discard """
|
||||||
type TAlphabet = enum
|
type TAlphabet = enum
|
||||||
A, B, C
|
A, B, C
|
||||||
|
|
||||||
iterator items(E: typedesc): E =
|
iterator items(E: typedesc{enum}): E =
|
||||||
for v in low(E)..high(E):
|
for v in low(E)..high(E):
|
||||||
yield v
|
yield v
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,9 @@ Changes affecting backwards compatibility
|
||||||
``PNimrodNode`` which unfortunately breaks the old macro system.
|
``PNimrodNode`` which unfortunately breaks the old macro system.
|
||||||
- ``pegs.@`` has been renamed to ``pegs.!*`` and ``pegs.@@`` has been renamed
|
- ``pegs.@`` has been renamed to ``pegs.!*`` and ``pegs.@@`` has been renamed
|
||||||
to ``pegs.!*\`` as ``@`` operators now have different precedence.
|
to ``pegs.!*\`` as ``@`` operators now have different precedence.
|
||||||
|
- the type ``proc`` (without any params or return type) is now considered a
|
||||||
|
type class matching all proc types. Use ``proc ()`` to get the old meaning
|
||||||
|
denoting a proc expecing no arguments and returing no value.
|
||||||
|
|
||||||
|
|
||||||
Compiler Additions
|
Compiler Additions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue