diff options
-rwxr-xr-x | compiler/semexprs.nim | 10 | ||||
-rwxr-xr-x | compiler/semgnrc.nim | 9 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 11 | ||||
-rw-r--r-- | tests/run/tmixin.nim | 27 |
4 files changed, 47 insertions, 10 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index adcd67ea3..2c98d9de6 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -471,7 +471,8 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = result = n case n.kind of nkSym: - if skipTypes(n.sym.typ, abstractInst).kind != tyVar: + # n.sym.typ can be nil in 'check' mode ... + if n.sym.typ != nil and skipTypes(n.sym.typ, abstractInst).kind != tyVar: incl(n.sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n) of nkDotExpr: @@ -722,9 +723,6 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode = addSon(result, semExpr(c, arg)) proc discardCheck(result: PNode) = - proc ImplicitelyDiscardable(n: PNode): bool {.inline.} = - result = isCallExpr(n) and n.sons[0].kind == nkSym and - sfDiscardable in n.sons[0].sym.flags if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}: if result.kind == nkNilLit: # XXX too much work and fixing would break bootstrapping: @@ -1104,7 +1102,9 @@ proc semProcBody(c: PContext, n: PNode): PNode = # ``result``: if result.kind == nkSym and result.sym == c.p.resultSym: nil - elif result.kind == nkNilLit: + elif result.kind == nkNilLit or ImplicitelyDiscardable(result): + # intended semantic: if it's 'discardable' and the context allows for it, + # discard it. This is bad for chaining but nicer for C wrappers. # ambiguous :-( result.typ = nil else: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index dc0be54cb..4eaa5f39b 100755 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -87,7 +87,7 @@ proc Lookup(c: PContext, n: PNode, flags: TSemGenericFlags, if ident.id notin ctx and withinMixin notin flags: localError(n.info, errUndeclaredIdentifier, ident.s) else: - if withinMixin in flags: + if withinBind in flags: result = symChoice(c, n, s, scClosed) elif s.name.id in ctx: result = symChoice(c, n, s, scForceOpen) @@ -134,26 +134,27 @@ proc semGenericStmt(c: PContext, n: PNode, if s != nil: incl(s.flags, sfUsed) isDefinedMagic = s.magic in {mDefined, mDefinedInScope, mCompiles} + let scOption = if s.name.id in ctx: scForceOpen else: scOpen case s.kind of skMacro: if macroToExpand(s): result = semMacroExpr(c, n, n, s, false) else: - n.sons[0] = symChoice(c, n.sons[0], s, scOpen) + n.sons[0] = symChoice(c, n.sons[0], s, scOption) result = n of skTemplate: if macroToExpand(s): let n = fixImmediateParams(n) result = semTemplateExpr(c, n, s, false) else: - n.sons[0] = symChoice(c, n.sons[0], s, scOpen) + n.sons[0] = symChoice(c, n.sons[0], s, scOption) result = n # BUGFIX: we must not return here, we need to do first phase of # symbol lookup ... of skUnknown, skParam: # Leave it as an identifier. of skProc, skMethod, skIterator, skConverter: - result.sons[0] = symChoice(c, n.sons[0], s, scOpen) + result.sons[0] = symChoice(c, n.sons[0], s, scOption) first = 1 of skGenericParam: result.sons[0] = newSymNode(s, n.sons[0].info) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5c0060e20..2d36015a7 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1088,6 +1088,10 @@ proc insertDestructors(c: PContext, varSection: PNode): return +proc ImplicitelyDiscardable(n: PNode): bool = + result = isCallExpr(n) and n.sons[0].kind == nkSym and + sfDiscardable in n.sons[0].sym.flags + proc semStmtList(c: PContext, n: PNode): PNode = # these must be last statements in a block: const @@ -1134,7 +1138,12 @@ proc semStmtList(c: PContext, n: PNode): PNode = # a statement list (s; e) has the type 'e': if result.kind == nkStmtList and result.len > 0: - result.typ = lastSon(result).typ + var lastStmt = lastSon(result) + if not ImplicitelyDiscardable(lastStmt): + result.typ = lastStmt.typ + #localError(lastStmt.info, errGenerated, + # "Last expression must be explicitly returned if it " & + # "is discardable or discarded") proc SemStmt(c: PContext, n: PNode): PNode = # now: simply an alias: diff --git a/tests/run/tmixin.nim b/tests/run/tmixin.nim new file mode 100644 index 000000000..d841326a5 --- /dev/null +++ b/tests/run/tmixin.nim @@ -0,0 +1,27 @@ +discard """ + output: "1\n2" +""" + +type + TFoo1 = object of TObject + v: int + TFoo2 = object of TFoo1 + v2: int + +proc test(f: TFoo1) = + echo "1" + +proc Foo[T](f: T) = + mixin test + test(f) + +var + a: TFoo1 + b: TFoo2 + + +proc test(f: TFoo2) = + echo "2" + +Foo(a) +Foo(b) |