errsupport.go raw

   1  // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
   2  // Source: ../../cmd/compile/internal/types2/errsupport.go
   3  
   4  // Copyright 2024 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  // This file implements support functions for error messages.
   9  
  10  package types
  11  
  12  // lookupError returns a case-specific error when a lookup of selector sel in the
  13  // given type fails but an object with alternative spelling (case folding) is found.
  14  // If structLit is set, the error message is specifically for struct literal fields.
  15  func (check *Checker) lookupError(typ Type, sel string, obj Object, structLit bool) string {
  16  	// Provide more detail if there is an unexported object, or one with different capitalization.
  17  	// If selector and object are in the same package (==), export doesn't matter, otherwise (!=) it does.
  18  	// Messages depend on whether it's a general lookup or a field lookup in a struct literal.
  19  	//
  20  	// case           sel     pkg   have   message (examples for general lookup)
  21  	// ---------------------------------------------------------------------------------------------------------
  22  	// ok             x.Foo   ==    Foo
  23  	// misspelled     x.Foo   ==    FoO    type X has no field or method Foo, but does have field FoO
  24  	// misspelled     x.Foo   ==    foo    type X has no field or method Foo, but does have field foo
  25  	// misspelled     x.Foo   ==    foO    type X has no field or method Foo, but does have field foO
  26  	//
  27  	// misspelled     x.foo   ==    Foo    type X has no field or method foo, but does have field Foo
  28  	// misspelled     x.foo   ==    FoO    type X has no field or method foo, but does have field FoO
  29  	// ok             x.foo   ==    foo
  30  	// misspelled     x.foo   ==    foO    type X has no field or method foo, but does have field foO
  31  	//
  32  	// ok             x.Foo   !=    Foo
  33  	// misspelled     x.Foo   !=    FoO    type X has no field or method Foo, but does have field FoO
  34  	// unexported     x.Foo   !=    foo    type X has no field or method Foo, but does have unexported field foo
  35  	// missing        x.Foo   !=    foO    type X has no field or method Foo
  36  	//
  37  	// misspelled     x.foo   !=    Foo    type X has no field or method foo, but does have field Foo
  38  	// missing        x.foo   !=    FoO    type X has no field or method foo
  39  	// inaccessible   x.foo   !=    foo    cannot refer to unexported field foo
  40  	// missing        x.foo   !=    foO    type X has no field or method foo
  41  
  42  	const (
  43  		ok           = iota
  44  		missing      // no object found
  45  		misspelled   // found object with different spelling
  46  		unexported   // found object with name differing only in first letter
  47  		inaccessible // found object with matching name but inaccessible from the current package
  48  	)
  49  
  50  	// determine case
  51  	e := missing
  52  	var alt string // alternative spelling of selector; if any
  53  	if obj != nil {
  54  		alt = obj.Name()
  55  		if obj.Pkg() == check.pkg {
  56  			assert(alt != sel) // otherwise there is no lookup error
  57  			e = misspelled
  58  		} else if isExported(sel) {
  59  			if isExported(alt) {
  60  				e = misspelled
  61  			} else if tail(sel) == tail(alt) {
  62  				e = unexported
  63  			}
  64  		} else if isExported(alt) {
  65  			if tail(sel) == tail(alt) {
  66  				e = misspelled
  67  			}
  68  		} else if sel == alt {
  69  			e = inaccessible
  70  		}
  71  	}
  72  
  73  	if structLit {
  74  		switch e {
  75  		case missing:
  76  			return check.sprintf("unknown field %s in struct literal of type %s", sel, typ)
  77  		case misspelled:
  78  			return check.sprintf("unknown field %s in struct literal of type %s, but does have %s", sel, typ, alt)
  79  		case unexported:
  80  			return check.sprintf("unknown field %s in struct literal of type %s, but does have unexported %s", sel, typ, alt)
  81  		case inaccessible:
  82  			return check.sprintf("cannot refer to unexported field %s in struct literal of type %s", alt, typ)
  83  		}
  84  	} else {
  85  		what := "object"
  86  		switch obj.(type) {
  87  		case *Var:
  88  			what = "field"
  89  		case *Func:
  90  			what = "method"
  91  		}
  92  		switch e {
  93  		case missing:
  94  			return check.sprintf("type %s has no field or method %s", typ, sel)
  95  		case misspelled:
  96  			return check.sprintf("type %s has no field or method %s, but does have %s %s", typ, sel, what, alt)
  97  		case unexported:
  98  			return check.sprintf("type %s has no field or method %s, but does have unexported %s %s", typ, sel, what, alt)
  99  		case inaccessible:
 100  			return check.sprintf("cannot refer to unexported %s %s", what, alt)
 101  		}
 102  	}
 103  
 104  	panic("unreachable")
 105  }
 106  
 107  // tail returns the string s without its first (UTF-8) character.
 108  // If len(s) == 0, the result is s.
 109  func tail(s string) string {
 110  	for i, _ := range s {
 111  		if i > 0 {
 112  			return s[i:]
 113  		}
 114  	}
 115  	return s
 116  }
 117