From 9a3963f51b6e5ed25befa766270b1bbf5155e090 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 4 Sep 2014 23:50:00 +0300 Subject: [PATCH 1/2] fix #959 Variable declarations using a type class will be subject to type inference similar to the one already present in type coercions and the return type inference. --- compiler/semstmts.nim | 11 ++++++++--- doc/manual.txt | 11 ++++++++--- tests/metatype/typeclassinference.nim | 11 +++++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 28d062392e..93a1994a72 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -350,9 +350,14 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var def: PNode if a.sons[length-1].kind != nkEmpty: def = semExprWithType(c, a.sons[length-1], {efAllowDestructor}) - # BUGFIX: ``fitNode`` is needed here! - # check type compability between def.typ and typ: - if typ != nil: def = fitNode(c, typ, def) + if typ != nil: + if typ.isMetaType: + def = inferWithMetaType(c, typ, def) + typ = def.typ + else: + # BUGFIX: ``fitNode`` is needed here! + # check type compability between def.typ and typ + def = fitNode(c, typ, def) else: typ = skipIntLit(def.typ) if typ.kind in {tySequence, tyArray, tySet} and diff --git a/doc/manual.txt b/doc/manual.txt index 10fe783362..144a3b2c08 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -3671,8 +3671,8 @@ once for each tested type and any static code included within them will also be executed once. -Return Type Inference ---------------------- +Type inference with type classes +-------------------------------- If a type class is used as the return type of a proc and it won't be bound to a concrete type by some of the proc params, Nim will infer the return type @@ -3681,13 +3681,18 @@ from the proc body. This is usually used with the ``auto`` type class: .. code-block:: nim proc makePair(a, b): auto = (first: a, second: b) -The return type will be treated as additional generic param and can be +The return type will be treated as an additional generic param and can be explicitly specified at call sites as any other generic param. Future versions of Nim may also support overloading based on the return type of the overloads. In such settings, the expected result type at call sites may also influence the inferred return type. +Likewise, if a type class is used in another position where Nim expects a +concrete type (e.g. a variable declaration or a type coercion), Nim will try to +infer the concrete type by applying the sane matching algorithm also used in +overload resolution. + Symbol lookup in generics ------------------------- diff --git a/tests/metatype/typeclassinference.nim b/tests/metatype/typeclassinference.nim index 72b5aca961..2ac037ac5f 100644 --- a/tests/metatype/typeclassinference.nim +++ b/tests/metatype/typeclassinference.nim @@ -1,3 +1,8 @@ +discard """ + errormsg: "type mismatch: got (string) but expected 'ptr'" + line: 20 +""" + import typetraits type @@ -8,3 +13,9 @@ var x = Vec([1, 2, 3]) static: assert x.type.name == "Vec[static[int](3), int]" +var str1: string = "hello, world!" +var ptr1: ptr = addr(str1) + +var str2: string = "hello, world!" +var ptr2: ptr = str2 + From 7d5e387a488200113664a3ffa60e5c63ec32c54b Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 5 Sep 2014 01:02:46 +0300 Subject: [PATCH 2/2] mostly fixes #1339 The compiler hangs were caused by the interaction of tyError and the instantiation caches. For procs, the cache wasn't able to find previously compiled proc featuring tyError in the signature. For types, the unresolved type parameters leading to tyError were not replaced everywhere leading to endless replaceTypeVarsT recursion for cyclic types. The fix is still not perfect, because the handling of tyError in other places in the compiler doesn't seem to be complete and the first test case now results in internal error (still, much better than a hang blocking your IDE). --- compiler/semtypinst.nim | 8 ++++++-- compiler/types.nim | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 9484bbe908..4563dc8d40 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -216,12 +216,16 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = result.typ = replaceTypeVarsT(cl, s.typ) result.ast = replaceTypeVarsN(cl, s.ast) -proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType = +proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = result = PType(idTableGet(cl.typeMap, t)) if result == nil: if cl.allowMetaTypes or tfRetType in t.flags: return localError(t.sym.info, errCannotInstantiateX, typeToString(t)) result = errorType(cl.c) + # In order to prevent endless recursions, we must remember + # this bad lookup and replace it with errorType everywhere. + # These code paths are only active in nimrod check + idTablePut(cl.typeMap, t, result) elif result.kind == tyGenericParam and not cl.allowMetaTypes: internalError(cl.info, "substitution with generic parameter") @@ -353,7 +357,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = of tyGenericBody: localError(cl.info, errCannotInstantiateX, typeToString(t)) - result = t + result = errorType(cl.c) #result = replaceTypeVarsT(cl, lastSon(t)) of tyFromExpr: diff --git a/compiler/types.nim b/compiler/types.nim index adc03a13e2..7b59fbf200 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -913,9 +913,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = sameTypeAux(a.sons[0], b.sons[0], c) else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b) - of tyEnum, tyForward, tyProxy: + of tyEnum, tyForward: # XXX generic enums do not make much sense, but require structural checking result = a.id == b.id and sameFlags(a, b) + of tyError: + result = b.kind == tyError of tyTuple: cycleCheck() result = sameTuple(a, b, c) and sameFlags(a, b)