mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-07 13:33:22 +00:00
requested code review changes
This commit is contained in:
@@ -99,7 +99,10 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
if cmp < 0: best = z # x is better than the best so far
|
||||
elif cmp == 0: alt = z # x is as good as the best so far
|
||||
elif errors != nil or z.diagnostics != nil:
|
||||
errors.safeAdd((sym, int z.mutabilityProblem, z.diagnostics))
|
||||
errors.safeAdd(CandidateError(
|
||||
sym: sym,
|
||||
unmatchedVarParam: int z.mutabilityProblem,
|
||||
diagnostics: z.diagnostics))
|
||||
else:
|
||||
# Symbol table has been modified. Restart and pre-calculate all syms
|
||||
# before any further candidate init and compare. SLOW, but rare case.
|
||||
@@ -126,9 +129,9 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
# we do a pre-analysis. If all types produce the same string, we will add
|
||||
# module information.
|
||||
let proto = describeArgs(c, n, 1, preferName)
|
||||
for err, mut, diagnostics in items(errors):
|
||||
for err in errors:
|
||||
var errProto = ""
|
||||
let n = err.typ.n
|
||||
let n = err.sym.typ.n
|
||||
for i in countup(1, n.len - 1):
|
||||
var p = n.sons[i]
|
||||
if p.kind == nkSym:
|
||||
@@ -140,16 +143,17 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
break
|
||||
|
||||
var candidates = ""
|
||||
for err, mut, diagnostics in items(errors):
|
||||
if err.kind in routineKinds and err.ast != nil:
|
||||
add(candidates, renderTree(err.ast,
|
||||
for err in errors:
|
||||
if err.sym.kind in routineKinds and err.sym.ast != nil:
|
||||
add(candidates, renderTree(err.sym.ast,
|
||||
{renderNoBody, renderNoComments, renderNoPragmas}))
|
||||
else:
|
||||
add(candidates, err.getProcHeader(prefer))
|
||||
add(candidates, err.sym.getProcHeader(prefer))
|
||||
add(candidates, "\n")
|
||||
if mut != 0 and mut < n.len:
|
||||
add(candidates, "for a 'var' type a variable needs to be passed, but '" & renderTree(n[mut]) & "' is immutable\n")
|
||||
for diag in diagnostics:
|
||||
if err.unmatchedVarParam != 0 and err.unmatchedVarParam < n.len:
|
||||
add(candidates, "for a 'var' type a variable needs to be passed, but '" &
|
||||
renderTree(n[err.unmatchedVarParam]) & "' is immutable\n")
|
||||
for diag in err.diagnostics:
|
||||
add(candidates, diag & "\n")
|
||||
|
||||
result = (prefer, candidates)
|
||||
@@ -180,7 +184,9 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
|
||||
var symx = initOverloadIter(o, c, headSymbol)
|
||||
while symx != nil:
|
||||
if symx.kind in routineKinds:
|
||||
errors.add((symx, 0, nil))
|
||||
errors.add(CandidateError(sym: symx,
|
||||
unmatchedVarParam: 0,
|
||||
diagnostics: nil))
|
||||
symx = nextOverloadIter(o, c, headSymbol)
|
||||
if errors.len == 0:
|
||||
localError(n.info, "could not resolve: " & $n)
|
||||
@@ -405,7 +411,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||
n.sons[1] = n.sons[1].sons[0]
|
||||
notFoundError(c, n, errors)
|
||||
else:
|
||||
if efExplain notin flags:
|
||||
if efExplain notin flags and c.compilesContextId == 0:
|
||||
# repeat the overload resolution,
|
||||
# this time enabling all the diagnostic output (this should fail again)
|
||||
discard semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
|
||||
|
||||
@@ -1555,9 +1555,14 @@ proc usesResult(n: PNode): bool =
|
||||
for c in n:
|
||||
if usesResult(c): return true
|
||||
|
||||
proc inferConceptStaticParam(c: PContext, typ: PType, n: PNode) =
|
||||
proc inferConceptStaticParam(c: PContext, inferred, n: PNode) =
|
||||
var typ = inferred.typ
|
||||
let res = semConstExpr(c, n)
|
||||
if not sameType(res.typ, typ.base): localError(n.info, "")
|
||||
if not sameType(res.typ, typ.base):
|
||||
localError(n.info,
|
||||
"cannot infer the concept parameter '%s', due to a type mismatch. " &
|
||||
"attempt to equate '%s' and '%s'.",
|
||||
[inferred.renderTree, $res.typ, $typ.base])
|
||||
typ.n = res
|
||||
|
||||
proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
@@ -1616,12 +1621,14 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if c.inTypeClass > 0 and expr.typ != nil:
|
||||
case expr.typ.kind
|
||||
of tyBool:
|
||||
if expr.kind == nkInfix and expr[0].sym.name.s == "==":
|
||||
if expr.kind == nkInfix and
|
||||
expr[0].kind == nkSym and
|
||||
expr[0].sym.name.s == "==":
|
||||
if expr[1].typ.isUnresolvedStatic:
|
||||
inferConceptStaticParam(c, expr[1].typ, expr[2])
|
||||
inferConceptStaticParam(c, expr[1], expr[2])
|
||||
continue
|
||||
elif expr[2].typ.isUnresolvedStatic:
|
||||
inferConceptStaticParam(c, expr[2].typ, expr[1])
|
||||
inferConceptStaticParam(c, expr[2], expr[1])
|
||||
continue
|
||||
|
||||
let verdict = semConstExpr(c, n[i])
|
||||
|
||||
@@ -1235,7 +1235,7 @@ proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym =
|
||||
if n.kind == nkType:
|
||||
result = symFromType(n.typ, n.info)
|
||||
else:
|
||||
localError(n.info, "xx")
|
||||
localError(n.info, errTypeExpected)
|
||||
result = errorSym(c, n)
|
||||
|
||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
|
||||
@@ -22,10 +22,10 @@ type
|
||||
TCandidateState* = enum
|
||||
csEmpty, csMatch, csNoMatch
|
||||
|
||||
CandidateError = tuple
|
||||
sym: PSym
|
||||
unmatchedVarParam: int
|
||||
diagnostics: seq[string]
|
||||
CandidateError* = object
|
||||
sym*: PSym
|
||||
unmatchedVarParam*: int
|
||||
diagnostics*: seq[string]
|
||||
|
||||
CandidateErrors* = seq[CandidateError]
|
||||
|
||||
@@ -589,8 +589,8 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
|
||||
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
ff, a: PType): PType =
|
||||
var
|
||||
Concept = ff.skipTypes({tyUserTypeClassInst})
|
||||
body = Concept.n[3]
|
||||
typeClass = ff.skipTypes({tyUserTypeClassInst})
|
||||
body = typeClass.n[3]
|
||||
if c.inTypeClass > 4:
|
||||
localError(body.info, $body & " too nested for type matching")
|
||||
return nil
|
||||
@@ -611,7 +611,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
param: PSym
|
||||
|
||||
template paramSym(kind): untyped =
|
||||
newSym(kind, typeParamName, Concept.sym, Concept.sym.info)
|
||||
newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info)
|
||||
|
||||
block addTypeParam:
|
||||
for prev in typeParams:
|
||||
@@ -642,7 +642,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
|
||||
addDecl(c, param)
|
||||
|
||||
for param in Concept.n[0]:
|
||||
for param in typeClass.n[0]:
|
||||
var
|
||||
dummyName: PNode
|
||||
dummyType: PType
|
||||
@@ -665,7 +665,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
|
||||
internalAssert dummyName.kind == nkIdent
|
||||
var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
|
||||
dummyName.ident, Concept.sym, Concept.sym.info)
|
||||
dummyName.ident, typeClass.sym, typeClass.sym.info)
|
||||
dummyParam.typ = dummyType
|
||||
addDecl(c, dummyParam)
|
||||
|
||||
@@ -675,7 +675,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
errorPrefix: string
|
||||
flags: TExprFlags = {}
|
||||
collectDiagnostics = m.diagnostics != nil or
|
||||
sfExplain in Concept.sym.flags
|
||||
sfExplain in typeClass.sym.flags
|
||||
|
||||
if collectDiagnostics:
|
||||
oldWriteHook = writelnHook
|
||||
@@ -684,7 +684,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
diagnostics = @[]
|
||||
flags = {efExplain}
|
||||
writelnHook = proc (s: string) =
|
||||
if errorPrefix == nil: errorPrefix = Concept.sym.name.s & ":"
|
||||
if errorPrefix == nil: errorPrefix = typeClass.sym.name.s & ":"
|
||||
let msg = s.replace("Error:", errorPrefix)
|
||||
if oldWriteHook != nil: oldWriteHook msg
|
||||
diagnostics.add msg
|
||||
@@ -704,7 +704,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
put(m, p[1], p[0].typ)
|
||||
|
||||
if ff.kind == tyUserTypeClassInst:
|
||||
result = generateTypeInstance(c, m.bindings, Concept.sym.info, ff)
|
||||
result = generateTypeInstance(c, m.bindings, typeClass.sym.info, ff)
|
||||
else:
|
||||
result = copyType(ff, ff.owner, true)
|
||||
|
||||
|
||||
@@ -197,9 +197,6 @@ supply all type parameters of the generic type, because any missing ones will
|
||||
be inferred to have the equivalent of the `any` type class and thus they will
|
||||
match anything without discrimination.
|
||||
|
||||
To help you write more concise implicitly generic procs, the Nim's system
|
||||
module includes the named types `T1` through `T9` which are bind once aliases
|
||||
of the `auto` type.
|
||||
|
||||
Concepts
|
||||
--------
|
||||
@@ -436,17 +433,35 @@ in the place of each missing generic param.
|
||||
Please note that generic concepts such as `Enumerable[T]` can be matched
|
||||
against concrete types such as `string`. Nim doesn't require the concept
|
||||
type to have the same number of parameters as the type being matched.
|
||||
In order to express such a requirement, you'll need to rely on a type
|
||||
mapping operator such a `genericHead` or `stripGenericParams` within the
|
||||
concept body:
|
||||
If you wish to express a requirement towards the generic parameters of
|
||||
the matched type, you can use a type mapping operator such as `genericHead`
|
||||
or `stripGenericParams` within the body of the concept to obtain the
|
||||
uninstantiated version of the type, which you can then try to instantiate
|
||||
in any required way. For example, here is how one might define the classic
|
||||
`Functor` concept from Haskell and then demonstrate that Nim's `Option[T]`
|
||||
type is an instance of it:
|
||||
|
||||
.. code-block:: nim
|
||||
import future, typetraits
|
||||
|
||||
type
|
||||
Functor[A] = concept f
|
||||
f.value is A
|
||||
map(f, A -> T1) is genericHead(f.type)[T1]
|
||||
type MatchedGenericType = genericHead(f.type)
|
||||
# `f` will be a value of a type such as `Option[T]`
|
||||
# `MatchedGenericType` will become the `Option` type
|
||||
|
||||
f.val is A
|
||||
# The Functor should provide a way to obtain
|
||||
# a value stored inside it
|
||||
|
||||
type T = auto
|
||||
map(f, A -> T) is MatchedGenericType[T]
|
||||
# And it should provide a way to map one instance of
|
||||
# the Functor to a instance of a different type, given
|
||||
# a suitable `map` operation for the enclosed values
|
||||
|
||||
import options
|
||||
echo Option[int] is Functor # prints true
|
||||
|
||||
|
||||
Concept derived values
|
||||
|
||||
@@ -98,17 +98,6 @@ type
|
||||
SomeNumber* = SomeInteger|SomeReal
|
||||
## type class matching all number types
|
||||
|
||||
T1* = auto
|
||||
T2* = auto
|
||||
T3* = auto
|
||||
T4* = auto
|
||||
T5* = auto
|
||||
T6* = auto
|
||||
T7* = auto
|
||||
T8* = auto
|
||||
T9* = auto
|
||||
## Helper types for writing implicitly generic procs
|
||||
|
||||
proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.}
|
||||
## Special compile-time procedure that checks whether `x` is
|
||||
## defined.
|
||||
|
||||
Reference in New Issue
Block a user