Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/commands.nim
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,10 @@ proc pathRelativeToConfig(arg: string, pass: TCmdLinePass, conf: ConfigRef): str

proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf: ConfigRef) =
if conf.skipParentDetectionMode:
if switch.normalize == "skipparentcfg":
processOnOffSwitchG(conf, {optSkipParentConfigFiles}, arg, pass, info)
return
var key = ""
var val = ""
case switch.normalize
Expand Down
15 changes: 15 additions & 0 deletions compiler/concepts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,19 @@ proc conceptsMatch(c: PContext, fc, ac: PType; m: var MatchCon): MatchKind =
return mkNoMatch
return mkSubset


proc isObjectSubtype(a, f: PType): bool =
assert a.kind == tyObject
var t = a.baseClass
var last = a.baseClass
while t != nil and not sameObjectTypes(f, t):
if t.kind != tyObject: # avoid entering generic params etc
return false
t = t.baseClass
if t == nil:
return false
t != nil

proc matchType(c: PContext; fo, ao: PType; m: var MatchCon): bool =
## The heart of the concept matching process. 'f' is the formal parameter of some
## routine inside the concept that we're looking for. 'a' is the formal parameter
Expand Down Expand Up @@ -327,6 +340,8 @@ proc matchType(c: PContext; fo, ao: PType; m: var MatchCon): bool =
result = a.base.sym == f.sym
else:
result = sameType(f, a)
if not(result) and f.kind == tyObject:
result = isObjectSubtype(f, a)
of tyEmpty, tyString, tyCstring, tyPointer, tyNil, tyUntyped, tyTyped, tyVoid:
result = a.skipTypes(ignorableForArgType).kind == f.kind
of tyBool, tyChar, tyInt..tyUInt64:
Expand Down
78 changes: 60 additions & 18 deletions compiler/nimconf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -128,28 +128,32 @@ proc parseDirective(L: var Lexer, tok: var Token; config: ConfigRef; condStack:
of wEnd: doEnd(L, tok, condStack)
of wWrite:
ppGetTok(L, tok)
msgs.msgWriteln(config, strtabs.`%`($tok, config.configVars,
{useEnvironment, useKey}))
if not config.skipParentDetectionMode:
msgs.msgWriteln(config, strtabs.`%`($tok, config.configVars,
{useEnvironment, useKey}))
ppGetTok(L, tok)
else:
case tok.ident.s.normalize
of "putenv":
ppGetTok(L, tok)
var key = $tok
ppGetTok(L, tok)
os.putEnv(key, $tok)
if not config.skipParentDetectionMode:
os.putEnv(key, $tok)
ppGetTok(L, tok)
of "prependenv":
ppGetTok(L, tok)
var key = $tok
ppGetTok(L, tok)
os.putEnv(key, $tok & os.getEnv(key))
if not config.skipParentDetectionMode:
os.putEnv(key, $tok & os.getEnv(key))
ppGetTok(L, tok)
of "appendenv":
ppGetTok(L, tok)
var key = $tok
ppGetTok(L, tok)
os.putEnv(key, os.getEnv(key) & $tok)
if not config.skipParentDetectionMode:
os.putEnv(key, os.getEnv(key) & $tok)
ppGetTok(L, tok)
else:
lexMessage(L, errGenerated, "invalid directive: '$1'" % $tok)
Expand Down Expand Up @@ -214,11 +218,14 @@ proc parseAssignment(L: var Lexer, tok: var Token;
processSwitch(s, val, passPP, info, config)

proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
config: ConfigRef): bool =
config: ConfigRef, dryrun=false): bool =
var
L: Lexer = default(Lexer)
tok: Token
stream: PLLStream
if dryrun:
L.errorHandler = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
discard
stream = llStreamOpen(filename, fmRead)
if stream != nil:
openLexer(L, filename, stream, cache, config)
Expand All @@ -244,6 +251,21 @@ proc getSystemConfigPath*(conf: ConfigRef; filename: RelativeFile): AbsoluteFile
if not fileExists(result): result = p / RelativeDir"etc/nim" / filename
if not fileExists(result): result = AbsoluteDir"/etc/nim" / filename

