semobjconstr.nim 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Nim Contributors
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements Nim's object construction rules.
  10. # included from sem.nim
  11. from std/sugar import dup
  12. type
  13. ObjConstrContext = object
  14. typ: PType # The constructed type
  15. initExpr: PNode # The init expression (nkObjConstr)
  16. needsFullInit: bool # A `requiresInit` derived type will
  17. # set this to true while visiting
  18. # parent types.
  19. missingFields: seq[PSym] # Fields that the user failed to specify
  20. checkDefault: bool # Checking defaults
  21. InitStatus = enum # This indicates the result of object construction
  22. initUnknown
  23. initFull # All of the fields have been initialized
  24. initPartial # Some of the fields have been initialized
  25. initNone # None of the fields have been initialized
  26. initConflict # Fields from different branches have been initialized
  27. proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
  28. flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]]
  29. proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) =
  30. case newStatus
  31. of initConflict:
  32. existing = newStatus
  33. of initPartial:
  34. if existing in {initUnknown, initFull, initNone}:
  35. existing = initPartial
  36. of initNone:
  37. if existing == initUnknown:
  38. existing = initNone
  39. elif existing == initFull:
  40. existing = initPartial
  41. of initFull:
  42. if existing == initUnknown:
  43. existing = initFull
  44. elif existing == initNone:
  45. existing = initPartial
  46. of initUnknown:
  47. discard
  48. proc invalidObjConstr(c: PContext, n: PNode) =
  49. if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s[0] == ':':
  50. localError(c.config, n.info, "incorrect object construction syntax; use a space after the colon")
  51. else:
  52. localError(c.config, n.info, "incorrect object construction syntax")
  53. proc locateFieldInInitExpr(c: PContext, field: PSym, initExpr: PNode): PNode =
  54. # Returns the assignment nkExprColonExpr node or nil
  55. result = nil
  56. let fieldId = field.name.id
  57. for i in 1..<initExpr.len:
  58. let assignment = initExpr[i]
  59. if assignment.kind != nkExprColonExpr:
  60. invalidObjConstr(c, assignment)
  61. elif fieldId == considerQuotedIdent(c, assignment[0]).id:
  62. return assignment
  63. proc semConstrField(c: PContext, flags: TExprFlags,
  64. field: PSym, initExpr: PNode): PNode =
  65. let assignment = locateFieldInInitExpr(c, field, initExpr)
  66. if assignment != nil:
  67. if nfSem in assignment.flags: return assignment[1]
  68. if nfSkipFieldChecking in assignment[1].flags:
  69. discard
  70. elif not fieldVisible(c, field):
  71. localError(c.config, initExpr.info,
  72. "the field '$1' is not accessible." % [field.name.s])
  73. return
  74. var initValue = semExprFlagDispatched(c, assignment[1], flags, field.typ)
  75. if initValue != nil:
  76. initValue = fitNodeConsiderViewType(c, field.typ, initValue, assignment.info)
  77. initValue.flags.incl nfSkipFieldChecking
  78. assignment[0] = newSymNode(field)
  79. assignment[1] = initValue
  80. assignment.flags.incl nfSem
  81. result = initValue
  82. else:
  83. result = nil
  84. proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
  85. isStmtBranch: bool): IntSet =
  86. if caseNode[caseIdx].kind == nkOfBranch:
  87. result = initIntSet()
  88. for val in processBranchVals(caseNode[caseIdx]):
  89. result.incl(val)
  90. else:
  91. result = c.getIntSetOfType(caseNode[0].typ)
  92. for i in 1..<caseNode.len-1:
  93. for val in processBranchVals(caseNode[i]):
  94. result.excl(val)
  95. proc findUsefulCaseContext(c: PContext, discrimator: PNode): (PNode, int) =
  96. result = (nil, 0)
  97. for i in countdown(c.p.caseContext.high, 0):
  98. let
  99. (caseNode, index) = c.p.caseContext[i]
  100. skipped = caseNode[0].skipHidden
  101. if skipped.kind == nkSym and skipped.sym == discrimator.sym:
  102. return (caseNode, index)
  103. proc pickCaseBranch(caseExpr, matched: PNode): PNode =
  104. # XXX: Perhaps this proc already exists somewhere
  105. let endsWithElse = caseExpr[^1].kind == nkElse
  106. for i in 1..<caseExpr.len - int(endsWithElse):
  107. if caseExpr[i].caseBranchMatchesExpr(matched):
  108. return caseExpr[i]
  109. if endsWithElse:
  110. result = caseExpr[^1]
  111. else:
  112. result = nil
  113. iterator directFieldsInRecList(recList: PNode): PNode =
  114. # XXX: We can remove this case by making all nkOfBranch nodes
  115. # regular. Currently, they try to avoid using nkRecList if they
  116. # include only a single field
  117. if recList.kind == nkSym:
  118. yield recList
  119. else:
  120. doAssert recList.kind == nkRecList
  121. for field in recList:
  122. if field.kind == nkSym:
  123. yield field
  124. template quoteStr(s: string): string = "'" & s & "'"
  125. proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): string =
  126. result = ""
  127. for field in directFieldsInRecList(fieldsRecList):
  128. if locateFieldInInitExpr(c, field.sym, initExpr) != nil:
  129. if result.len != 0: result.add ", "
  130. result.add field.sym.name.s.quoteStr
  131. proc locateFieldInDefaults(sym: PSym, defaults: seq[PNode]): bool =
  132. result = false
  133. for d in defaults:
  134. if sym.id == d[0].sym.id:
  135. return true
  136. proc collectMissingFields(c: PContext, fieldsRecList: PNode,
  137. constrCtx: var ObjConstrContext, defaults: seq[PNode]
  138. ): seq[PSym] =
  139. result = @[]
  140. for r in directFieldsInRecList(fieldsRecList):
  141. let assignment = locateFieldInInitExpr(c, r.sym, constrCtx.initExpr)
  142. if assignment == nil and not locateFieldInDefaults(r.sym, defaults):
  143. if constrCtx.needsFullInit or
  144. sfRequiresInit in r.sym.flags or
  145. r.sym.typ.requiresInit:
  146. constrCtx.missingFields.add r.sym
  147. else:
  148. result.add r.sym
  149. proc collectMissingCaseFields(c: PContext, branchNode: PNode,
  150. constrCtx: var ObjConstrContext, defaults: seq[PNode]): seq[PSym] =
  151. if branchNode != nil:
  152. let fieldsRecList = branchNode[^1]
  153. result = collectMissingFields(c, fieldsRecList, constrCtx, defaults)
  154. else:
  155. result = @[]
  156. proc collectOrAddMissingCaseFields(c: PContext, branchNode: PNode,
  157. constrCtx: var ObjConstrContext, defaults: var seq[PNode]) =
  158. let res = collectMissingCaseFields(c, branchNode, constrCtx, defaults)
  159. for sym in res:
  160. let asgnType = newType(tyTypeDesc, c.idgen, sym.typ.owner)
  161. let recTyp = sym.typ.skipTypes(defaultFieldsSkipTypes)
  162. rawAddSon(asgnType, recTyp)
  163. let asgnExpr = newTree(nkCall,
  164. newSymNode(getSysMagic(c.graph, constrCtx.initExpr.info, "zeroDefault", mZeroDefault)),
  165. newNodeIT(nkType, constrCtx.initExpr.info, asgnType)
  166. )
  167. asgnExpr.flags.incl nfSkipFieldChecking
  168. asgnExpr.typ = recTyp
  169. defaults.add newTree(nkExprColonExpr, newSymNode(sym), asgnExpr)
  170. proc collectBranchFields(c: PContext, n: PNode, discriminatorVal: PNode,
  171. constrCtx: var ObjConstrContext, flags: TExprFlags) =
  172. # All bets are off. If any of the branches has a mandatory
  173. # fields we must produce an error:
  174. for i in 1..<n.len:
  175. let branchNode = n[i]
  176. if branchNode != nil:
  177. let oldCheckDefault = constrCtx.checkDefault
  178. constrCtx.checkDefault = true
  179. let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags)
  180. constrCtx.checkDefault = oldCheckDefault
  181. if len(defaults) > 0:
  182. localError(c.config, discriminatorVal.info, "branch initialization " &
  183. "with a runtime discriminator is not supported " &
  184. "for a branch whose fields have default values.")
  185. discard collectMissingCaseFields(c, n[i], constrCtx, @[])
  186. proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
  187. flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
  188. result = (initUnknown, @[])
  189. case n.kind
  190. of nkRecList:
  191. for field in n:
  192. let (subSt, subDf) = semConstructFields(c, field, constrCtx, flags)
  193. result.status.mergeInitStatus subSt
  194. result.defaults.add subDf
  195. of nkRecCase:
  196. template fieldsPresentInBranch(branchIdx: int): string =
  197. let branch = n[branchIdx]
  198. let fields = branch[^1]
  199. fieldsPresentInInitExpr(c, fields, constrCtx.initExpr)
  200. let discriminator = n[0]
  201. internalAssert c.config, discriminator.kind == nkSym
  202. var selectedBranch = -1
  203. for i in 1..<n.len:
  204. let innerRecords = n[i][^1]
  205. let (status, _) = semConstructFields(c, innerRecords, constrCtx, flags) # todo
  206. if status notin {initNone, initUnknown}:
  207. result.status.mergeInitStatus status
  208. if selectedBranch != -1:
  209. let prevFields = fieldsPresentInBranch(selectedBranch)
  210. let currentFields = fieldsPresentInBranch(i)
  211. localError(c.config, constrCtx.initExpr.info,
  212. ("The fields '$1' and '$2' cannot be initialized together, " &
  213. "because they are from conflicting branches in the case object.") %
  214. [prevFields, currentFields])
  215. result.status = initConflict
  216. else:
  217. selectedBranch = i
  218. if selectedBranch != -1:
  219. template badDiscriminatorError =
  220. if c.inUncheckedAssignSection == 0:
  221. let fields = fieldsPresentInBranch(selectedBranch)
  222. localError(c.config, constrCtx.initExpr.info,
  223. ("cannot prove that it's safe to initialize $1 with " &
  224. "the runtime value for the discriminator '$2' ") %
  225. [fields, discriminator.sym.name.s])
  226. mergeInitStatus(result.status, initNone)
  227. template wrongBranchError(i) =
  228. if c.inUncheckedAssignSection == 0:
  229. let fields = fieldsPresentInBranch(i)
  230. localError(c.config, constrCtx.initExpr.info,
  231. ("a case selecting discriminator '$1' with value '$2' " &
  232. "appears in the object construction, but the field(s) $3 " &
  233. "are in conflict with this value.") %
  234. [discriminator.sym.name.s, discriminatorVal.renderTree, fields])
  235. template valuesInConflictError(valsDiff) =
  236. localError(c.config, discriminatorVal.info, ("possible values " &
  237. "$2 are in conflict with discriminator values for " &
  238. "selected object branch $1.") % [$selectedBranch,
  239. valsDiff.renderAsType(n[0].typ)])
  240. let branchNode = n[selectedBranch]
  241. let flags = {efPreferStatic, efPreferNilResult}
  242. var discriminatorVal = semConstrField(c, flags,
  243. discriminator.sym,
  244. constrCtx.initExpr)
  245. if discriminatorVal != nil:
  246. discriminatorVal = discriminatorVal.skipHidden
  247. if discriminatorVal.kind notin nkLiterals and (
  248. not isOrdinalType(discriminatorVal.typ, true) or
  249. lengthOrd(c.config, discriminatorVal.typ) > MaxSetElements or
  250. lengthOrd(c.config, n[0].typ) > MaxSetElements):
  251. localError(c.config, discriminatorVal.info,
  252. "branch initialization with a runtime discriminator only " &
  253. "supports ordinal types with 2^16 elements or less.")
  254. if discriminatorVal == nil:
  255. badDiscriminatorError()
  256. elif discriminatorVal.kind == nkSym:
  257. let (ctorCase, ctorIdx) = findUsefulCaseContext(c, discriminatorVal)
  258. if ctorCase == nil:
  259. if discriminatorVal.typ.kind == tyRange:
  260. let rangeVals = c.getIntSetOfType(discriminatorVal.typ)
  261. let recBranchVals = branchVals(c, n, selectedBranch, false)
  262. let diff = rangeVals - recBranchVals
  263. if diff.len != 0:
  264. valuesInConflictError(diff)
  265. else:
  266. badDiscriminatorError()
  267. elif discriminatorVal.sym.kind notin {skLet, skParam} or
  268. discriminatorVal.sym.typ.kind in {tyVar}:
  269. if c.inUncheckedAssignSection == 0:
  270. localError(c.config, discriminatorVal.info,
  271. "runtime discriminator must be immutable if branch fields are " &
  272. "initialized, a 'let' binding is required.")
  273. elif ctorCase[ctorIdx].kind == nkElifBranch:
  274. localError(c.config, discriminatorVal.info, "branch initialization " &
  275. "with a runtime discriminator is not supported inside of an " &
  276. "`elif` branch.")
  277. else:
  278. var
  279. ctorBranchVals = branchVals(c, ctorCase, ctorIdx, true)
  280. recBranchVals = branchVals(c, n, selectedBranch, false)
  281. branchValsDiff = ctorBranchVals - recBranchVals
  282. if branchValsDiff.len != 0:
  283. valuesInConflictError(branchValsDiff)
  284. else:
  285. var failedBranch = -1
  286. if branchNode.kind != nkElse:
  287. if not branchNode.caseBranchMatchesExpr(discriminatorVal):
  288. failedBranch = selectedBranch
  289. else:
  290. # With an else clause, check that all other branches don't match:
  291. for i in 1..<n.len - 1:
  292. if n[i].caseBranchMatchesExpr(discriminatorVal):
  293. failedBranch = i
  294. break
  295. if failedBranch != -1:
  296. if discriminatorVal.typ.kind == tyRange:
  297. let rangeVals = c.getIntSetOfType(discriminatorVal.typ)
  298. let recBranchVals = branchVals(c, n, selectedBranch, false)
  299. let diff = rangeVals - recBranchVals
  300. if diff.len != 0:
  301. valuesInConflictError(diff)
  302. else:
  303. wrongBranchError(failedBranch)
  304. let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags)
  305. result.defaults.add defaults
  306. # When a branch is selected with a partial match, some of the fields
  307. # that were not initialized may be mandatory. We must check for this:
  308. if result.status == initPartial:
  309. collectOrAddMissingCaseFields(c, branchNode, constrCtx, result.defaults)
  310. else:
  311. result.status = initNone
  312. let discriminatorVal = semConstrField(c, flags + {efPreferStatic},
  313. discriminator.sym,
  314. constrCtx.initExpr)
  315. if discriminatorVal == nil:
  316. if discriminator.sym.ast != nil:
  317. # branch is selected by the default field value of discriminator
  318. let discriminatorDefaultVal = discriminator.sym.ast
  319. result.status = initUnknown
  320. result.defaults.add newTree(nkExprColonExpr, n[0], discriminatorDefaultVal)
  321. if discriminatorDefaultVal.kind == nkIntLit:
  322. let matchedBranch = n.pickCaseBranch discriminatorDefaultVal
  323. if matchedBranch != nil:
  324. let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags)
  325. result.defaults.add defaults
  326. collectOrAddMissingCaseFields(c, matchedBranch, constrCtx, result.defaults)
  327. else:
  328. collectBranchFields(c, n, discriminatorDefaultVal, constrCtx, flags)
  329. else:
  330. # None of the branches were explicitly selected by the user and no
  331. # value was given to the discrimator. We can assume that it will be
  332. # initialized to zero and this will select a particular branch as
  333. # a result:
  334. let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0)
  335. let matchedBranch = n.pickCaseBranch defaultValue
  336. discard collectMissingCaseFields(c, matchedBranch, constrCtx, @[])
  337. else:
  338. result.status = initPartial
  339. if discriminatorVal.kind == nkIntLit:
  340. # When the discriminator is a compile-time value, we also know
  341. # which branch will be selected:
  342. let matchedBranch = n.pickCaseBranch discriminatorVal
  343. if matchedBranch != nil:
  344. let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags)
  345. result.defaults.add defaults
  346. collectOrAddMissingCaseFields(c, matchedBranch, constrCtx, result.defaults)
  347. else:
  348. collectBranchFields(c, n, discriminatorVal, constrCtx, flags)
  349. of nkSym:
  350. let field = n.sym
  351. let e = semConstrField(c, flags, field, constrCtx.initExpr)
  352. if e != nil:
  353. result.status = initFull
  354. elif field.ast != nil:
  355. result.status = initUnknown
  356. result.defaults.add newTree(nkExprColonExpr, n, field.ast)
  357. else:
  358. if efWantNoDefaults notin flags: # cannot compute defaults at the typeRightPass
  359. let defaultExpr = defaultNodeField(c, n, constrCtx.checkDefault)
  360. if defaultExpr != nil:
  361. result.status = initUnknown
  362. result.defaults.add newTree(nkExprColonExpr, n, defaultExpr)
  363. else:
  364. result.status = initNone
  365. else:
  366. result.status = initNone
  367. else:
  368. internalAssert c.config, false
  369. proc semConstructTypeAux(c: PContext,
  370. constrCtx: var ObjConstrContext,
  371. flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
  372. result = (initUnknown, @[])
  373. var t = constrCtx.typ
  374. while true:
  375. let (status, defaults) = semConstructFields(c, t.n, constrCtx, flags)
  376. result.status.mergeInitStatus status
  377. result.defaults.add defaults
  378. if status in {initPartial, initNone, initUnknown}:
  379. discard collectMissingFields(c, t.n, constrCtx, result.defaults)
  380. let base = t.baseClass
  381. if base == nil or base.id == t.id or
  382. base.kind in {tyRef, tyPtr} and base.elementType.id == t.id:
  383. break
  384. t = skipTypes(base, skipPtrs)
  385. if t.kind != tyObject:
  386. # XXX: This is not supposed to happen, but apparently
  387. # there are some issues in semtypinst. Luckily, it
  388. # seems to affect only `computeRequiresInit`.
  389. return
  390. constrCtx.needsFullInit = constrCtx.needsFullInit or
  391. tfNeedsFullInit in t.flags
  392. proc initConstrContext(t: PType, initExpr: PNode): ObjConstrContext =
  393. ObjConstrContext(typ: t, initExpr: initExpr,
  394. needsFullInit: tfNeedsFullInit in t.flags)
  395. proc computeRequiresInit(c: PContext, t: PType): bool =
  396. assert t.kind == tyObject
  397. var constrCtx = initConstrContext(t, newNode(nkObjConstr))
  398. let initResult = semConstructTypeAux(c, constrCtx, {efWantNoDefaults})
  399. constrCtx.missingFields.len > 0
  400. proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
  401. var objType = t
  402. while objType.kind notin {tyObject, tyDistinct}:
  403. objType = objType.last
  404. assert objType != nil
  405. if objType.kind == tyObject:
  406. var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
  407. let initResult = semConstructTypeAux(c, constrCtx, {efWantNoDefaults})
  408. if constrCtx.missingFields.len > 0:
  409. localError(c.config, info,
  410. "The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])
  411. elif objType.kind == tyDistinct:
  412. localError(c.config, info,
  413. "The $1 distinct type doesn't have a default value." % typeToString(t))
  414. else:
  415. assert false, "Must not enter here."
  416. proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
  417. var t = semTypeNode(c, n[0], nil)
  418. result = newNodeIT(nkObjConstr, n.info, t)
  419. for i in 0..<n.len:
  420. result.add n[i]
  421. if t == nil:
  422. return localErrorNode(c, result, "object constructor needs an object type")
  423. if t.skipTypes({tyGenericInst,
  424. tyAlias, tySink, tyOwned, tyRef}).kind != tyObject and
  425. expectedType != nil and expectedType.skipTypes({tyGenericInst,
  426. tyAlias, tySink, tyOwned, tyRef}).kind == tyObject:
  427. t = expectedType
  428. t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned})
  429. if t.kind == tyRef:
  430. t = skipTypes(t.elementType, {tyGenericInst, tyAlias, tySink, tyOwned})
  431. if optOwnedRefs in c.config.globalOptions:
  432. result.typ = makeVarType(c, result.typ, tyOwned)
  433. # we have to watch out, there are also 'owned proc' types that can be used
  434. # multiple times as long as they don't have closures.
  435. result.typ.flags.incl tfHasOwned
  436. if t.kind != tyObject:
  437. return localErrorNode(c, result, if t.kind != tyGenericBody:
  438. "object constructor needs an object type".dup(addTypeNodeDeclaredLoc(c.config, t))
  439. else: "cannot instantiate: '" &
  440. typeToString(t, preferDesc) &
  441. "'; the object's generic parameters cannot be inferred and must be explicitly given"
  442. )
  443. # Check if the object is fully initialized by recursively testing each
  444. # field (if this is a case object, initialized fields in two different
  445. # branches will be reported as an error):
  446. var constrCtx = initConstrContext(t, result)
  447. let (initResult, defaults) = semConstructTypeAux(c, constrCtx, flags)
  448. var hasError = false # needed to split error detect/report for better msgs
  449. # It's possible that the object was not fully initialized while
  450. # specifying a .requiresInit. pragma:
  451. if constrCtx.missingFields.len > 0:
  452. hasError = true
  453. localError(c.config, result.info,
  454. "The $1 type requires the following fields to be initialized: $2." %
  455. [t.sym.name.s, listSymbolNames(constrCtx.missingFields)])
  456. # Since we were traversing the object fields, it's possible that
  457. # not all of the fields specified in the constructor was visited.
  458. # We'll check for such fields here:
  459. for i in 1..<result.len:
  460. let field = result[i]
  461. if nfSem notin field.flags:
  462. if field.kind != nkExprColonExpr:
  463. invalidObjConstr(c, field)
  464. hasError = true
  465. continue
  466. let id = considerQuotedIdent(c, field[0])
  467. # This node was not processed. There are two possible reasons:
  468. # 1) It was shadowed by a field with the same name on the left
  469. for j in 1..<i:
  470. let prevId = considerQuotedIdent(c, result[j][0])
  471. if prevId.id == id.id:
  472. localError(c.config, field.info, errFieldInitTwice % id.s)
  473. hasError = true
  474. break
  475. # 2) No such field exists in the constructed type
  476. let msg = errUndeclaredField % id.s & " for type " & getProcHeader(c.config, t.sym)
  477. localError(c.config, field.info, msg)
  478. hasError = true
  479. break
  480. result.sons.add defaults
  481. if initResult == initFull:
  482. incl result.flags, nfAllFieldsSet
  483. # wrap in an error see #17437
  484. if hasError: result = errorNode(c, result)