return fmt.Sprintf("etype=%d", et)
}
-// sprint_depchain prints a dependency chain of nodes into fmt.
+// sprint_depchain prints a dependency chain of nodes into trace.
// It is used by typecheck in the case of OLITERAL nodes
// to print constant definition loops.
-func sprint_depchain(fmt_ *string, stack []*Node, cur *Node, first *Node) {
+func sprint_depchain(trace *string, stack []*Node, cur *Node, first *Node) {
for i := len(stack) - 1; i >= 0; i-- {
if n := stack[i]; n.Op == cur.Op {
if n != first {
- sprint_depchain(fmt_, stack[:i], n, first)
+ sprint_depchain(trace, stack[:i], n, first)
}
- *fmt_ += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur)
+ *trace += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur)
return
}
}
if n.Typecheck == 2 {
// Typechecking loop. Trying printing a meaningful message,
// otherwise a stack trace of typechecking.
- var fmt_ string
switch n.Op {
// We can already diagnose variables used as types.
case ONAME:
yyerror("%v is not a type", n)
}
+ case OTYPE:
+ if top&Etype == Etype {
+ var trace string
+ sprint_depchain(&trace, typecheck_tcstack, n, n)
+ yyerrorl(n.Lineno, "invalid recursive type alias %v%s", n, trace)
+ }
+
case OLITERAL:
if top&(Erv|Etype) == Etype {
yyerror("%v is not a type", n)
break
}
- sprint_depchain(&fmt_, typecheck_tcstack, n, n)
- yyerrorl(n.Lineno, "constant definition loop%s", fmt_)
+ var trace string
+ sprint_depchain(&trace, typecheck_tcstack, n, n)
+ yyerrorl(n.Lineno, "constant definition loop%s", trace)
}
if nsavederrors+nerrors == 0 {
- fmt_ = ""
+ var trace string
for i := len(typecheck_tcstack) - 1; i >= 0; i-- {
x := typecheck_tcstack[i]
- fmt_ += fmt.Sprintf("\n\t%v %v", x.Line(), x)
+ trace += fmt.Sprintf("\n\t%v %v", x.Line(), x)
}
- yyerror("typechecking loop involving %v%s", n, fmt_)
+ yyerror("typechecking loop involving %v%s", n, trace)
}
lineno = lno