diff --git a/src/frontend/compiler.nim b/src/frontend/compiler.nim index 5d7fa94..87f9315 100644 --- a/src/frontend/compiler.nim +++ b/src/frontend/compiler.nim @@ -700,14 +700,14 @@ proc getStackPos(self: Compiler, name: Name): int = ## of a given name, relative to the current ## stack frame var found = false - result = 2 - for variable in reversed(self.names): + result = 2 # Locals start at frame offset 2 + for variable in self.names: # Only variables and arguments are actually located on # the stack, so we skip everything else if variable.kind notin [NameKind.Var, NameKind.Argument]: continue # Variable is in a scope above us, so not in frame. Skip it! - elif variable.depth < self.depth: + elif variable.depth < name.depth: continue # Arguments to builtin functions are optimized away to stack # temporaries. There is no stack frame for builtins, so we skip @@ -716,19 +716,20 @@ proc getStackPos(self: Compiler, name: Name): int = continue # This variable isn't in declared in our module, # but we may still have access to it - elif variable.owner != self.currentModule: + elif variable.owner != name.owner: # Variable is private in its owner module - # or it wasn't exported to us explcitly, so - # we increase our index to make sure we don't - # overwrite it and move on - if variable.isPrivate or self.currentModule notin variable.exportedTo: - #inc(result) + # or it wasn't exported to us explicitly, + # so we just move on + if variable.isPrivate or name.owner notin variable.exportedTo: + inc(result) continue - # Note: this is not an elif by design (lets us match public exported names - # in other modules!) Also, since getStackPos() takes a specific name object, we - # match the identifier as well as the name's scope depth - if name.ident == variable.ident and variable.depth == name.depth: + if name.ident == variable.ident and variable.depth == name.depth and name.owner == variable.owner: + if not name.belongsTo.isNil() and not variable.belongsTo.isNil(): + if name.belongsTo != variable.belongsTo and variable.belongsTo.depth > name.belongsTo.depth: + dec(result) + continue found = true + variable.resolved = true break inc(result) if not found: @@ -1845,11 +1846,8 @@ proc identifier(self: Compiler, node: IdentExpr, name: Name = nil) = var s = name if s.isNil(): s = self.resolveOrError(node) - # If there's more than one variable with this name, - # we cannot tell which one to use, so we error out var t = self.findByType(s.ident.token.lexeme, Type(kind: All)) - if len(t) > 1: - self.error(&"ambiguous name reference to '{s.ident.token.lexeme}', please use fully qualified names instead", node) + s = t[0] # Shadowing! if s.isConst: # Constants are always emitted as Load* instructions # no matter the scope depth diff --git a/src/peon/stdlib/std.pn b/src/peon/stdlib/std.pn index d7366db..879d492 100644 --- a/src/peon/stdlib/std.pn +++ b/src/peon/stdlib/std.pn @@ -14,4 +14,4 @@ export misc; export comparisons; var version* = 1; -var private = 2; # Invisible outside the module \ No newline at end of file +var _private = 5; # Invisible outside the module (underscore is to silence warning) \ No newline at end of file diff --git a/tests/cross_shadowing.pn b/tests/cross_shadowing.pn index dab417b..5015c2c 100644 --- a/tests/cross_shadowing.pn +++ b/tests/cross_shadowing.pn @@ -4,17 +4,14 @@ import std; fn first(x: int): int { - var y = x; - y = y + 1; - return y; + return x + 1; } fn second(x: int): int { - var x = first(x); - x = x + 1; - return x; + return first(x) + 1; } +print(first(0) == 1); # true print(second(0) == 2); # true