p.tracef("\n")
}
- if sym.Flags&SymAlias != 0 {
- Fatalf("exporter: unexpected alias %v in inlined function body", sym)
+ if sym.isAlias() {
+ Fatalf("exporter: unexpected type alias %v in inlined function body", sym)
}
p.obj(sym)
Fatalf("exporter: export of incomplete type %v", sym)
}
- const alias = false // TODO(gri) fix this
- if alias {
+ if sym.isAlias() {
p.tag(aliasTag)
p.pos(n)
p.qualifiedName(sym)
importconst(sym, idealType(typ), nodlit(val))
case aliasTag:
- // TODO(gri) hook up type alias
p.pos()
- p.qualifiedName()
- p.typ()
+ sym := p.qualifiedName()
+ typ := p.typ()
+ importalias(sym, typ)
case typeTag:
p.typ()
func (p *importer) field() *Field {
p.pos()
- sym := p.fieldName()
+ sym, alias := p.fieldName()
typ := p.typ()
note := p.string()
}
sym = sym.Pkg.Lookup(s.Name)
f.Embedded = 1
- } else if sym.Flags&SymAlias != 0 {
- // anonymous field: we have an explicit name because it's an alias
+ } else if alias {
+ // anonymous field: we have an explicit name because it's a type alias
f.Embedded = 1
}
return f
}
-func (p *importer) fieldName() *Sym {
+func (p *importer) fieldName() (*Sym, bool) {
name := p.string()
if p.version == 0 && name == "_" {
// version 0 didn't export a package for _ field names
// but used the builtin package instead
- return builtinpkg.Lookup(name)
+ return builtinpkg.Lookup(name), false
}
pkg := localpkg
- var flag SymFlags
+ alias := false
switch name {
case "":
// 1) field name matches base type name and is exported: nothing to do
case "@":
// 3) field name doesn't match base type name (alias name): need name and possibly package
name = p.string()
- flag = SymAlias
+ alias = true
fallthrough
default:
if !exportname(name) {
pkg = p.pkg()
}
}
- sym := pkg.Lookup(name)
- sym.Flags |= flag
- return sym
+ return pkg.Lookup(name), alias
}
func (p *importer) methodName() *Sym {
// node n, which was returned by typedcl0
// is being declared to have uncompiled type t.
-// return the ODCLTYPE node to use.
-func typedcl1(n *Node, t *Node, local bool) *Node {
- n.Name.Param.Ntype = t
- n.Local = local
+// returns the ODCLTYPE node to use.
+func typedcl1(n *Node, t *Node, pragma Pragma, alias bool) *Node {
+ if pragma != 0 && alias {
+ yyerror("cannot specify directive with type alias")
+ pragma = 0
+ }
+
+ n.Local = true
+
+ p := n.Name.Param
+ p.Ntype = t
+ p.Pragma = pragma
+ p.Alias = alias
+
return nod(ODCLTYPE, n, nil)
}
fmt.Printf("export symbol %v\n", n.Sym)
}
- // Ensure original object is on exportlist before aliases.
- if n.Sym.Flags&SymAlias != 0 {
+ // Ensure original types are on exportlist before type aliases.
+ if n.Sym.isAlias() {
exportlist = append(exportlist, n.Sym.Def)
}
}
}
+// importalias declares symbol s as an imported type alias with type t.
+func importalias(s *Sym, t *Type) {
+ importsym(s, OTYPE)
+ if s.Def != nil && s.Def.Op == OTYPE {
+ if eqtype(t, s.Def.Type) {
+ return
+ }
+ 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)
+ }
+
+ n := newname(s)
+ n.Op = OTYPE
+ s.Importdef = importpkg
+ n.Type = t
+ declare(n, PEXTERN)
+
+ if Debug['E'] != 0 {
+ fmt.Printf("import type %v = %L\n", s, t)
+ }
+}
+
func dumpasmhdr() {
b, err := bio.Create(asmhdr)
if err != nil {
SymSiggen
SymAsm
SymAlgGen
- SymAlias // alias, original is Sym.Def.Sym
)
+func (sym *Sym) isAlias() bool {
+ return sym.Def != nil && sym.Def.Sym != sym
+}
+
// The Class of a variable/function describes the "storage class"
// of a variable or function. During parsing, storage classes are
// called declaration contexts.
// of the compilers arrays.
//
// typedef struct
-// { // must not move anything
+// { // must not move anything
// uchar array[8]; // pointer to data
// uchar nel[4]; // number of elements
// uchar cap[4]; // allocated number of elements
// of the compilers strings.
//
// typedef struct
-// { // must not move anything
+// { // must not move anything
// uchar array[8]; // pointer to data
// uchar nel[4]; // number of elements
// } String;
continue
}
- if s.Def.Sym != s && s.Flags&SymAlias == 0 {
+ if s.isAlias() {
// throw away top-level name left over
// from previous import . "x"
if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
}
func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
- if decl.Alias {
- yyerror("type alias declarations unimplemented")
- }
-
name := typedcl0(p.name(decl.Name))
- pragma := Pragma(decl.Pragma)
- if pragma != 0 && decl.Alias {
- yyerror("cannot specify directive with type alias")
- pragma = 0
- }
- name.Name.Param.Pragma = pragma
+ // decl.Type may be nil but in that case we got a syntax error during parsing
typ := p.typeExprOrNil(decl.Type)
- return typedcl1(name, typ, true)
+ return typedcl1(name, typ, Pragma(decl.Pragma), decl.Alias)
}
func (p *noder) declNames(names []*syntax.Name) []*Node {
// func
Func *Func
- // ONAME
+ // ONAME, OTYPE, OPACK, OLABEL, some OLITERAL
Name *Name
Sym *Sym // various
Noescape bool // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
Walkdef uint8 // tracks state during typecheckdef; 2 == loop detected
Typecheck uint8 // tracks state during typechecking; 2 == loop detected
- Local bool
- IsStatic bool // whether this Node will be converted to purely static data
+ Local bool // type created in this file (see also Type.Local); TODO(gri): move this into flags
+ IsStatic bool // whether this Node will be converted to purely static data
Initorder uint8
Used bool // for variable/label declared and not used error
Isddd bool // is the argument variadic
n.Xoffset = x
}
-// Name holds Node fields used only by named nodes (ONAME, OPACK, OLABEL, some OLITERAL).
+// Name holds Node fields used only by named nodes (ONAME, OTYPE, OPACK, OLABEL, some OLITERAL).
type Name struct {
Pack *Node // real package for import . names
Pkg *Pkg // pkg for OPACK nodes
Heapaddr *Node // temp holding heap address of param (could move to Param?)
Defn *Node // initializing assignment
Curfn *Node // function for local variables
- Param *Param // additional fields for ONAME
+ Param *Param // additional fields for ONAME, OTYPE
Decldepth int32 // declaration loop depth, increased for every loop or label
Vargen int32 // unique name for ONAME within a function. Function outputs are numbered starting at one.
Funcdepth int32
Innermost *Node
Outer *Node
- // OTYPE pragmas
+ // OTYPE
//
// TODO: Should Func pragmas also be stored on the Name?
Pragma Pragma
+ Alias bool // node is alias for Ntype
}
// Func holds Node fields used only with function-like nodes.
ODCLFUNC // func f() or func (r) f()
ODCLFIELD // struct field, interface field, or func/method argument/return value.
ODCLCONST // const pi = 3.14
- ODCLTYPE // type Int int
+ ODCLTYPE // type Int int or type Int = int
ODELETE // delete(Left, Right)
ODOT // Left.Sym (Left is of struct type)
// copy new type and clear fields
// that don't come along.
- // anything zeroed here must be zeroed in
- // typedcl2 too.
copytype(n, t)
ret:
n.Name.Defn = typecheck(n.Name.Defn, Etop) // fills in n->type
case OTYPE:
+ if p := n.Name.Param; p.Alias {
+ // Type alias declaration: Simply use the rhs type - no need
+ // to create a new type.
+ // If we have a syntax error, p.Ntype may be nil.
+ if p.Ntype != nil {
+ p.Ntype = typecheck(p.Ntype, Etype)
+ n.Type = p.Ntype.Type
+ if n.Type == nil {
+ n.Diag = true
+ goto ret
+ }
+ n.Sym.Def = p.Ntype
+ }
+ break
+ }
+
+ // regular type declaration
if Curfn != nil {
defercheckwidth()
}
n.Walkdef = 1
n.Type = typ(TFORW)
- n.Type.Sym = n.Sym
+ n.Type.Sym = n.Sym // TODO(gri) this also happens in typecheckdeftype(n) - where should it happen?
nerrors0 := nerrors
typecheckdeftype(n)
if n.Type.Etype == TFORW && nerrors > nerrors0 {
// but it was reported. Silence future errors.
n.Type.Broke = true
}
-
if Curfn != nil {
resumecheckwidth()
}
// Test basic restrictions on type aliases.
-// The compiler doesn't implement type aliases yet,
-// so for now we get the same error (unimplemented)
-// everywhere, OR-ed into the ERROR checks.
-// TODO(gri) remove the need for "unimplemented"
-
package p
import (
. "reflect"
)
+type T0 struct{}
+
// Valid type alias declarations.
-type _ = int // ERROR "unimplemented"
-type _ = struct{} // ERROR "unimplemented"
-type _ = reflect.Value // ERROR "unimplemented"
-type _ = Value // ERROR "unimplemented"
+type _ = T0
+type _ = int
+type _ = struct{}
+type _ = reflect.Value
+type _ = Value
type (
- a1 = int // ERROR "unimplemented"
- a2 = struct{} // ERROR "unimplemented"
- a3 = reflect.Value // ERROR "unimplemented"
- a4 = Value // ERROR "unimplemented"
+ A0 = T0
+ A1 = int
+ A2 = struct{}
+ A3 = reflect.Value
+ A4 = Value
+ A5 = Value
+
+ N0 A0
)
+// Methods can be declared on the original named type and the alias.
+func (T0) m1() {}
+func (A0) m1() {} // TODO(gri) this should be an error
+func (A0) m2() {}
+
+// Type aliases and the original type name can be used interchangeably.
+var _ A0 = T0{}
+var _ T0 = A0{}
+
+// But aliases and original types cannot be used with new types based on them.
+var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment"
+var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment"
+
+var _ A5 = Value{}
+
+var _ interface {
+ m1()
+ m2()
+} = T0{}
+
+var _ interface {
+ m1()
+ m2()
+} = A0{}
+
func _() {
- type _ = int // ERROR "unimplemented"
- type _ = struct{} // ERROR "unimplemented"
- type _ = reflect.Value // ERROR "unimplemented"
- type _ = Value // ERROR "unimplemented"
+ type _ = T0
+ type _ = int
+ type _ = struct{}
+ type _ = reflect.Value
+ type _ = Value
type (
- a1 = int // ERROR "unimplemented"
- a2 = struct{} // ERROR "unimplemented"
- a3 = reflect.Value // ERROR "unimplemented"
- a4 = Value // ERROR "unimplemented"
+ A0 = T0
+ A1 = int
+ A2 = struct{}
+ A3 = reflect.Value
+ A4 = Value
+ A5 Value
+
+ N0 A0
)
+
+ var _ A0 = T0{}
+ var _ T0 = A0{}
+
+ var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment"
+ var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment"
+
+ var _ A5 = Value{} // ERROR "cannot use reflect\.Value literal \(type reflect.Value\) as type A5 in assignment"
}
// Invalid type alias declarations.
-type _ = reflect.ValueOf // ERROR "reflect.ValueOf is not a type|unimplemented"
+type _ = reflect.ValueOf // ERROR "reflect.ValueOf is not a type"
+
+func (A1) m() {} // ERROR "cannot define new methods on non-local type int"
+
+type B1 = struct{}
-type b1 = struct{} // ERROR "unimplemented"
-func (b1) m() {} // disabled ERROR "invalid receiver type"
+func (B1) m() {} // ERROR "invalid receiver type"
// TODO(gri) expand
-// It appears that type-checking exits after some more severe errors, so we may
-// need more test files.