introduce a pre-processing pass for the concept bodies
fixes #4982 fixes #3805 close #3414
This commit is contained in:
parent
30ccadfe4c
commit
cd02561368
13 changed files with 138 additions and 60 deletions
|
|
@ -442,6 +442,7 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
|
||||||
result = nn
|
result = nn
|
||||||
|
|
||||||
proc semGenericStmt(c: PContext, n: PNode): PNode
|
proc semGenericStmt(c: PContext, n: PNode): PNode
|
||||||
|
proc semConceptBody(c: PContext, n: PNode): PNode
|
||||||
|
|
||||||
include semtypes, semtempl, semgnrc, semstmts, semexprs
|
include semtypes, semtempl, semgnrc, semstmts, semexprs
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,11 @@ type
|
||||||
bracketExpr*: PNode # current bracket expression (for ^ support)
|
bracketExpr*: PNode # current bracket expression (for ^ support)
|
||||||
mapping*: TIdTable
|
mapping*: TIdTable
|
||||||
|
|
||||||
|
TMatchedConcept* = object
|
||||||
|
candidateType*: PType
|
||||||
|
prev*: ptr TMatchedConcept
|
||||||
|
depth*: int
|
||||||
|
|
||||||
TInstantiationPair* = object
|
TInstantiationPair* = object
|
||||||
genericSym*: PSym
|
genericSym*: PSym
|
||||||
inst*: PInstantiation
|
inst*: PInstantiation
|
||||||
|
|
@ -75,6 +80,7 @@ type
|
||||||
importTable*: PScope # scope for all imported symbols
|
importTable*: PScope # scope for all imported symbols
|
||||||
topLevelScope*: PScope # scope for all top-level symbols
|
topLevelScope*: PScope # scope for all top-level symbols
|
||||||
p*: PProcCon # procedure context
|
p*: PProcCon # procedure context
|
||||||
|
matchedConcept*: ptr TMatchedConcept # the current concept being matched
|
||||||
friendModules*: seq[PSym] # friend modules; may access private data;
|
friendModules*: seq[PSym] # friend modules; may access private data;
|
||||||
# this is used so that generic instantiations
|
# this is used so that generic instantiations
|
||||||
# can access private object fields
|
# can access private object fields
|
||||||
|
|
@ -82,7 +88,6 @@ type
|
||||||
|
|
||||||
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
||||||
# store this info in the syms themselves!)
|
# store this info in the syms themselves!)
|
||||||
inTypeClass*: int # > 0 if we are in a user-defined type class
|
|
||||||
inGenericContext*: int # > 0 if we are in a generic type
|
inGenericContext*: int # > 0 if we are in a generic type
|
||||||
inUnrolledContext*: int # > 0 if we are unrolling a loop
|
inUnrolledContext*: int # > 0 if we are unrolling a loop
|
||||||
compilesContextId*: int # > 0 if we are in a ``compiles`` magic
|
compilesContextId*: int # > 0 if we are in a ``compiles`` magic
|
||||||
|
|
@ -277,7 +282,7 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
|
||||||
assert n != nil
|
assert n != nil
|
||||||
result.n = n
|
result.n = n
|
||||||
|
|
||||||
proc newTypeWithSons2*(kind: TTypeKind, owner: PSym, sons: seq[PType]): PType =
|
proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType]): PType =
|
||||||
result = newType(kind, owner)
|
result = newType(kind, owner)
|
||||||
result.sons = sons
|
result.sons = sons
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -705,7 +705,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||||
analyseIfAddressTakenInCall(c, result)
|
analyseIfAddressTakenInCall(c, result)
|
||||||
if callee.magic != mNone:
|
if callee.magic != mNone:
|
||||||
result = magicsAfterOverloadResolution(c, result, flags)
|
result = magicsAfterOverloadResolution(c, result, flags)
|
||||||
if c.inTypeClass == 0:
|
if c.matchedConcept == nil:
|
||||||
result = evalAtCompileTime(c, result)
|
result = evalAtCompileTime(c, result)
|
||||||
|
|
||||||
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
@ -2147,7 +2147,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
let checks = if efNoEvaluateGeneric in flags: {checkUndeclared}
|
let checks = if efNoEvaluateGeneric in flags: {checkUndeclared}
|
||||||
else: {checkUndeclared, checkModule, checkAmbiguity}
|
else: {checkUndeclared, checkModule, checkAmbiguity}
|
||||||
var s = qualifiedLookUp(c, n, checks)
|
var s = qualifiedLookUp(c, n, checks)
|
||||||
if c.inTypeClass == 0: semCaptureSym(s, c.p.owner)
|
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
|
||||||
result = semSym(c, n, s, flags)
|
result = semSym(c, n, s, flags)
|
||||||
if s.kind in {skProc, skMethod, skConverter, skIterator}:
|
if s.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||||
#performProcvarCheck(c, n, s)
|
#performProcvarCheck(c, n, s)
|
||||||
|
|
|
||||||
|
|
@ -594,8 +594,11 @@ proc foldConStrStr(m: PSym, n: PNode): PNode =
|
||||||
|
|
||||||
proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
|
proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
|
||||||
result = newSymNode(s, info)
|
result = newSymNode(s, info)
|
||||||
|
if s.typ.kind != tyTypeDesc:
|
||||||
result.typ = newType(tyTypeDesc, s.owner)
|
result.typ = newType(tyTypeDesc, s.owner)
|
||||||
result.typ.addSonSkipIntLit(s.typ)
|
result.typ.addSonSkipIntLit(s.typ)
|
||||||
|
else:
|
||||||
|
result.typ = s.typ
|
||||||
|
|
||||||
proc getConstExpr(m: PSym, n: PNode): PNode =
|
proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||||
result = nil
|
result = nil
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ type
|
||||||
|
|
||||||
type
|
type
|
||||||
TSemGenericFlag = enum
|
TSemGenericFlag = enum
|
||||||
withinBind, withinTypeDesc, withinMixin
|
withinBind, withinTypeDesc, withinMixin, withinConcept
|
||||||
TSemGenericFlags = set[TSemGenericFlag]
|
TSemGenericFlags = set[TSemGenericFlag]
|
||||||
|
|
||||||
proc semGenericStmt(c: PContext, n: PNode,
|
proc semGenericStmt(c: PContext, n: PNode,
|
||||||
|
|
@ -200,12 +200,13 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
let fn = n.sons[0]
|
let fn = n.sons[0]
|
||||||
var s = qualifiedLookUp(c, fn, {})
|
var s = qualifiedLookUp(c, fn, {})
|
||||||
if s == nil and withinMixin notin flags and
|
if s == nil and
|
||||||
|
{withinMixin, withinConcept}*flags == {} and
|
||||||
fn.kind in {nkIdent, nkAccQuoted} and
|
fn.kind in {nkIdent, nkAccQuoted} and
|
||||||
considerQuotedIdent(fn).id notin ctx.toMixin:
|
considerQuotedIdent(fn).id notin ctx.toMixin:
|
||||||
errorUndeclaredIdentifier(c, n.info, fn.renderTree)
|
errorUndeclaredIdentifier(c, n.info, fn.renderTree)
|
||||||
|
|
||||||
var first = 0
|
var first = ord(withinConcept in flags)
|
||||||
var mixinContext = false
|
var mixinContext = false
|
||||||
if s != nil:
|
if s != nil:
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
|
|
@ -471,3 +472,9 @@ proc semGenericStmt(c: PContext, n: PNode): PNode =
|
||||||
ctx.toMixin = initIntset()
|
ctx.toMixin = initIntset()
|
||||||
result = semGenericStmt(c, n, {}, ctx)
|
result = semGenericStmt(c, n, {}, ctx)
|
||||||
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
||||||
|
|
||||||
|
proc semConceptBody(c: PContext, n: PNode): PNode =
|
||||||
|
var ctx: GenericCtx
|
||||||
|
ctx.toMixin = initIntset()
|
||||||
|
result = semGenericStmt(c, n, {withinConcept}, ctx)
|
||||||
|
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
||||||
|
|
|
||||||
|
|
@ -257,8 +257,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
# NOTE: for access of private fields within generics from a different module
|
# NOTE: for access of private fields within generics from a different module
|
||||||
# we set the friend module:
|
# we set the friend module:
|
||||||
c.friendModules.add(getModule(fn))
|
c.friendModules.add(getModule(fn))
|
||||||
let oldInTypeClass = c.inTypeClass
|
let oldMatchedConcept = c.matchedConcept
|
||||||
c.inTypeClass = 0
|
c.matchedConcept = nil
|
||||||
let oldScope = c.currentScope
|
let oldScope = c.currentScope
|
||||||
while not isTopLevel(c): c.currentScope = c.currentScope.parent
|
while not isTopLevel(c): c.currentScope = c.currentScope.parent
|
||||||
result = copySym(fn, false)
|
result = copySym(fn, false)
|
||||||
|
|
@ -319,5 +319,5 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
c.currentScope = oldScope
|
c.currentScope = oldScope
|
||||||
discard c.friendModules.pop()
|
discard c.friendModules.pop()
|
||||||
dec(c.instCounter)
|
dec(c.instCounter)
|
||||||
c.inTypeClass = oldInTypeClass
|
c.matchedConcept = oldMatchedConcept
|
||||||
if result.kind == skMethod: finishMethod(c, result)
|
if result.kind == skMethod: finishMethod(c, result)
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ proc uninstantiate(t: PType): PType =
|
||||||
else: t
|
else: t
|
||||||
|
|
||||||
proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
|
proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
|
||||||
const skippedTypes = {tyTypeDesc}
|
const skippedTypes = {tyTypeDesc, tyAlias}
|
||||||
let trait = traitCall[0]
|
let trait = traitCall[0]
|
||||||
internalAssert trait.kind == nkSym
|
internalAssert trait.kind == nkSym
|
||||||
var operand = operand.skipTypes(skippedTypes)
|
var operand = operand.skipTypes(skippedTypes)
|
||||||
|
|
@ -119,7 +119,7 @@ proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
|
||||||
traitCall.sons[2].typ.skipTypes({tyTypeDesc})
|
traitCall.sons[2].typ.skipTypes({tyTypeDesc})
|
||||||
|
|
||||||
template typeWithSonsResult(kind, sons): PNode =
|
template typeWithSonsResult(kind, sons): PNode =
|
||||||
newTypeWithSons2(kind, context, sons).toNode(traitCall.info)
|
newTypeWithSons(context, kind, sons).toNode(traitCall.info)
|
||||||
|
|
||||||
case trait.sym.name.s
|
case trait.sym.name.s
|
||||||
of "or", "|":
|
of "or", "|":
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ proc fixNilType(n: PNode) =
|
||||||
n.typ = nil
|
n.typ = nil
|
||||||
|
|
||||||
proc discardCheck(c: PContext, result: PNode) =
|
proc discardCheck(c: PContext, result: PNode) =
|
||||||
if c.inTypeClass > 0: return
|
if c.matchedConcept != nil: return
|
||||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
||||||
if result.kind == nkNilLit:
|
if result.kind == nkNilLit:
|
||||||
result.typ = nil
|
result.typ = nil
|
||||||
|
|
@ -1761,7 +1761,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
else:
|
else:
|
||||||
var expr = semExpr(c, n.sons[i], flags)
|
var expr = semExpr(c, n.sons[i], flags)
|
||||||
n.sons[i] = expr
|
n.sons[i] = expr
|
||||||
if c.inTypeClass > 0 and expr.typ != nil:
|
if c.matchedConcept != nil and expr.typ != nil:
|
||||||
case expr.typ.kind
|
case expr.typ.kind
|
||||||
of tyBool:
|
of tyBool:
|
||||||
if expr.kind == nkInfix and
|
if expr.kind == nkInfix and
|
||||||
|
|
@ -1800,7 +1800,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
||||||
if result.len == 1 and
|
if result.len == 1 and
|
||||||
# concept bodies should be preserved as a stmt list:
|
# concept bodies should be preserved as a stmt list:
|
||||||
c.inTypeClass == 0 and
|
c.matchedConcept == nil and
|
||||||
# also, don't make life complicated for macros.
|
# also, don't make life complicated for macros.
|
||||||
# they will always expect a proper stmtlist:
|
# they will always expect a proper stmtlist:
|
||||||
nfBlockArg notin n.flags and
|
nfBlockArg notin n.flags and
|
||||||
|
|
|
||||||
|
|
@ -1202,17 +1202,51 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
||||||
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
||||||
if nfBase2 in n.flags:
|
if nfBase2 in n.flags:
|
||||||
message(n.info, warnDeprecated, "use 'concept' instead; 'generic'")
|
message(n.info, warnDeprecated, "use 'concept' instead; 'generic'")
|
||||||
result = newOrPrevType(tyUserTypeClass, prev, c)
|
|
||||||
result.n = n
|
|
||||||
|
|
||||||
let
|
let
|
||||||
pragmas = n[1]
|
pragmas = n[1]
|
||||||
inherited = n[2]
|
inherited = n[2]
|
||||||
|
|
||||||
|
result = newOrPrevType(tyUserTypeClass, prev, c)
|
||||||
|
var owner = getCurrOwner(c)
|
||||||
|
var candidateTypeSlot = newTypeWithSons(owner, tyAlias, @[c.errorType])
|
||||||
|
result.sons = @[candidateTypeSlot]
|
||||||
|
result.n = n
|
||||||
|
|
||||||
if inherited.kind != nkEmpty:
|
if inherited.kind != nkEmpty:
|
||||||
for n in inherited.sons:
|
for n in inherited.sons:
|
||||||
let typ = semTypeNode(c, n, nil)
|
let typ = semTypeNode(c, n, nil)
|
||||||
result.sons.safeAdd(typ)
|
result.sons.add(typ)
|
||||||
|
|
||||||
|
openScope(c)
|
||||||
|
for param in n[0]:
|
||||||
|
var
|
||||||
|
dummyName: PNode
|
||||||
|
dummyType: PType
|
||||||
|
|
||||||
|
let modifier = case param.kind
|
||||||
|
of nkVarTy: tyVar
|
||||||
|
of nkRefTy: tyRef
|
||||||
|
of nkPtrTy: tyPtr
|
||||||
|
of nkStaticTy: tyStatic
|
||||||
|
of nkTypeOfExpr: tyTypeDesc
|
||||||
|
else: tyNone
|
||||||
|
|
||||||
|
if modifier != tyNone:
|
||||||
|
dummyName = param[0]
|
||||||
|
dummyType = c.makeTypeWithModifier(modifier, candidateTypeSlot)
|
||||||
|
if modifier == tyTypeDesc: dummyType.flags.incl tfExplicit
|
||||||
|
else:
|
||||||
|
dummyName = param
|
||||||
|
dummyType = candidateTypeSlot
|
||||||
|
|
||||||
|
internalAssert dummyName.kind == nkIdent
|
||||||
|
var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
|
||||||
|
dummyName.ident, owner, owner.info)
|
||||||
|
dummyParam.typ = dummyType
|
||||||
|
addDecl(c, dummyParam)
|
||||||
|
|
||||||
|
result.n.sons[3] = semConceptBody(c, n[3])
|
||||||
|
closeScope(c)
|
||||||
|
|
||||||
proc semProcTypeWithScope(c: PContext, n: PNode,
|
proc semProcTypeWithScope(c: PContext, n: PNode,
|
||||||
prev: PType, kind: TSymKind): PType =
|
prev: PType, kind: TSymKind): PType =
|
||||||
|
|
|
||||||
|
|
@ -607,14 +607,24 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
var
|
var
|
||||||
typeClass = ff.skipTypes({tyUserTypeClassInst})
|
typeClass = ff.skipTypes({tyUserTypeClassInst})
|
||||||
body = typeClass.n[3]
|
body = typeClass.n[3]
|
||||||
if c.inTypeClass > 4:
|
matchedConceptContext: TMatchedConcept
|
||||||
|
prevMatchedConcept = c.matchedConcept
|
||||||
|
prevCandidateType = typeClass[0][0]
|
||||||
|
|
||||||
|
if prevMatchedConcept != nil:
|
||||||
|
matchedConceptContext.prev = prevMatchedConcept
|
||||||
|
matchedConceptContext.depth = prevMatchedConcept.depth + 1
|
||||||
|
if prevMatchedConcept.depth > 4:
|
||||||
localError(body.info, $body & " too nested for type matching")
|
localError(body.info, $body & " too nested for type matching")
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
openScope(c)
|
openScope(c)
|
||||||
inc c.inTypeClass
|
matchedConceptContext.candidateType = a
|
||||||
|
typeClass[0].sons[0] = a
|
||||||
|
c.matchedConcept = addr(matchedConceptContext)
|
||||||
defer:
|
defer:
|
||||||
dec c.inTypeClass
|
c.matchedConcept = prevMatchedConcept
|
||||||
|
typeClass[0].sons[0] = prevCandidateType
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
var typeParams: seq[(PSym, PType)]
|
var typeParams: seq[(PSym, PType)]
|
||||||
|
|
@ -658,33 +668,6 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
|
|
||||||
addDecl(c, param)
|
addDecl(c, param)
|
||||||
|
|
||||||
for param in typeClass.n[0]:
|
|
||||||
var
|
|
||||||
dummyName: PNode
|
|
||||||
dummyType: PType
|
|
||||||
|
|
||||||
let modifier = case param.kind
|
|
||||||
of nkVarTy: tyVar
|
|
||||||
of nkRefTy: tyRef
|
|
||||||
of nkPtrTy: tyPtr
|
|
||||||
of nkStaticTy: tyStatic
|
|
||||||
of nkTypeOfExpr: tyTypeDesc
|
|
||||||
else: tyNone
|
|
||||||
|
|
||||||
if modifier != tyNone:
|
|
||||||
dummyName = param[0]
|
|
||||||
dummyType = c.makeTypeWithModifier(modifier, a)
|
|
||||||
if modifier == tyTypeDesc: dummyType.flags.incl tfExplicit
|
|
||||||
else:
|
|
||||||
dummyName = param
|
|
||||||
dummyType = a
|
|
||||||
|
|
||||||
internalAssert dummyName.kind == nkIdent
|
|
||||||
var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
|
|
||||||
dummyName.ident, typeClass.sym, typeClass.sym.info)
|
|
||||||
dummyParam.typ = dummyType
|
|
||||||
addDecl(c, dummyParam)
|
|
||||||
|
|
||||||
var
|
var
|
||||||
oldWriteHook: type(writelnHook)
|
oldWriteHook: type(writelnHook)
|
||||||
diagnostics: seq[string]
|
diagnostics: seq[string]
|
||||||
|
|
@ -826,7 +809,7 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
|
||||||
var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ.sons)
|
var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ.sons)
|
||||||
inferred.n = newIntNode(nkIntLit, rhs)
|
inferred.n = newIntNode(nkIntLit, rhs)
|
||||||
put(c, lhs.typ, inferred)
|
put(c, lhs.typ, inferred)
|
||||||
if c.c.inTypeClass > 0:
|
if c.c.matchedConcept != nil:
|
||||||
# inside concepts, binding is currently done with
|
# inside concepts, binding is currently done with
|
||||||
# direct mutation of the involved types:
|
# direct mutation of the involved types:
|
||||||
lhs.typ.n = inferred.n
|
lhs.typ.n = inferred.n
|
||||||
|
|
@ -916,7 +899,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
assert(aOrig != nil)
|
assert(aOrig != nil)
|
||||||
|
|
||||||
var
|
var
|
||||||
useTypeLoweringRuleInTypeClass = c.c.inTypeClass > 0 and
|
useTypeLoweringRuleInTypeClass = c.c.matchedConcept != nil and
|
||||||
not c.isNoCall and
|
not c.isNoCall and
|
||||||
f.kind != tyTypeDesc and
|
f.kind != tyTypeDesc and
|
||||||
tfExplicit notin aOrig.flags
|
tfExplicit notin aOrig.flags
|
||||||
|
|
@ -965,7 +948,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
# for example, but unfortunately `prepareOperand` is not called in certain
|
# for example, but unfortunately `prepareOperand` is not called in certain
|
||||||
# situation when nkDotExpr are rotated to nkDotCalls
|
# situation when nkDotExpr are rotated to nkDotCalls
|
||||||
|
|
||||||
if a.kind in {tyGenericInst, tyAlias} and
|
if aOrig.kind == tyAlias:
|
||||||
|
return typeRel(c, f, lastSon(aOrig))
|
||||||
|
|
||||||
|
if a.kind == tyGenericInst and
|
||||||
skipTypes(f, {tyVar}).kind notin {
|
skipTypes(f, {tyVar}).kind notin {
|
||||||
tyGenericBody, tyGenericInvocation,
|
tyGenericBody, tyGenericInvocation,
|
||||||
tyGenericInst, tyGenericParam} + tyTypeClasses:
|
tyGenericInst, tyGenericParam} + tyTypeClasses:
|
||||||
|
|
@ -1106,7 +1092,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
|
|
||||||
if fRange.rangeHasUnresolvedStatic:
|
if fRange.rangeHasUnresolvedStatic:
|
||||||
return inferStaticsInRange(c, fRange, a)
|
return inferStaticsInRange(c, fRange, a)
|
||||||
elif c.c.inTypeClass > 0 and aRange.rangeHasUnresolvedStatic:
|
elif c.c.matchedConcept != nil and aRange.rangeHasUnresolvedStatic:
|
||||||
return inferStaticsInRange(c, aRange, f)
|
return inferStaticsInRange(c, aRange, f)
|
||||||
else:
|
else:
|
||||||
if lengthOrd(fRange) != lengthOrd(aRange):
|
if lengthOrd(fRange) != lengthOrd(aRange):
|
||||||
|
|
|
||||||
|
|
@ -110,9 +110,11 @@ proc isDeepConstExpr*(n: PNode): bool =
|
||||||
|
|
||||||
proc isRange*(n: PNode): bool {.inline.} =
|
proc isRange*(n: PNode): bool {.inline.} =
|
||||||
if n.kind in nkCallKinds:
|
if n.kind in nkCallKinds:
|
||||||
if n[0].kind == nkIdent and n[0].ident.id == ord(wDotDot) or
|
let callee = n[0]
|
||||||
n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
|
if (callee.kind == nkIdent and callee.ident.id == ord(wDotDot)) or
|
||||||
n[0][1].sym.name.id == ord(wDotDot):
|
(callee.kind == nkSym and callee.sym.name.id == ord(wDotDot)) or
|
||||||
|
(callee.kind in {nkClosedSymChoice, nkOpenSymChoice} and
|
||||||
|
callee[1].sym.name.id == ord(wDotDot)):
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc whichPragma*(n: PNode): TSpecialWord =
|
proc whichPragma*(n: PNode): TSpecialWord =
|
||||||
|
|
|
||||||
22
tests/concepts/t3414.nim
Normal file
22
tests/concepts/t3414.nim
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
type
|
||||||
|
View[T] = concept v
|
||||||
|
v.empty is bool
|
||||||
|
v.front is T
|
||||||
|
popFront v
|
||||||
|
|
||||||
|
proc find(view: View; target: View.T): View =
|
||||||
|
result = view
|
||||||
|
|
||||||
|
while not result.empty:
|
||||||
|
if view.front == target:
|
||||||
|
return
|
||||||
|
|
||||||
|
mixin popFront
|
||||||
|
popFront result
|
||||||
|
|
||||||
|
proc popFront[T](s: var seq[T]) = discard
|
||||||
|
proc empty[T](s: seq[T]): bool = false
|
||||||
|
|
||||||
|
var s1 = @[1, 2, 3]
|
||||||
|
let s2 = s1.find(10)
|
||||||
|
|
||||||
18
tests/concepts/t4982.nim
Normal file
18
tests/concepts/t4982.nim
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "undeclared identifier: 'x'"
|
||||||
|
line: 10
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits # without this import the program compiles (and echos false)
|
||||||
|
|
||||||
|
type
|
||||||
|
SomeTestConcept = concept t
|
||||||
|
x.name is string # typo: t.name was intended (which would result in echo true)
|
||||||
|
|
||||||
|
type
|
||||||
|
TestClass = ref object of RootObj
|
||||||
|
name: string
|
||||||
|
|
||||||
|
var test = TestClass(name: "mytest")
|
||||||
|
echo $(test is SomeTestConcept)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue