Skip to content

Commit 25159d3

Browse files
committed
cmd/compile: avoid spurious errors for invalid map key types
Instead of trying to validate map key types eagerly in some cases, delay their validation to the end of type-checking, when we all type information is present. Passes go build -toolexec 'toolstash -cmp' -a std . Fixes #21273. Fixes #21657. Change-Id: I532369dc91c6adca1502d6aa456bb06b57e6c7ff Reviewed-on: https://go-review.googlesource.com/75310 Reviewed-by: Matthew Dempsky <[email protected]>
1 parent aec345d commit 25159d3

File tree

4 files changed

+41
-37
lines changed

4 files changed

+41
-37
lines changed

src/cmd/compile/internal/gc/align.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ func dowidth(t *types.Type) {
291291

292292
case TFORW: // should have been filled in
293293
if !t.Broke() {
294+
t.SetBroke(true)
294295
yyerror("invalid recursive type %v", t)
295296
}
296297
w = 1 // anything will do

src/cmd/compile/internal/gc/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,8 @@ func Main(archInit func(*Arch)) {
513513
fcount++
514514
}
515515
}
516+
// With all types ckecked, it's now safe to verify map keys.
517+
checkMapKeys()
516518
timings.AddEvent(fcount, "funcs")
517519

518520
// Phase 4: Decide how to capture closed variables.

src/cmd/compile/internal/gc/typecheck.go

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package gc
77
import (
88
"cmd/compile/internal/types"
99
"cmd/internal/objabi"
10-
"cmd/internal/src"
1110
"fmt"
1211
"math"
1312
"strings"
@@ -420,18 +419,7 @@ func typecheck1(n *Node, top int) *Node {
420419
}
421420
n.Op = OTYPE
422421
n.Type = types.NewMap(l.Type, r.Type)
423-
424-
// map key validation
425-
alg, bad := algtype1(l.Type)
426-
if alg == ANOEQ {
427-
if bad.Etype == TFORW {
428-
// queue check for map until all the types are done settling.
429-
mapqueue = append(mapqueue, mapqueueval{l, n.Pos})
430-
} else if bad.Etype != TANY {
431-
// no need to queue, key is already bad
432-
yyerror("invalid map key type %v", l.Type)
433-
}
434-
}
422+
mapqueue = append(mapqueue, n) // check map keys when all types are settled
435423
n.Left = nil
436424
n.Right = nil
437425

@@ -3496,16 +3484,18 @@ func stringtoarraylit(n *Node) *Node {
34963484
return nn
34973485
}
34983486

3499-
var ntypecheckdeftype int
3487+
var mapqueue []*Node
35003488

3501-
type mapqueueval struct {
3502-
n *Node
3503-
lno src.XPos
3489+
func checkMapKeys() {
3490+
for _, n := range mapqueue {
3491+
k := n.Type.MapType().Key
3492+
if !k.Broke() && !IsComparable(k) {
3493+
yyerrorl(n.Pos, "invalid map key type %v", k)
3494+
}
3495+
}
3496+
mapqueue = nil
35043497
}
35053498

3506-
// tracks the line numbers at which forward types are first used as map keys
3507-
var mapqueue []mapqueueval
3508-
35093499
func copytype(n *Node, t *types.Type) {
35103500
if t.Etype == TFORW {
35113501
// This type isn't computed yet; when it is, update n.
@@ -3565,7 +3555,6 @@ func copytype(n *Node, t *types.Type) {
35653555
}
35663556

35673557
func typecheckdeftype(n *Node) {
3568-
ntypecheckdeftype++
35693558
lno := lineno
35703559
setlineno(n)
35713560
n.Type.Sym = n.Sym
@@ -3584,22 +3573,6 @@ func typecheckdeftype(n *Node) {
35843573
}
35853574

35863575
lineno = lno
3587-
3588-
// if there are no type definitions going on, it's safe to
3589-
// try to validate the map key types for the interfaces
3590-
// we just read.
3591-
if ntypecheckdeftype == 1 {
3592-
for _, e := range mapqueue {
3593-
lineno = e.lno
3594-
if !IsComparable(e.n.Type) {
3595-
yyerror("invalid map key type %v", e.n.Type)
3596-
}
3597-
}
3598-
mapqueue = nil
3599-
lineno = lno
3600-
}
3601-
3602-
ntypecheckdeftype--
36033576
}
36043577

36053578
func typecheckdef(n *Node) {

test/fixedbugs/issue21273.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// errorcheck
2+
3+
// Copyright 2017 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
type T0 T0 // ERROR "invalid recursive type"
10+
type _ map[T0]int
11+
12+
type T1 struct{ T1 } // ERROR "invalid recursive type"
13+
type _ map[T1]int
14+
15+
func f() {
16+
type T2 T2 // ERROR "invalid recursive type"
17+
type _ map[T2]int
18+
}
19+
20+
func g() {
21+
type T3 struct{ T3 } // ERROR "invalid recursive type"
22+
type _ map[T3]int
23+
}
24+
25+
func h() {
26+
type T4 struct{ m map[T4]int } // ERROR "invalid map key"
27+
type _ map[T4]int // ERROR "invalid map key"
28+
}

0 commit comments

Comments
 (0)