Skip to content

Commit

Permalink
Fixed consistent range variable shadowing in loop bodies
Browse files Browse the repository at this point in the history
When a range loop uses pre-declared variables, ensure their shadowed
names are used consistently throughout the loop body. Previously,
the loop's range variables would be correctly shadowed but usages
within the body would still use the original names.

Example fix:
  for k, _ = range strategies {
      strategies[k] = stayAtK(k + 1)   // k not shadowed in body
  }

Becomes:
  foreach (var (kΔ1, _) in strategies) {
      strategies[kΔ1] = stayAtK(kΔ1 + 1)   // k correctly shadowed
  }

The fix tracks shadowed range variable names and ensures they're
used consistently for all references within the loop scope.
  • Loading branch information
ritchiecarroll committed Jan 22, 2025
1 parent 1ed9bd9 commit 462229d
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ private static (score, bool) stay(score s) {
private delegate action strategy(score _);

private static strategy stayAtK(nint k) {
var sʗ1 = s;
return (score s) => {
if (sʗ1.thisTurn >= k) {
if (s.thisTurn >= k) {
return stay;
}
return roll;
Expand Down Expand Up @@ -94,7 +93,7 @@ private static @string ratioString(params ꓸꓸꓸnint valsʗp) {
private static void Main() {
var strategies = new slice<strategy>(win);
foreach (var (kΔ1, _) in strategies) {
strategies[k] = stayAtK(kΔ1 + 1);
strategies[kΔ1] = stayAtK(kΔ1 + 1);
}
var (wins, games) = roundRobin(strategies);
nint k = default!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private static void Main() {
Animal a = default!;
fmt.Printf("%T\n"u8, a);
foreach (var (_, aΔ1) in zoo) {
fmt.Println(a.Type(), "can", a.Swim());
fmt.Println(aΔ1.Type(), "can", aΔ1.Swim());
}
fmt.Printf("%T\n"u8, a);
ShowZoo(Ꮡzoo);
Expand Down
4 changes: 2 additions & 2 deletions src/go2cs/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
//"..\\Tests\\Behavioral\\InterfaceCasting",
//"..\\Tests\\Behavioral\\ForVariants",
//"..\\Tests\\Behavioral\\IfStatements\\IfStatements.go",
"..\\Tests\\Behavioral\\PointerToPointer",
//"..\\Tests\\Behavioral\\PointerToPointer",
//"..\\Tests\\Behavioral\\LambdaFunctions",
//"..\\Tests\\Behavioral\\FirstClassFunctions",
//"..\\Tests\\Behavioral\\RangeStatements",
"..\\Tests\\Behavioral\\RangeStatements",
//"..\\Tests\\Behavioral\\SpreadOperator",
//"..\\Tests\\Behavioral\\VariableCapture",
//"..\\Tests\\Behavioral\\TypeSwitch",
Expand Down
33 changes: 31 additions & 2 deletions src/go2cs/performVariableAnalysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -914,16 +914,45 @@ func (v *Visitor) performVariableAnalysis(funcDecl *ast.FuncDecl, signature *typ
reassignVar,
)

// Track the shadowed names of range variables
rangeVars := make(map[string]string)

// Process range variables and remember their shadowed names
if node.Key != nil {
processor.processIdent(getIdentifier(node.Key), node.Tok == token.DEFINE)
if keyIdent := getIdentifier(node.Key); keyIdent != nil {
processor.processIdent(keyIdent, node.Tok == token.DEFINE)
// Store any shadowed name that was created
if shadowName, ok := v.identNames[keyIdent]; ok {
rangeVars[keyIdent.Name] = shadowName
}
}
}
if node.Value != nil {
processor.processIdent(getIdentifier(node.Value), node.Tok == token.DEFINE)
if valueIdent := getIdentifier(node.Value); valueIdent != nil {
processor.processIdent(valueIdent, node.Tok == token.DEFINE)
// Store any shadowed name that was created
if shadowName, ok := v.identNames[valueIdent]; ok {
rangeVars[valueIdent.Name] = shadowName
}
}
}

tracker.processing = false

visitNode(node.X)

// Process identifiers in the loop body to use shadowed names
ast.Inspect(node.Body, func(n ast.Node) bool {
if ident, ok := n.(*ast.Ident); ok {
if shadowName, exists := rangeVars[ident.Name]; exists {
if obj := v.info.Uses[ident]; obj != nil {
v.identNames[ident] = shadowName
}
}
}
return true
})

visitNode(node.Body)

tracker.exit()
Expand Down

0 comments on commit 462229d

Please sign in to comment.