Source file src/go/types/scope_test.go

     1  // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
     2  // Source: ../../cmd/compile/internal/types2/scope_test.go
     3  
     4  // Copyright 2026 The Go Authors. All rights reserved.
     5  // Use of this source code is governed by a BSD-style
     6  // license that can be found in the LICENSE file.
     7  
     8  package types
     9  
    10  import (
    11  	"fmt"
    12  	"slices"
    13  	"testing"
    14  )
    15  
    16  // TestScopeObjects tests that Scope.Objects yields elements in sorted name order, handles empty scopes, and supports early break.
    17  func TestScopeObjects(t *testing.T) {
    18  	s := NewScope(nil, nopos, nopos, "test")
    19  
    20  	// Empty scope
    21  	var gotNames []string
    22  	for obj := range s.Objects() {
    23  		gotNames = append(gotNames, obj.Name())
    24  	}
    25  	if len(gotNames) != 0 {
    26  		t.Errorf("empty scope: got %v, want empty", gotNames)
    27  	}
    28  
    29  	// Insert objects out of order
    30  	names := []string{"e", "c", "a", "b", "d"}
    31  	for _, name := range names {
    32  		v := NewVar(nopos, nil, name, Typ[Int])
    33  		if alt := s.Insert(v); alt != nil {
    34  			t.Fatalf("Insert(%s) failed", name)
    35  		}
    36  	}
    37  
    38  	wantNames := []string{"a", "b", "c", "d", "e"}
    39  	if !slices.Equal(s.Names(), wantNames) {
    40  		t.Errorf("Names() = %v, want %v", s.Names(), wantNames)
    41  	}
    42  
    43  	// Scope.Objects yields elements in sorted name order
    44  	gotNames = nil
    45  	for obj := range s.Objects() {
    46  		gotNames = append(gotNames, obj.Name())
    47  		if obj != s.Lookup(obj.Name()) {
    48  			t.Errorf("Objects() yielded %v, want Lookup result %v", obj, s.Lookup(obj.Name()))
    49  		}
    50  	}
    51  	if !slices.Equal(gotNames, wantNames) {
    52  		t.Errorf("Objects() yielded %v, want %v", gotNames, wantNames)
    53  	}
    54  
    55  	// Break early from iteration
    56  	count := 0
    57  	for range s.Objects() {
    58  		count++
    59  		if count == 2 {
    60  			break
    61  		}
    62  	}
    63  	if count != 2 {
    64  		t.Errorf("early break: iterated %d times, want 2", count)
    65  	}
    66  }
    67  
    68  // TestScopeMutationReflectsChanges tests that Scope.Insert clears the name cache so subsequent calls reflect mutations.
    69  func TestScopeMutationReflectsChanges(t *testing.T) {
    70  	s := NewScope(nil, nopos, nopos, "test")
    71  
    72  	v1 := NewVar(nopos, nil, "b", Typ[Int])
    73  	s.Insert(v1)
    74  
    75  	// Prime cache
    76  	if want := []string{"b"}; !slices.Equal(s.Names(), want) {
    77  		t.Fatalf("Names() = %v, want %v", s.Names(), want)
    78  	}
    79  
    80  	// Insert before existing name
    81  	v0 := NewVar(nopos, nil, "a", Typ[Int])
    82  	s.Insert(v0)
    83  
    84  	// Names() must reflect new object
    85  	wantNames := []string{"a", "b"}
    86  	if !slices.Equal(s.Names(), wantNames) {
    87  		t.Errorf("after inserting 'a': Names() = %v, want %v", s.Names(), wantNames)
    88  	}
    89  
    90  	// Objects() must reflect new object
    91  	var gotNames []string
    92  	for obj := range s.Objects() {
    93  		gotNames = append(gotNames, obj.Name())
    94  	}
    95  	if !slices.Equal(gotNames, wantNames) {
    96  		t.Errorf("after inserting 'a': Objects() = %v, want %v", gotNames, wantNames)
    97  	}
    98  
    99  	// Insert after existing names
   100  	v2 := NewVar(nopos, nil, "c", Typ[Int])
   101  	s.Insert(v2)
   102  
   103  	wantNames = []string{"a", "b", "c"}
   104  	if !slices.Equal(s.Names(), wantNames) {
   105  		t.Errorf("after inserting 'c': Names() = %v, want %v", s.Names(), wantNames)
   106  	}
   107  	gotNames = nil
   108  	for obj := range s.Objects() {
   109  		gotNames = append(gotNames, obj.Name())
   110  	}
   111  	if !slices.Equal(gotNames, wantNames) {
   112  		t.Errorf("after inserting 'c': Objects() = %v, want %v", gotNames, wantNames)
   113  	}
   114  
   115  	// Duplicate insert should not mutate or break cache
   116  	dup := NewVar(nopos, nil, "b", Typ[String])
   117  	if alt := s.Insert(dup); alt != v1 {
   118  		t.Errorf("Insert duplicate: got %v, want %v", alt, v1)
   119  	}
   120  	if !slices.Equal(s.Names(), wantNames) {
   121  		t.Errorf("after duplicate Insert: Names() = %v, want %v", s.Names(), wantNames)
   122  	}
   123  }
   124  
   125  // TestScopeNoAllocations tests that repeated calls to Scope.Names
   126  // and Scope.Objects do not allocate once cached.
   127  func TestScopeNoAllocations(t *testing.T) {
   128  	s := NewScope(nil, nopos, nopos, "test")
   129  	for i := range 10 {
   130  		s.Insert(NewVar(nopos, nil, fmt.Sprintf("v%d", i), Typ[Int]))
   131  	}
   132  
   133  	// Prime the cache.
   134  	_ = s.Names()
   135  
   136  	// Scope.Names
   137  	namesAllocs := testing.AllocsPerRun(100, func() { _ = s.Names() })
   138  	if namesAllocs > 0 {
   139  		t.Errorf("repeated s.Names() allocated %f times, want 0", namesAllocs)
   140  	}
   141  
   142  	// Scope.Objects allocates the iterator closure, and nothing else,
   143  	// on top of what Names allocates.
   144  	if allocs := testing.AllocsPerRun(100, func() {
   145  		s.Objects()(func(Object) bool { return true })
   146  	}); allocs > namesAllocs+1 {
   147  		t.Errorf("repeated s.Objects() iteration allocated %f times, want at most %f", allocs, namesAllocs+1)
   148  	}
   149  }
   150  

View as plain text