mirror of https://github.com/golang/go.git
cmd/gc: replace "typechecking loop" by nicer errors in some cases.
For issue 3757:
BEFORE: test/fixedbugs/bug463.go:12: typechecking loop involving a
test/fixedbugs/bug463.go:12 a
test/fixedbugs/bug463.go:12 <node DCLCONST>
AFTER: test/fixedbugs/bug463.go:12: constant definition loop
test/fixedbugs/bug463.go:12: a uses a
For issue 3937:
BEFORE: test/fixedbugs/bug464.go:12: typechecking loop involving foo
test/fixedbugs/bug464.go:12 <T>
test/fixedbugs/bug464.go:12 foo
test/fixedbugs/bug464.go:12 <node DCLFUNC>
AFTER: test/fixedbugs/bug464.go:12: foo is not a type
Fixes #3757.
Fixes #3937.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6614058
This commit is contained in:
parent
87c35d8df1
commit
892fa3ae6c
|
|
@ -105,6 +105,27 @@ typekind(Type *t)
|
|||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* sprint_depchain prints a dependency chain
|
||||
* of nodes into fmt.
|
||||
* It is used by typecheck in the case of OLITERAL nodes
|
||||
* to print constant definition loops.
|
||||
*/
|
||||
static void
|
||||
sprint_depchain(Fmt *fmt, NodeList *stack, Node *cur, Node *first)
|
||||
{
|
||||
NodeList *l;
|
||||
|
||||
for(l = stack; l; l=l->next) {
|
||||
if(l->n->op == cur->op) {
|
||||
if(l->n != first)
|
||||
sprint_depchain(fmt, l->next, l->n, first);
|
||||
fmtprint(fmt, "\n\t%L: %N uses %N", l->n->lineno, l->n, cur);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* type check node *np.
|
||||
* replaces *np with a new pointer in some cases.
|
||||
|
|
@ -155,6 +176,24 @@ typecheck(Node **np, int top)
|
|||
}
|
||||
|
||||
if(n->typecheck == 2) {
|
||||
// Typechecking loop. Trying printing a meaningful message,
|
||||
// otherwise a stack trace of typechecking.
|
||||
switch(n->op) {
|
||||
case ONAME:
|
||||
// We can already diagnose variables used as types.
|
||||
if((top & (Erv|Etype)) == Etype)
|
||||
yyerror("%N is not a type", n);
|
||||
break;
|
||||
case OLITERAL:
|
||||
if((top & (Erv|Etype)) == Etype) {
|
||||
yyerror("%N is not a type", n);
|
||||
break;
|
||||
}
|
||||
fmtstrinit(&fmt);
|
||||
sprint_depchain(&fmt, tcstack, n, n);
|
||||
yyerrorl(n->lineno, "constant definition loop%s", fmtstrflush(&fmt));
|
||||
break;
|
||||
}
|
||||
if(nsavederrors+nerrors == 0) {
|
||||
fmtstrinit(&fmt);
|
||||
for(l=tcstack; l; l=l->next)
|
||||
|
|
@ -165,7 +204,7 @@ typecheck(Node **np, int top)
|
|||
return n;
|
||||
}
|
||||
n->typecheck = 2;
|
||||
|
||||
|
||||
if(tcfree != nil) {
|
||||
l = tcfree;
|
||||
tcfree = l->next;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
// errorcheck
|
||||
|
||||
// Copyright 2012 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.
|
||||
|
||||
// Issue 3757: unhelpful typechecking loop message
|
||||
// for constants that refer to themselves.
|
||||
|
||||
package main
|
||||
|
||||
const a = a // ERROR "refers to itself|definition loop"
|
||||
|
||||
const (
|
||||
X = A
|
||||
A = B // ERROR "refers to itself|definition loop"
|
||||
B = D
|
||||
C, D = 1, A
|
||||
)
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// errorcheck
|
||||
|
||||
// Copyright 2012 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.
|
||||
|
||||
// Issue 3937: unhelpful typechecking loop message
|
||||
// for identifiers wrongly used as types.
|
||||
|
||||
package main
|
||||
|
||||
func foo(x foo) {} // ERROR "expected type|not a type"
|
||||
Loading…
Reference in New Issue