Commit d4023430 authored by griesemer's avatar griesemer Committed by Robert Griesemer

go/doc: fix constant type propagation

The old code was seriously broken: It assumed that a constant
declaration without a type would always inherit the type of
the previous declaration, but in fact it only inherits the
type of the previous declaration when there's no type and no
constant value.

While fixing this bug, found that the result was not sorted
deterministically in all situations due to a poor choice of
order value (which led to spurious test failures since the
tests assume deterministic outputs). Fixed that as well.

Added new test cases and fixed some old (broken) tests.

Fixes #16153.

Change-Id: I95b480e019b0fd3538638caba02fe651c69e0513
Reviewed-on: https://go-review.googlesource.com/68730Reviewed-by: default avatarAlan Donovan <adonovan@google.com>
parent 1ddacfea
...@@ -200,7 +200,7 @@ func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec { ...@@ -200,7 +200,7 @@ func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec {
var prevType ast.Expr var prevType ast.Expr
for _, spec := range list { for _, spec := range list {
spec := spec.(*ast.ValueSpec) spec := spec.(*ast.ValueSpec)
if spec.Type == nil && prevType != nil { if spec.Type == nil && len(spec.Values) == 0 && prevType != nil {
// provide current spec with an explicit type // provide current spec with an explicit type
spec.Type = copyConstType(prevType, spec.Pos()) spec.Type = copyConstType(prevType, spec.Pos())
} }
......
...@@ -154,6 +154,7 @@ type reader struct { ...@@ -154,6 +154,7 @@ type reader struct {
imports map[string]int imports map[string]int
hasDotImp bool // if set, package contains a dot import hasDotImp bool // if set, package contains a dot import
values []*Value // consts and vars values []*Value // consts and vars
order int // sort order of const and var declarations (when we can't use a name)
types map[string]*namedType types map[string]*namedType
funcs methodSet funcs methodSet
...@@ -256,11 +257,9 @@ func (r *reader) readValue(decl *ast.GenDecl) { ...@@ -256,11 +257,9 @@ func (r *reader) readValue(decl *ast.GenDecl) {
if n, imp := baseTypeName(s.Type); !imp { if n, imp := baseTypeName(s.Type); !imp {
name = n name = n
} }
case decl.Tok == token.CONST: case decl.Tok == token.CONST && len(s.Values) == 0:
// no type is present but we have a constant declaration; // no type or value is present but we have a constant declaration;
// use the previous type name (w/o more type information // use the previous type name (possibly the empty string)
// we cannot handle the case of unnamed variables with
// initializer expressions except for some trivial cases)
name = prev name = prev
} }
if name != "" { if name != "" {
...@@ -297,9 +296,15 @@ func (r *reader) readValue(decl *ast.GenDecl) { ...@@ -297,9 +296,15 @@ func (r *reader) readValue(decl *ast.GenDecl) {
Doc: decl.Doc.Text(), Doc: decl.Doc.Text(),
Names: specNames(decl.Specs), Names: specNames(decl.Specs),
Decl: decl, Decl: decl,
order: len(*values), order: r.order,
}) })
decl.Doc = nil // doc consumed - remove from AST decl.Doc = nil // doc consumed - remove from AST
// Note: It's important that the order used here is global because the cleanupTypes
// methods may move values associated with types back into the global list. If the
// order is list-specific, sorting is not deterministic because the same order value
// may appear multiple times (was bug, found when fixing #16153).
r.order++
} }
// fields returns a struct's fields or an interface's methods. // fields returns a struct's fields or an interface's methods.
......
...@@ -21,11 +21,18 @@ CONSTANTS ...@@ -21,11 +21,18 @@ CONSTANTS
C4 int C4 int
) )
// Constants with an imported type that needs to be propagated. // Constants with a single type that is not propagated.
const ( const (
Default os.FileMode = 0644 Default = 0644
Useless = 0312 Useless = 0312
WideOpen = 0777 WideOpen = 0777
)
// Constants with an imported type that is propagated.
const (
M1 os.FileMode
M2
M3
) )
// Package constants. // Package constants.
......
...@@ -23,14 +23,7 @@ CONSTANTS ...@@ -23,14 +23,7 @@ CONSTANTS
C4 C4
) )
// Package constants. // Constants with a single type that is not propagated.
const (
_ int = iota
I1
I2
)
// Constants with an imported type that needs to be propagated.
const ( const (
zero os.FileMode = 0 zero os.FileMode = 0
Default = 0644 Default = 0644
...@@ -38,6 +31,21 @@ CONSTANTS ...@@ -38,6 +31,21 @@ CONSTANTS
WideOpen = 0777 WideOpen = 0777
) )
// Constants with an imported type that is propagated.
const (
zero os.FileMode = 0
M1
M2
M3
)
// Package constants.
const (
_ int = iota
I1
I2
)
// Unexported constants counting from blank iota. See issue 9615. // Unexported constants counting from blank iota. See issue 9615.
const ( const (
_ = iota _ = iota
......
...@@ -21,11 +21,18 @@ CONSTANTS ...@@ -21,11 +21,18 @@ CONSTANTS
C4 int C4 int
) )
// Constants with an imported type that needs to be propagated. // Constants with a single type that is not propagated.
const ( const (
Default os.FileMode = 0644 Default = 0644
Useless = 0312 Useless = 0312
WideOpen = 0777 WideOpen = 0777
)
// Constants with an imported type that is propagated.
const (
M1 os.FileMode
M2
M3
) )
// Package constants. // Package constants.
......
...@@ -29,7 +29,7 @@ const ( ...@@ -29,7 +29,7 @@ const (
C4 C4
) )
// Constants with an imported type that needs to be propagated. // Constants with a single type that is not propagated.
const ( const (
zero os.FileMode = 0 zero os.FileMode = 0
Default = 0644 Default = 0644
...@@ -37,6 +37,14 @@ const ( ...@@ -37,6 +37,14 @@ const (
WideOpen = 0777 WideOpen = 0777
) )
// Constants with an imported type that is propagated.
const (
zero os.FileMode = 0
M1
M2
M3
)
// Package constants. // Package constants.
const ( const (
_ int = iota _ int = iota
......
//
PACKAGE issue16153
IMPORTPATH
testdata/issue16153
FILENAMES
testdata/issue16153.go
CONSTANTS
//
const (
X3 int64 = iota
Y3 = 1
)
//
const (
X4 int64 = iota
Y4
)
// original test case
const (
Y1 = 256
)
// variations
const (
Y2 uint8
)
//
PACKAGE issue16153
IMPORTPATH
testdata/issue16153
FILENAMES
testdata/issue16153.go
CONSTANTS
// original test case
const (
x1 uint8 = 255
Y1 = 256
)
// variations
const (
x2 uint8 = 255
Y2
)
//
const (
X3 int64 = iota
Y3 = 1
)
//
const (
X4 int64 = iota
Y4
)
//
PACKAGE issue16153
IMPORTPATH
testdata/issue16153
FILENAMES
testdata/issue16153.go
CONSTANTS
//
const (
X3 int64 = iota
Y3 = 1
)
//
const (
X4 int64 = iota
Y4
)
// original test case
const (
Y1 = 256
)
// variations
const (
Y2 uint8
)
// Copyright 2017 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.
package issue16153
// original test case
const (
x1 uint8 = 255
Y1 = 256
)
// variations
const (
x2 uint8 = 255
Y2
)
const (
X3 int64 = iota
Y3 = 1
)
const (
X4 int64 = iota
Y4
)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment