diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/semexprs.nim | 20 | ||||
-rw-r--r-- | compiler/semtypes.nim | 21 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 25 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 46 |
4 files changed, 83 insertions, 29 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 8332d404d..f52de6750 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1482,20 +1482,28 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode = case t.kind - of tyTypeParamsHolders: + of tyGenericInst: result = readTypeParameter(c, t, i, n.info) if result == c.graph.emptyNode: - result = semGenericStmt(c, n) - result.typ = makeTypeFromExpr(c, result.copyTree) + if c.inGenericContext > 0: + result = semGenericStmt(c, n) + result.typ = makeTypeFromExpr(c, result.copyTree) + else: + result = nil of tyUserTypeClasses: if t.isResolvedUserTypeClass: result = readTypeParameter(c, t, i, n.info) + elif c.inGenericContext > 0: + result = semGenericStmt(c, n) + result.typ = makeTypeFromExpr(c, copyTree(result)) else: + result = nil + elif t.containsGenericType: + if c.inGenericContext > 0: result = semGenericStmt(c, n) result.typ = makeTypeFromExpr(c, copyTree(result)) - of tyFromExpr, tyGenericParam, tyAnything: - result = semGenericStmt(c, n) - result.typ = makeTypeFromExpr(c, copyTree(result)) + else: + result = nil else: result = nil diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index bdf8fb8ca..2a5b6c751 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1312,6 +1312,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, result = newProcType(c, n.info, prev) var check = initIntSet() var counter = 0 + template isCurrentlyGeneric: bool = + # genericParams might update as implicit generic params are added + genericParams != nil and genericParams.len > 0 for i in 1..<n.len: var a = n[i] @@ -1332,7 +1335,10 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, hasDefault = a[^1].kind != nkEmpty if hasType: + let isGeneric = isCurrentlyGeneric() + inc c.inGenericContext, ord(isGeneric) typ = semParamType(c, a[^2], constraint) + dec c.inGenericContext, ord(isGeneric) # TODO: Disallow typed/untyped in procs in the compiler/stdlib if kind in {skProc, skFunc} and (typ.kind == tyTyped or typ.kind == tyUntyped): if not isMagic(getCurrOwner(c)): @@ -1353,7 +1359,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, message(c.config, a.info, warnImplicitDefaultValue, msg) block determineType: var defTyp = typ - if genericParams != nil and genericParams.len > 0: + if isCurrentlyGeneric(): defTyp = nil def = semGenericStmt(c, def) if hasUnresolvedArgs(c, def): @@ -1432,11 +1438,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, onDef(a[j].info, arg) a[j] = newSymNode(arg) - var r: PType = - if n[0].kind != nkEmpty: - semTypeNode(c, n[0], nil) - else: - nil + var r: PType = nil + if n[0].kind != nkEmpty: + let isGeneric = isCurrentlyGeneric() + inc c.inGenericContext, ord(isGeneric) + r = semTypeNode(c, n[0], nil) + dec c.inGenericContext, ord(isGeneric) if r != nil and kind in {skMacro, skTemplate} and r.kind == tyTyped: # XXX: To implement the proposed change in the warning, just @@ -1489,7 +1496,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, result.flags.excl tfHasMeta result.n.typ = r - if genericParams != nil and genericParams.len > 0: + if isCurrentlyGeneric(): for n in genericParams: if {sfUsed, sfAnon} * n.sym.flags == {}: result.flags.incl tfUnresolved diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 428d897ec..483db0bbb 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -678,8 +678,31 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = elif t.elementType.kind != tyNone: result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.elementType)) - of tyUserTypeClass, tyStatic: + of tyUserTypeClass: result = t + + of tyStatic: + if cl.c.matchedConcept != nil: + # allow concepts to not instantiate statics for now + # they can't always infer them + return + if not containsGenericType(t) and (t.n == nil or t.n.kind in nkLiterals): + # no need to instantiate + return + bailout() + result = instCopyType(cl, t) + cl.localCache[t.itemId] = result + for i in FirstGenericParamAt..<result.kidsLen: + var r = result[i] + if r != nil: + r = replaceTypeVarsT(cl, r) + result[i] = r + propagateToOwner(result, r) + result.n = replaceTypeVarsN(cl, result.n) + if not cl.allowMetaTypes and result.n != nil and + result.base.kind != tyNone: + result.n = cl.c.semConstExpr(cl.c, result.n) + result.n.typ = result.base of tyGenericInst, tyUserTypeClassInst: bailout() diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index d0c9ce029..ee1ad49d0 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -885,6 +885,7 @@ proc maybeSkipDistinct(m: TCandidate; t: PType, callee: PSym): PType = proc tryResolvingStaticExpr(c: var TCandidate, n: PNode, allowUnresolved = false, + allowCalls = false, expectedType: PType = nil): PNode = # Consider this example: # type Value[N: static[int]] = object @@ -894,7 +895,7 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode, # This proc is used to evaluate such static expressions. let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil, allowMetaTypes = allowUnresolved) - if instantiated.kind in nkCallKinds: + if not allowCalls and instantiated.kind in nkCallKinds: return nil result = c.c.semExpr(c.c, instantiated) @@ -966,7 +967,8 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool = else: discard - elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil: + elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and + (lhs.typ.n == nil or idTableGet(c.bindings, lhs.typ) == nil): var inferred = newTypeS(tyStatic, c.c, lhs.typ.elementType) inferred.n = newIntNode(nkIntLit, rhs) put(c, lhs.typ, inferred) @@ -1877,7 +1879,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, elif f.base.kind notin {tyNone, tyGenericParam}: result = typeRel(c, f.base, a, flags) if result != isNone and f.n != nil: - if not exprStructuralEquivalent(f.n, aOrig.n): + var r = tryResolvingStaticExpr(c, f.n) + if r == nil: r = f.n + if not exprStructuralEquivalent(r, aOrig.n) and + not (aOrig.n.kind == nkIntLit and + inferStaticParam(c, r, aOrig.n.intVal)): result = isNone elif f.base.kind == tyGenericParam: # Handling things like `type A[T; Y: static T] = object` @@ -1963,23 +1969,29 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyFromExpr: # fix the expression, so it contains the already instantiated types if f.n == nil or f.n.kind == nkEmpty: return isGeneric - let reevaluated = tryResolvingStaticExpr(c, f.n) - if reevaluated == nil: + if c.c.inGenericContext > 0: + # need to delay until instantiation + # also prevent infinite recursion below + return isNone + inc c.c.inGenericContext # to generate tyFromExpr again if unresolved + let reevaluated = tryResolvingStaticExpr(c, f.n, allowCalls = true).typ + dec c.c.inGenericContext + case reevaluated.kind + of tyFromExpr: + # not resolved result = isNone - return - case reevaluated.typ.kind of tyTypeDesc: - result = typeRel(c, a, reevaluated.typ.base, flags) + result = typeRel(c, a, reevaluated.base, flags) of tyStatic: - result = typeRel(c, a, reevaluated.typ.base, flags) - if result != isNone and reevaluated.typ.n != nil: - if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n): + result = typeRel(c, a, reevaluated.base, flags) + if result != isNone and reevaluated.n != nil: + if not exprStructuralEquivalent(aOrig.n, reevaluated.n): result = isNone else: # bug #14136: other types are just like 'tyStatic' here: - result = typeRel(c, a, reevaluated.typ, flags) - if result != isNone and reevaluated.typ.n != nil: - if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n): + result = typeRel(c, a, reevaluated, flags) + if result != isNone and reevaluated.n != nil: + if not exprStructuralEquivalent(aOrig.n, reevaluated.n): result = isNone of tyNone: if a.kind == tyNone: result = isEqual @@ -2188,7 +2200,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, a = typ else: if m.callee.kind == tyGenericBody: - if f.kind == tyStatic and typeRel(m, f.base, a) != isNone: + # we can't use `makeStaticExpr` if `arg` has a generic type + # because it generates `tyStatic`, which semtypinst doesn't touch + # not sure if checking for `tyFromExpr` is enough + if f.kind == tyStatic and typeRel(m, f.base, a) != isNone and + a.kind != tyFromExpr: result = makeStaticExpr(m.c, arg) result.typ.flags.incl tfUnresolved result.typ.n = arg |