From 5c160b28baceb263fbd95ea0c95f5083e191c114 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 12 Jan 2017 14:35:20 -0800 Subject: [PATCH] [dev.typealias] cmd/compile: improved error message for cyles involving type aliases Known issue: #18640 (requires a bit more work, I believe). For #18130. Change-Id: I53dc26012070e0c79f63b7c76266732190a83d47 Reviewed-on: https://go-review.googlesource.com/35129 Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/fmt.go | 4 +++- src/cmd/compile/internal/gc/typecheck.go | 27 +++++++++++++++--------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index fffce440bc..16a4e342fc 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -1077,6 +1077,7 @@ var opprec = []int{ OSEND: 3, OANDAND: 2, OOROR: 1, + // Statements handled by stmtfmt OAS: -1, OAS2: -1, @@ -1104,7 +1105,8 @@ var opprec = []int{ OSWITCH: -1, OXCASE: -1, OXFALL: -1, - OEND: 0, + + OEND: 0, } func (n *Node) exprfmt(s fmt.State, prec int) { diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 46c71d69c4..f18bcfad78 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -96,16 +96,16 @@ func typekind(t *Type) string { 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 } } @@ -152,7 +152,6 @@ func typecheck(n *Node, top int) *Node { 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: @@ -160,22 +159,30 @@ func typecheck(n *Node, top int) *Node { 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 -- 2.48.1