diff options
author | Zahary Karadjov <zahary@gmail.com> | 2012-09-29 16:49:04 +0300 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2012-10-03 01:59:49 +0300 |
commit | 7e44015491d4002be3c80cb7d6797e4c63651fbe (patch) | |
tree | 6650bd361de96a9e70b75c089bf7c4521e755d9a /compiler | |
parent | b28fcdfa93ccf132b878e7dcd26e36d48f107212 (diff) | |
download | Nim-7e44015491d4002be3c80cb7d6797e4c63651fbe.tar.gz |
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)
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 2 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 16 | ||||
-rwxr-xr-x | compiler/seminst.nim | 11 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 19 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 7 | ||||
-rwxr-xr-x | compiler/types.nim | 4 |
6 files changed, 41 insertions, 18 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 814784029..c6e4d8318 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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 diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 7c147e778..4608d38ef 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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 diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 61210c0f8..8e164531a 100755 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -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() diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 5362d6d4a..eeb48a647 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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] diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 7e482b3d2..82a8c9399 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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) diff --git a/compiler/types.nim b/compiler/types.nim index d8879f1b4..b650b49b8 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -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: |