Skip to content

Commit b2386df

Browse files
committed
[dev.typealias] cmd/compile: type-check type alias declarations
Known issues: - needs many more tests - duplicate method declarations via type alias names are not detected - type alias cycle error messages need to be improved - need to review setup of byte/rune type aliases For #18130. Change-Id: Icc2fefad6214e5e56539a9dcb3fe537bf58029f8 Reviewed-on: https://go-review.googlesource.com/35121 Run-TryBot: Robert Griesemer <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]>
1 parent ac8421f commit b2386df

File tree

10 files changed

+153
-75
lines changed

10 files changed

+153
-75
lines changed

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

+3-4
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,8 @@ func export(out *bufio.Writer, trace bool) int {
352352
p.tracef("\n")
353353
}
354354

355-
if sym.Flags&SymAlias != 0 {
356-
Fatalf("exporter: unexpected alias %v in inlined function body", sym)
355+
if sym.isAlias() {
356+
Fatalf("exporter: unexpected type alias %v in inlined function body", sym)
357357
}
358358

359359
p.obj(sym)
@@ -486,8 +486,7 @@ func (p *exporter) obj(sym *Sym) {
486486
Fatalf("exporter: export of incomplete type %v", sym)
487487
}
488488

489-
const alias = false // TODO(gri) fix this
490-
if alias {
489+
if sym.isAlias() {
491490
p.tag(aliasTag)
492491
p.pos(n)
493492
p.qualifiedName(sym)

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

+11-13
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,10 @@ func (p *importer) obj(tag int) {
316316
importconst(sym, idealType(typ), nodlit(val))
317317

318318
case aliasTag:
319-
// TODO(gri) hook up type alias
320319
p.pos()
321-
p.qualifiedName()
322-
p.typ()
320+
sym := p.qualifiedName()
321+
typ := p.typ()
322+
importalias(sym, typ)
323323

324324
case typeTag:
325325
p.typ()
@@ -576,7 +576,7 @@ func (p *importer) fieldList() (fields []*Field) {
576576

577577
func (p *importer) field() *Field {
578578
p.pos()
579-
sym := p.fieldName()
579+
sym, alias := p.fieldName()
580580
typ := p.typ()
581581
note := p.string()
582582

@@ -589,8 +589,8 @@ func (p *importer) field() *Field {
589589
}
590590
sym = sym.Pkg.Lookup(s.Name)
591591
f.Embedded = 1
592-
} else if sym.Flags&SymAlias != 0 {
593-
// anonymous field: we have an explicit name because it's an alias
592+
} else if alias {
593+
// anonymous field: we have an explicit name because it's a type alias
594594
f.Embedded = 1
595595
}
596596

@@ -625,15 +625,15 @@ func (p *importer) method() *Field {
625625
return f
626626
}
627627

628-
func (p *importer) fieldName() *Sym {
628+
func (p *importer) fieldName() (*Sym, bool) {
629629
name := p.string()
630630
if p.version == 0 && name == "_" {
631631
// version 0 didn't export a package for _ field names
632632
// but used the builtin package instead
633-
return builtinpkg.Lookup(name)
633+
return builtinpkg.Lookup(name), false
634634
}
635635
pkg := localpkg
636-
var flag SymFlags
636+
alias := false
637637
switch name {
638638
case "":
639639
// 1) field name matches base type name and is exported: nothing to do
@@ -644,16 +644,14 @@ func (p *importer) fieldName() *Sym {
644644
case "@":
645645
// 3) field name doesn't match base type name (alias name): need name and possibly package
646646
name = p.string()
647-
flag = SymAlias
647+
alias = true
648648
fallthrough
649649
default:
650650
if !exportname(name) {
651651
pkg = p.pkg()
652652
}
653653
}
654-
sym := pkg.Lookup(name)
655-
sym.Flags |= flag
656-
return sym
654+
return pkg.Lookup(name), alias
657655
}
658656

659657
func (p *importer) methodName() *Sym {

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

+14-4
Original file line numberDiff line numberDiff line change
@@ -695,10 +695,20 @@ func typedcl0(s *Sym) *Node {
695695

696696
// node n, which was returned by typedcl0
697697
// is being declared to have uncompiled type t.
698-
// return the ODCLTYPE node to use.
699-
func typedcl1(n *Node, t *Node, local bool) *Node {
700-
n.Name.Param.Ntype = t
701-
n.Local = local
698+
// returns the ODCLTYPE node to use.
699+
func typedcl1(n *Node, t *Node, pragma Pragma, alias bool) *Node {
700+
if pragma != 0 && alias {
701+
yyerror("cannot specify directive with type alias")
702+
pragma = 0
703+
}
704+
705+
n.Local = true
706+
707+
p := n.Name.Param
708+
p.Ntype = t
709+
p.Pragma = pragma
710+
p.Alias = alias
711+
702712
return nod(ODCLTYPE, n, nil)
703713
}
704714

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

+23-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ func exportsym(n *Node) {
4545
fmt.Printf("export symbol %v\n", n.Sym)
4646
}
4747

48-
// Ensure original object is on exportlist before aliases.
49-
if n.Sym.Flags&SymAlias != 0 {
48+
// Ensure original types are on exportlist before type aliases.
49+
if n.Sym.isAlias() {
5050
exportlist = append(exportlist, n.Sym.Def)
5151
}
5252

@@ -348,6 +348,27 @@ func importvar(s *Sym, t *Type) {
348348
}
349349
}
350350

351+
// importalias declares symbol s as an imported type alias with type t.
352+
func importalias(s *Sym, t *Type) {
353+
importsym(s, OTYPE)
354+
if s.Def != nil && s.Def.Op == OTYPE {
355+
if eqtype(t, s.Def.Type) {
356+
return
357+
}
358+
yyerror("inconsistent definition for type alias %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path)
359+
}
360+
361+
n := newname(s)
362+
n.Op = OTYPE
363+
s.Importdef = importpkg
364+
n.Type = t
365+
declare(n, PEXTERN)
366+
367+
if Debug['E'] != 0 {
368+
fmt.Printf("import type %v = %L\n", s, t)
369+
}
370+
}
371+
351372
func dumpasmhdr() {
352373
b, err := bio.Create(asmhdr)
353374
if err != nil {

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

+6-3
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,12 @@ const (
6363
SymSiggen
6464
SymAsm
6565
SymAlgGen
66-
SymAlias // alias, original is Sym.Def.Sym
6766
)
6867

68+
func (sym *Sym) isAlias() bool {
69+
return sym.Def != nil && sym.Def.Sym != sym
70+
}
71+
6972
// The Class of a variable/function describes the "storage class"
7073
// of a variable or function. During parsing, storage classes are
7174
// called declaration contexts.
@@ -87,7 +90,7 @@ const (
8790
// of the compilers arrays.
8891
//
8992
// typedef struct
90-
// { // must not move anything
93+
// { // must not move anything
9194
// uchar array[8]; // pointer to data
9295
// uchar nel[4]; // number of elements
9396
// uchar cap[4]; // allocated number of elements
@@ -104,7 +107,7 @@ var sizeof_Array int // runtime sizeof(Array)
104107
// of the compilers strings.
105108
//
106109
// typedef struct
107-
// { // must not move anything
110+
// { // must not move anything
108111
// uchar array[8]; // pointer to data
109112
// uchar nel[4]; // number of elements
110113
// } String;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,7 @@ func mkpackage(pkgname string) {
927927
continue
928928
}
929929

930-
if s.Def.Sym != s && s.Flags&SymAlias == 0 {
930+
if s.isAlias() {
931931
// throw away top-level name left over
932932
// from previous import . "x"
933933
if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {

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

+2-11
Original file line numberDiff line numberDiff line change
@@ -177,21 +177,12 @@ func (p *noder) constDecl(decl *syntax.ConstDecl) []*Node {
177177
}
178178

179179
func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
180-
if decl.Alias {
181-
yyerror("type alias declarations unimplemented")
182-
}
183-
184180
name := typedcl0(p.name(decl.Name))
185-
pragma := Pragma(decl.Pragma)
186-
if pragma != 0 && decl.Alias {
187-
yyerror("cannot specify directive with type alias")
188-
pragma = 0
189-
}
190-
name.Name.Param.Pragma = pragma
191181

182+
// decl.Type may be nil but in that case we got a syntax error during parsing
192183
typ := p.typeExprOrNil(decl.Type)
193184

194-
return typedcl1(name, typ, true)
185+
return typedcl1(name, typ, Pragma(decl.Pragma), decl.Alias)
195186
}
196187

197188
func (p *noder) declNames(names []*syntax.Name) []*Node {

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

+8-7
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type Node struct {
2727
// func
2828
Func *Func
2929

30-
// ONAME
30+
// ONAME, OTYPE, OPACK, OLABEL, some OLITERAL
3131
Name *Name
3232

3333
Sym *Sym // various
@@ -59,8 +59,8 @@ type Node struct {
5959
Noescape bool // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
6060
Walkdef uint8 // tracks state during typecheckdef; 2 == loop detected
6161
Typecheck uint8 // tracks state during typechecking; 2 == loop detected
62-
Local bool
63-
IsStatic bool // whether this Node will be converted to purely static data
62+
Local bool // type created in this file (see also Type.Local); TODO(gri): move this into flags
63+
IsStatic bool // whether this Node will be converted to purely static data
6464
Initorder uint8
6565
Used bool // for variable/label declared and not used error
6666
Isddd bool // is the argument variadic
@@ -180,14 +180,14 @@ func (n *Node) SetIota(x int64) {
180180
n.Xoffset = x
181181
}
182182

183-
// Name holds Node fields used only by named nodes (ONAME, OPACK, OLABEL, some OLITERAL).
183+
// Name holds Node fields used only by named nodes (ONAME, OTYPE, OPACK, OLABEL, some OLITERAL).
184184
type Name struct {
185185
Pack *Node // real package for import . names
186186
Pkg *Pkg // pkg for OPACK nodes
187187
Heapaddr *Node // temp holding heap address of param (could move to Param?)
188188
Defn *Node // initializing assignment
189189
Curfn *Node // function for local variables
190-
Param *Param // additional fields for ONAME
190+
Param *Param // additional fields for ONAME, OTYPE
191191
Decldepth int32 // declaration loop depth, increased for every loop or label
192192
Vargen int32 // unique name for ONAME within a function. Function outputs are numbered starting at one.
193193
Funcdepth int32
@@ -280,10 +280,11 @@ type Param struct {
280280
Innermost *Node
281281
Outer *Node
282282

283-
// OTYPE pragmas
283+
// OTYPE
284284
//
285285
// TODO: Should Func pragmas also be stored on the Name?
286286
Pragma Pragma
287+
Alias bool // node is alias for Ntype
287288
}
288289

289290
// Func holds Node fields used only with function-like nodes.
@@ -382,7 +383,7 @@ const (
382383
ODCLFUNC // func f() or func (r) f()
383384
ODCLFIELD // struct field, interface field, or func/method argument/return value.
384385
ODCLCONST // const pi = 3.14
385-
ODCLTYPE // type Int int
386+
ODCLTYPE // type Int int or type Int = int
386387

387388
ODELETE // delete(Left, Right)
388389
ODOT // Left.Sym (Left is of struct type)

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

+18-4
Original file line numberDiff line numberDiff line change
@@ -3578,8 +3578,6 @@ func typecheckdeftype(n *Node) {
35783578

35793579
// copy new type and clear fields
35803580
// that don't come along.
3581-
// anything zeroed here must be zeroed in
3582-
// typedcl2 too.
35833581
copytype(n, t)
35843582

35853583
ret:
@@ -3758,20 +3756,36 @@ func typecheckdef(n *Node) *Node {
37583756
n.Name.Defn = typecheck(n.Name.Defn, Etop) // fills in n->type
37593757

37603758
case OTYPE:
3759+
if p := n.Name.Param; p.Alias {
3760+
// Type alias declaration: Simply use the rhs type - no need
3761+
// to create a new type.
3762+
// If we have a syntax error, p.Ntype may be nil.
3763+
if p.Ntype != nil {
3764+
p.Ntype = typecheck(p.Ntype, Etype)
3765+
n.Type = p.Ntype.Type
3766+
if n.Type == nil {
3767+
n.Diag = true
3768+
goto ret
3769+
}
3770+
n.Sym.Def = p.Ntype
3771+
}
3772+
break
3773+
}
3774+
3775+
// regular type declaration
37613776
if Curfn != nil {
37623777
defercheckwidth()
37633778
}
37643779
n.Walkdef = 1
37653780
n.Type = typ(TFORW)
3766-
n.Type.Sym = n.Sym
3781+
n.Type.Sym = n.Sym // TODO(gri) this also happens in typecheckdeftype(n) - where should it happen?
37673782
nerrors0 := nerrors
37683783
typecheckdeftype(n)
37693784
if n.Type.Etype == TFORW && nerrors > nerrors0 {
37703785
// Something went wrong during type-checking,
37713786
// but it was reported. Silence future errors.
37723787
n.Type.Broke = true
37733788
}
3774-
37753789
if Curfn != nil {
37763790
resumecheckwidth()
37773791
}

0 commit comments

Comments
 (0)