"go/parser"
"go/token"
"internal/testenv"
+ "os"
+ "os/exec"
+ "path/filepath"
"reflect"
"regexp"
"strings"
func TestAliases(t *testing.T) {
testenv.MustHaveGoBuild(t)
+ const src = `
+package b
+
+import (
+ "./testdata/alias"
+ a "./testdata/alias"
+ // "math" // TODO(gri) does not work yet - fix importer (issue #17726)
+)
+
+const (
+ c1 = alias.Pi
+ c2 => a.Pi
+)
+
+var (
+ v1 => alias.Default
+ v2 => a.Default
+ v3 = f1
+)
+
+type (
+ t1 => alias.Context
+ t2 => a.Context
+)
+
+func f1 => alias.Sin
+func f2 => a.Sin
+
+func _() {
+ assert(c1 == c2 && c1 == alias.Pi && c2 == a.Pi)
+ v1 = v2 // must be assignable
+ var _ *t1 = new(t2) // must be assignable
+ var _ t2 = alias.Default
+ f1(1) // must be callable
+ f2(1)
+ _ = alias.Sin(1)
+ _ = a.Sin(1)
+}
+`
+
+ if out := compile(t, "testdata", "alias.go"); out != "" {
+ defer os.Remove(out)
+ }
+
+ DefPredeclaredTestFuncs() // declare assert built-in for testing
+ mustTypecheck(t, "Aliases", src, nil)
+}
+
+func compile(t *testing.T, dirname, filename string) string {
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", filename)
+ cmd.Dir = dirname
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Logf("%s", out)
+ t.Fatalf("go tool compile %s failed: %s", filename, err)
+ }
+ // filename should end with ".go"
+ return filepath.Join(dirname, filename[:len(filename)-2]+"o")
+}
+
+func TestAliasDefUses(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
const src = `
package p
Defs: make(map[*ast.Ident]Object),
Uses: make(map[*ast.Ident]Object),
}
- mustTypecheck(t, "Aliases", src, &info)
+ mustTypecheck(t, "TestAliasDefUses", src, &info)
// verify Defs
defs := map[string]string{
// ok to continue
}
check.recordUse(e.Sel, exp)
+ exp = original(exp)
+
+ // avoid further errors if the imported object is an alias that's broken
+ if exp == nil {
+ goto Error
+ }
+
// Simplified version of the code for *ast.Idents:
// - imported objects are always fully initialized
switch exp := exp.(type) {
x.typ = exp.typ
x.id = exp.id
default:
- check.dump("unexpected object %v (%T)", exp, exp)
+ check.dump("unexpected object %v", exp)
unreachable()
}
x.expr = e
}
}
+// original returns the original Object if obj is an Alias;
+// otherwise it returns obj. The result is never an Alias,
+// but it may be nil.
+func original(obj Object) Object {
+ // an alias stands for the original object; use that one instead
+ if alias, _ := obj.(*Alias); alias != nil {
+ obj = alias.orig
+ // aliases always refer to non-alias originals
+ if _, ok := obj.(*Alias); ok {
+ panic("original is an alias")
+ }
+ }
+ return obj
+}
+
func (check *Checker) aliasDecl(obj *Alias, decl *declInfo) {
assert(obj.typ == nil)
return
}
check.recordUse(sel, orig)
+ orig = original(orig)
+
+ // avoid further errors if the imported object is an alias that's broken
+ if orig == nil {
+ return
+ }
// An alias declaration must not refer to package unsafe.
if orig.Pkg() == Unsafe {
--- /dev/null
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used by TestAliases (api_test.go).
+
+package alias
+
+import (
+ "go/build"
+ "math"
+)
+
+const Pi => math.Pi
+
+var Default => build.Default
+
+type Context => build.Context
+
+func Sin => math.Sin
}
// An alias stands for the original object; use that one instead.
+ // TODO(gri) We should be able to factor out the Typ[Invalid] test.
if alias, _ := obj.(*Alias); alias != nil {
- if typ == Typ[Invalid] {
+ obj = original(obj)
+ if obj == nil || typ == Typ[Invalid] {
return
}
- obj = alias.orig
- // Aliases always refer to non-alias originals.
- if _, ok := obj.(*Alias); ok {
- panic("original is an alias")
- }
assert(typ == obj.Type())
}