From 9ce87a63b9f440b452ada1ff89ccb1c4f3ca919f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20Mart=C3=AD?= Date: Tue, 29 May 2018 18:25:18 +0200 Subject: [PATCH] cmd/compile: typecheck types and funcs before consts MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This way, once the constant declarations are typechecked, all named types are fully typechecked and have all of their methods added. Usually this isn't important, as methods and interfaces cannot be used in constant declarations. However, it can lead to confusing and incorrect errors, such as: $ cat f.go package p type I interface{ F() } type T struct{} const _ = I(T{}) func (T) F() {} $ go build f.go ./f.go:6:12: cannot convert T literal (type T) to type I: T does not implement I (missing F method) The error is clearly wrong, as T does have an F method. If we ensure that all funcs are typechecked before all constant declarations, we get the correct error: $ go build f2.go # command-line-arguments ./f.go:6:7: const initializer I(T literal) is not a constant Fixes #24755. Change-Id: I182b60397b9cac521d9a9ffadb11b42fd42e42fe Reviewed-on: https://go-review.googlesource.com/c/115096 Run-TryBot: Daniel Martí TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/main.go | 21 +++++++++++++++++---- test/fixedbugs/issue24755.go | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 test/fixedbugs/issue24755.go diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 339e8e08cd..09378bab6e 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -480,7 +480,7 @@ func Main(archInit func(*Arch)) { // Process top-level declarations in phases. - // Phase 1: const, type, and names and types of funcs. + // Phase 1: type, and names and types of funcs. // This will gather all the information about types // and methods but doesn't depend on any of it. defercheckwidth() @@ -489,16 +489,29 @@ func Main(archInit func(*Arch)) { timings.Start("fe", "typecheck", "top1") for i := 0; i < len(xtop); i++ { n := xtop[i] - if op := n.Op; op != ODCL && op != OAS && op != OAS2 { + if op := n.Op; op != ODCL && op != OAS && op != OAS2 && op != ODCLCONST { xtop[i] = typecheck(n, Etop) } } - // Phase 2: Variable assignments. - // To check interface assignments, depends on phase 1. + // Phase 2: Constant declarations. + // To have named types fully type checked, depends on phase 1. // Don't use range--typecheck can add closures to xtop. timings.Start("fe", "typecheck", "top2") + for i := 0; i < len(xtop); i++ { + n := xtop[i] + if op := n.Op; op == ODCLCONST { + xtop[i] = typecheck(n, Etop) + } + } + + // Phase 3: Variable assignments. + // To check interface assignments, depends on phase 1. + // To use constants, depends on phase 2. + + // Don't use range--typecheck can add closures to xtop. + timings.Start("fe", "typecheck", "top3") for i := 0; i < len(xtop); i++ { n := xtop[i] if op := n.Op; op == ODCL || op == OAS || op == OAS2 { diff --git a/test/fixedbugs/issue24755.go b/test/fixedbugs/issue24755.go new file mode 100644 index 0000000000..07c9d5a418 --- /dev/null +++ b/test/fixedbugs/issue24755.go @@ -0,0 +1,16 @@ +// errorcheck + +// Copyright 2018 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. + +// Tests that all types and functions are type-checked before any constant +// declaration is. Issue #24755. +package p + +type I interface{ F() } +type T struct{} + +const _ = I(T{}) // ERROR "const initializer I\(T literal\) is not a constant" + +func (T) F() {} -- 2.50.0