proc configEnablesSkipParent(conf: ConfigRef; cache: IdentCache;
cfgPath: AbsoluteFile): bool =
let prevMode = conf.skipParentDetectionMode
let prevSkip = optSkipParentConfigFiles in conf.globalOptions
conf.skipParentDetectionMode = true
try:
result = readConfigFile(cfgPath, cache, conf, dryrun=true) and
optSkipParentConfigFiles in conf.globalOptions
finally:
conf.skipParentDetectionMode = prevMode
if prevSkip:
incl(conf.globalOptions, optSkipParentConfigFiles)
else:
excl(conf.globalOptions, optSkipParentConfigFiles)

proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: IdGenerator) =
setDefaultLibpath(conf)
template readConfigFile(path) =
Expand Down Expand Up @@ -275,28 +297,48 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen:

if cfg == DefaultConfig:
runNimScriptIfExists(getUserConfigPath(DefaultConfigNims))

let pd = if not conf.projectPath.isEmpty: conf.projectPath else: AbsoluteDir(getCurrentDir())
if optSkipParentConfigFiles notin conf.globalOptions:
for dir in parentDirs(pd.string, fromRoot=true, inclusive=false):
readConfigFile(AbsoluteDir(dir) / cfg)


var
hasProjectCfg = conf.projectName.len != 0
projectConfig = AbsoluteFile ""
if hasProjectCfg:
projectConfig = changeFileExt(conf.projectFull, "nimcfg")
if not fileExists(projectConfig):
projectConfig = changeFileExt(conf.projectFull, "nim.cfg")
if not fileExists(projectConfig):
hasProjectCfg = false

let pd = if conf.projectPath.isEmpty: AbsoluteDir(getCurrentDir()) else: conf.projectPath
if optSkipParentConfigFiles notin conf.globalOptions and
not configEnablesSkipParent(conf, cache, pd / cfg) and
not(hasProjectCfg and configEnablesSkipParent(conf, cache, projectConfig)):
var parentDirs: seq[tuple[path: AbsoluteDir, hasNs: bool]] = @[]
for dir in parentDirs(pd.string, inclusive=false):
var thisReg = (path: AbsoluteDir(dir), hasNs: false)
let cfgPath = thisReg.path / cfg
if cfg == DefaultConfig:
runNimScriptIfExists(AbsoluteDir(dir) / DefaultConfigNims)
thisReg.hasNs = fileExists(thisReg.path / DefaultConfigNims)
if not (thisReg.hasNs or fileExists(cfgPath)):
continue
parentDirs.add thisReg
if configEnablesSkipParent(conf, cache, cfgPath):
break

for i in countdown(parentDirs.len - 1, 0):
let thisReg = parentDirs[i]
readConfigFile(thisReg.path / cfg)
if thisReg.hasNs:
runNimScriptIfExists(thisReg.path / DefaultConfigNims)

if optSkipProjConfigFile notin conf.globalOptions:
readConfigFile(pd / cfg)
if cfg == DefaultConfig:
runNimScriptIfExists(pd / DefaultConfigNims)

if conf.projectName.len != 0:
if hasProjectCfg:
# new project wide config file:
var projectConfig = changeFileExt(conf.projectFull, "nimcfg")
if not fileExists(projectConfig):
projectConfig = changeFileExt(conf.projectFull, "nim.cfg")
readConfigFile(projectConfig)


let scriptFile = conf.projectFull.changeFileExt("nims")
let scriptIsProj = scriptFile == conf.projectFull
template showHintConf =
Expand Down
1 change: 1 addition & 0 deletions compiler/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ type
expandPosition*: TLineInfo

currentConfigDir*: string # used for passPP only; absolute dir
skipParentDetectionMode*: bool # true while probing configs for skipParentCfg
clientProcessId*: int


Expand Down