implemented return type inference
Other fixes: * bind once is now the default for type classes as documented in the manual * fixes an issue in template overloading (erroneous ambiguity when different typedesc params were used)
This commit is contained in:
parent
b28fcdfa93
commit
7e44015491
9 changed files with 104 additions and 36 deletions
|
|
@ -350,6 +350,8 @@ type
|
|||
# pass of semProcTypeNode performed after instantiation.
|
||||
# this won't be needed if we don't perform this redundant
|
||||
# second pass (stay tuned).
|
||||
tfRetType # marks return types in proc (used to detect type classes
|
||||
# used as return types for return type inference)
|
||||
tfAll, # type class requires all constraints to be met (default)
|
||||
tfAny, # type class requires any constraint to be met
|
||||
tfCapturesEnv, # whether proc really captures some environment
|
||||
|
|
|
|||
|
|
@ -1048,8 +1048,20 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
|||
localError(a.info, errXCannotBeAssignedTo,
|
||||
renderTree(a, {renderNoComments}))
|
||||
else:
|
||||
n.sons[1] = semExprWithType(c, n.sons[1])
|
||||
n.sons[1] = fitNode(c, le, n.sons[1])
|
||||
var
|
||||
rhs = semExprWithType(c, n.sons[1])
|
||||
lhs = n.sons[0]
|
||||
if lhs.kind == nkSym and lhs.sym.kind == skResult and
|
||||
lhs.sym.typ.kind == tyGenericParam:
|
||||
if matchTypeClass(lhs.typ, rhs.typ):
|
||||
InternalAssert c.p.resultSym != nil
|
||||
lhs.typ = rhs.typ
|
||||
c.p.resultSym.typ = rhs.typ
|
||||
c.p.owner.typ.sons[0] = rhs.typ
|
||||
else:
|
||||
typeMismatch(n, lhs.typ, rhs.typ)
|
||||
|
||||
n.sons[1] = fitNode(c, le, rhs)
|
||||
fixAbstractType(c, n)
|
||||
asgnToResultVar(c, n, n.sons[0], n.sons[1])
|
||||
result = n
|
||||
|
|
|
|||
|
|
@ -25,8 +25,13 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
|||
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
||||
var t = PType(IdTableGet(pt, q.typ))
|
||||
if t == nil:
|
||||
LocalError(a.info, errCannotInstantiateX, s.name.s)
|
||||
t = errorType(c)
|
||||
if tfRetType in q.typ.flags:
|
||||
# keep the generic type and allow the return type to be bound
|
||||
# later by semAsgn in return type inference scenario
|
||||
t = q.typ
|
||||
else:
|
||||
LocalError(a.info, errCannotInstantiateX, s.name.s)
|
||||
t = errorType(c)
|
||||
elif t.kind == tyGenericParam:
|
||||
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
|
||||
elif t.kind == tyGenericInvokation:
|
||||
|
|
@ -163,7 +168,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
result.typ = newTypeS(tyProc, c)
|
||||
rawAddSon(result.typ, nil)
|
||||
result.typ.callConv = fn.typ.callConv
|
||||
ParamsTypeCheck(c, result.typ)
|
||||
var oldPrc = GenericCacheGet(c, entry)
|
||||
if oldPrc == nil:
|
||||
c.generics.generics.add(entry)
|
||||
|
|
@ -174,6 +178,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
if fn.kind != skTemplate:
|
||||
instantiateBody(c, n, result)
|
||||
sideEffectsCheck(c, result)
|
||||
ParamsTypeCheck(c, result.typ)
|
||||
else:
|
||||
result = oldPrc
|
||||
popInfoContext()
|
||||
|
|
|
|||
|
|
@ -584,22 +584,20 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
|
|||
result.typ = newTypeS(tyTypeDesc, c)
|
||||
result.typ.sons = paramType.sons
|
||||
of tyDistinct:
|
||||
# type T1 = distinct expr
|
||||
# type S1 = distinct Sortable
|
||||
# proc x(a, b: T1, c, d: S1)
|
||||
# This forces bindOnce behavior for the type class, equivalent to
|
||||
# proc x[T, S](a, b: T, c, d: S)
|
||||
result = paramTypeClass(c, paramType.lastSon, procKind)
|
||||
result.id = paramType.sym.name
|
||||
# disable the bindOnce behavior for the type class
|
||||
result.id = nil
|
||||
return
|
||||
of tyGenericBody:
|
||||
# type Foo[T] = object
|
||||
# proc x(a: Foo, b: Foo)
|
||||
result.typ = newTypeS(tyTypeClass, c)
|
||||
result.typ.addSonSkipIntLit(paramType)
|
||||
result.id = paramType.sym.name # bindOnce by default
|
||||
of tyTypeClass:
|
||||
result.typ = copyType(paramType, getCurrOwner(), false)
|
||||
else: nil
|
||||
# bindOnce by default
|
||||
if paramType.sym != nil: result.id = paramType.sym.name
|
||||
|
||||
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
paramType: PType, paramName: string,
|
||||
|
|
@ -619,7 +617,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
let s = SymtabGet(c.tab, paramTypId)
|
||||
# tests/run/tinterf triggers this:
|
||||
if s != nil: result = s.typ
|
||||
else:
|
||||
else:
|
||||
LocalError(info, errCannotInstantiateX, paramName)
|
||||
result = errorType(c)
|
||||
else:
|
||||
|
|
@ -684,8 +682,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
||||
for j in countup(0, length-3):
|
||||
var arg = newSymG(skParam, a.sons[j], c)
|
||||
var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s,
|
||||
arg.info).skipIntLit
|
||||
var finalType = liftParamType(c, kind, genericParams, typ,
|
||||
arg.name.s, arg.info).skipIntLit
|
||||
arg.typ = finalType
|
||||
arg.position = counter
|
||||
inc(counter)
|
||||
|
|
@ -703,6 +701,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||
if r.sym == nil or sfAnon notin r.sym.flags:
|
||||
r = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info)
|
||||
r.flags.incl tfRetType
|
||||
result.sons[0] = skipIntLit(r)
|
||||
res.typ = result.sons[0]
|
||||
|
||||
|
|
|
|||
|
|
@ -282,7 +282,12 @@ proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation =
|
|||
# if the loop finished without returning, either all constraints matched
|
||||
# or none of them matched.
|
||||
result = if tfAny in typeClass.flags: isNone else: isGeneric
|
||||
|
||||
|
||||
proc matchTypeClass*(typeClass, typ: PType): bool =
|
||||
var c: TCandidate
|
||||
InitCandidate(c, typeClass)
|
||||
result = matchTypeClass(c, typeClass, typ) == isGeneric
|
||||
|
||||
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
||||
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
|
||||
|
|
|
|||
|
|
@ -626,9 +626,9 @@ proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
|
|||
var c = initSameTypeClosure()
|
||||
c.flags = flags
|
||||
result = SameTypeAux(a, b, c)
|
||||
|
||||
|
||||
proc equalParam(a, b: PSym): TParamsEquality =
|
||||
if SameTypeOrNil(a.typ, b.typ):
|
||||
if SameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}):
|
||||
if a.ast == b.ast:
|
||||
result = paramsEqual
|
||||
elif a.ast != nil and b.ast != nil:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue