Commit fce91186 authored by Robert Griesemer's avatar Robert Griesemer

- handling of pointer forward decls

- some comments added to bug cases
- added notes

R=r
OCL=13543
CL=13543
parent f436ade2
...@@ -13,3 +13,11 @@ type S struct { ...@@ -13,3 +13,11 @@ type S struct {
func main() { func main() {
var s S; var s S;
} }
/*
Another problem with implicit forward declarations (as in this program on line 6)
is that it is not clear in which scope the type (here "T") should be declared.
This is the main reason why we should not allow implicit forward declarations at all,
and instead have an explicit type forward declaration. For more on this subject
see bug042.go.
*/
...@@ -18,3 +18,11 @@ type T struct { ...@@ -18,3 +18,11 @@ type T struct {
func main() { func main() {
var s S; var s S;
} }
/*
Per discussion w/ Ken, some time ago, we came to the conclusion that explicit
forward declarations (as on line 5 in this program) are preferrable over
implicit forward declarations because they make it explicit in which scope a
type is to be declared fully, eventually. As an aside, the machinery for it is
almost free in the compiler (one extra 'if' as far as I can tell).
*/
...@@ -115,7 +115,7 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) { ...@@ -115,7 +115,7 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
// determine number of objects to export // determine number of objects to export
n := 0; n := 0;
for p := scope.entries.first; p != nil; p = p.next { for p := scope.entries.first; p != nil; p = p.next {
if p.obj.mark { if p.obj.exported {
n++; n++;
} }
} }
...@@ -123,7 +123,7 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) { ...@@ -123,7 +123,7 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
// export the objects, if any // export the objects, if any
if n > 0 { if n > 0 {
for p := scope.entries.first; p != nil; p = p.next { for p := scope.entries.first; p != nil; p = p.next {
if p.obj.mark { if p.obj.exported {
E.WriteObject(p.obj); E.WriteObject(p.obj);
} }
} }
...@@ -136,8 +136,8 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) { ...@@ -136,8 +136,8 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
func (E *Exporter) WriteObject(obj *Globals.Object) { func (E *Exporter) WriteObject(obj *Globals.Object) {
if obj == nil || !obj.mark { if obj == nil || !obj.exported {
panic "obj == nil || !obj.mark"; panic "obj == nil || !obj.exported";
} }
if obj.kind == Object.TYPE && obj.typ.obj == obj { if obj.kind == Object.TYPE && obj.typ.obj == obj {
...@@ -274,7 +274,7 @@ func (E *Exporter) Export(comp* Globals.Compilation, file_name string) { ...@@ -274,7 +274,7 @@ func (E *Exporter) Export(comp* Globals.Compilation, file_name string) {
pkg := comp.pkgs[0]; pkg := comp.pkgs[0];
E.WritePackage(pkg); E.WritePackage(pkg);
for p := pkg.scope.entries.first; p != nil; p = p.next { for p := pkg.scope.entries.first; p != nil; p = p.next {
if p.obj.mark { if p.obj.exported {
E.WriteObject(p.obj); E.WriteObject(p.obj);
} }
} }
......
...@@ -15,7 +15,7 @@ package Globals ...@@ -15,7 +15,7 @@ package Globals
export Object export Object
type Object struct { type Object struct {
mark bool; // mark => object marked for export exported bool;
pos int; // source position pos int; // source position
kind int; kind int;
ident string; ident string;
...@@ -89,7 +89,7 @@ type Compilation struct { ...@@ -89,7 +89,7 @@ type Compilation struct {
export NewObject export NewObject
func NewObject(pos, kind int, ident string) *Object { func NewObject(pos, kind int, ident string) *Object {
obj := new(Object); obj := new(Object);
obj.mark = false; obj.exported = false;
obj.pos = pos; obj.pos = pos;
obj.kind = kind; obj.kind = kind;
obj.ident = ident; obj.ident = ident;
......
...@@ -29,6 +29,7 @@ type Parser struct { ...@@ -29,6 +29,7 @@ type Parser struct {
// Semantic analysis // Semantic analysis
top_scope *Globals.Scope; top_scope *Globals.Scope;
undef_types *Globals.List;
exports *Globals.List; exports *Globals.List;
} }
...@@ -77,6 +78,7 @@ func (P *Parser) Open(comp *Globals.Compilation, S *Scanner.Scanner, verbose int ...@@ -77,6 +78,7 @@ func (P *Parser) Open(comp *Globals.Compilation, S *Scanner.Scanner, verbose int
P.S = S; P.S = S;
P.Next(); P.Next();
P.top_scope = Universe.scope; P.top_scope = Universe.scope;
P.undef_types = Globals.NewList();
P.exports = Globals.NewList(); P.exports = Globals.NewList();
} }
...@@ -244,7 +246,7 @@ func (P *Parser) ParseQualifiedIdent(pos int, ident string) *Globals.Object { ...@@ -244,7 +246,7 @@ func (P *Parser) ParseQualifiedIdent(pos int, ident string) *Globals.Object {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Types // Types
func (P *Parser) ParseType() *Globals.Type{ func (P *Parser) ParseType() *Globals.Type {
P.Trace("Type"); P.Trace("Type");
typ := P.TryType(); typ := P.TryType();
...@@ -262,10 +264,11 @@ func (P *Parser) ParseTypeName() *Globals.Type { ...@@ -262,10 +264,11 @@ func (P *Parser) ParseTypeName() *Globals.Type {
P.Trace("TypeName"); P.Trace("TypeName");
if EnableSemanticTests { if EnableSemanticTests {
pos := P.pos;
obj := P.ParseQualifiedIdent(-1, ""); obj := P.ParseQualifiedIdent(-1, "");
typ := obj.typ; typ := obj.typ;
if obj.kind != Object.TYPE { if obj.kind != Object.TYPE {
P.Error(obj.pos, `"` + obj.ident + `" is not a type`); P.Error(pos, "qualified identifier does not denote a type");
typ = Universe.bad_t; typ = Universe.bad_t;
} }
P.Ecart(); P.Ecart();
...@@ -571,12 +574,38 @@ func (P *Parser) ParsePointerType() *Globals.Type { ...@@ -571,12 +574,38 @@ func (P *Parser) ParsePointerType() *Globals.Type {
P.Trace("PointerType"); P.Trace("PointerType");
P.Expect(Scanner.MUL); P.Expect(Scanner.MUL);
typ := Universe.undef_t; typ := Globals.NewType(Type.POINTER);
if (EnableSemanticTests && P.tok == Scanner.IDENT && P.Lookup(P.val) == nil) {
// forward declaration if EnableSemanticTests {
panic "UNIMPLEMENTED *forward_declared_type"; if P.tok == Scanner.IDENT {
if P.Lookup(P.val) == nil {
// implicit forward declaration
// TODO very problematic: in which scope should the
// type object be declared? It's different if this
// is inside a struct or say in a var declaration.
// This code is only here for "compatibility" with 6g.
pos := P.pos;
obj := Globals.NewObject(pos, Object.TYPE, P.ParseIdent());
obj.typ = Globals.NewType(Type.UNDEF);
obj.typ.obj = obj; // primary type object
typ.elt = obj.typ;
// TODO obj should be declared, but scope is not clear
} else {
// type name
// (ParseType() doesn't permit incomplete types,
// so call ParseTypeName() here)
typ.elt = P.ParseTypeName();
}
} else {
typ.elt = P.ParseType();
}
// collect undefined pointer types
if typ.elt.form == Type.UNDEF {
P.undef_types.AddTyp(typ);
}
} else { } else {
typ = Globals.NewType(Type.POINTER);
typ.elt = P.ParseType(); typ.elt = P.ParseType();
} }
...@@ -589,6 +618,7 @@ func (P *Parser) ParsePointerType() *Globals.Type { ...@@ -589,6 +618,7 @@ func (P *Parser) ParsePointerType() *Globals.Type {
func (P *Parser) TryType() *Globals.Type { func (P *Parser) TryType() *Globals.Type {
P.Trace("Type (try)"); P.Trace("Type (try)");
pos := P.pos;
var typ *Globals.Type = nil; var typ *Globals.Type = nil;
switch P.tok { switch P.tok {
case Scanner.IDENT: typ = P.ParseTypeName(); case Scanner.IDENT: typ = P.ParseTypeName();
...@@ -601,6 +631,10 @@ func (P *Parser) TryType() *Globals.Type { ...@@ -601,6 +631,10 @@ func (P *Parser) TryType() *Globals.Type {
case Scanner.MUL: typ = P.ParsePointerType(); case Scanner.MUL: typ = P.ParsePointerType();
} }
if typ != nil && typ.form == Type.UNDEF {
P.Error(pos, "incomplete type");
}
P.Ecart(); P.Ecart();
return typ; return typ;
} }
...@@ -1464,7 +1498,7 @@ func (P *Parser) ParseConstSpec(exported bool) { ...@@ -1464,7 +1498,7 @@ func (P *Parser) ParseConstSpec(exported bool) {
typ := P.TryType(); typ := P.TryType();
if typ != nil { if typ != nil {
for p := list.first; p != nil; p = p.next { for p := list.first; p != nil; p = p.next {
p.obj.mark = exported; p.obj.exported = exported;
p.obj.typ = typ; // TODO should use/have set_type()! p.obj.typ = typ; // TODO should use/have set_type()!
} }
} }
...@@ -1477,27 +1511,6 @@ func (P *Parser) ParseConstSpec(exported bool) { ...@@ -1477,27 +1511,6 @@ func (P *Parser) ParseConstSpec(exported bool) {
} }
func (P *Parser) ParseConstDecl(exported bool) {
P.Trace("ConstDecl");
P.Expect(Scanner.CONST);
if P.tok == Scanner.LPAREN {
P.Next();
for P.tok == Scanner.IDENT {
P.ParseConstSpec(exported);
if P.tok != Scanner.RPAREN {
P.Expect(Scanner.SEMICOLON);
}
}
P.Next();
} else {
P.ParseConstSpec(exported);
}
P.Ecart();
}
func (P *Parser) ParseTypeSpec(exported bool) { func (P *Parser) ParseTypeSpec(exported bool) {
P.Trace("TypeSpec"); P.Trace("TypeSpec");
...@@ -1505,22 +1518,23 @@ func (P *Parser) ParseTypeSpec(exported bool) { ...@@ -1505,22 +1518,23 @@ func (P *Parser) ParseTypeSpec(exported bool) {
ident := P.ParseIdent(); ident := P.ParseIdent();
obj := P.top_scope.Lookup(ident); // only lookup in top scope! obj := P.top_scope.Lookup(ident); // only lookup in top scope!
if obj != nil { if obj != nil {
// ok if forward declared type // name already declared - ok if forward declared type
if obj.kind != Object.TYPE || obj.typ.form != Type.UNDEF { if obj.kind != Object.TYPE || obj.typ.form != Type.UNDEF {
// TODO use obj.pos to refer to decl pos in error msg! // TODO use obj.pos to refer to decl pos in error msg!
P.Error(pos, `"` + ident + `" is declared already`); P.Error(pos, `"` + ident + `" is declared already`);
} }
} else { } else {
obj = Globals.NewObject(pos, Object.TYPE, ident); obj = Globals.NewObject(pos, Object.TYPE, ident);
obj.mark = exported; obj.exported = exported;
obj.typ = Universe.undef_t; // TODO fix this obj.typ = Globals.NewType(Type.UNDEF);
P.top_scope.Insert(obj); obj.typ.obj = obj; // primary type object
P.Declare(obj);
} }
typ := P.TryType(); // no type if we have a forward decl typ := P.TryType(); // nil if we have an explicit forward declaration
if typ != nil { if typ != nil {
// TODO what about the name of incomplete types? obj.typ = typ;
obj.typ = typ; // TODO should use/have set_typ()!
if typ.obj == nil { if typ.obj == nil {
typ.obj = obj; // primary type object typ.obj = obj; // primary type object
} }
...@@ -1530,27 +1544,6 @@ func (P *Parser) ParseTypeSpec(exported bool) { ...@@ -1530,27 +1544,6 @@ func (P *Parser) ParseTypeSpec(exported bool) {
} }
func (P *Parser) ParseTypeDecl(exported bool) {
P.Trace("TypeDecl");
P.Expect(Scanner.TYPE);
if P.tok == Scanner.LPAREN {
P.Next();
for P.tok == Scanner.IDENT {
P.ParseTypeSpec(exported);
if P.tok != Scanner.RPAREN {
P.Expect(Scanner.SEMICOLON);
}
}
P.Next();
} else {
P.ParseTypeSpec(exported);
}
P.Ecart();
}
func (P *Parser) ParseVarSpec(exported bool) { func (P *Parser) ParseVarSpec(exported bool) {
P.Trace("VarSpec"); P.Trace("VarSpec");
...@@ -1573,21 +1566,32 @@ func (P *Parser) ParseVarSpec(exported bool) { ...@@ -1573,21 +1566,32 @@ func (P *Parser) ParseVarSpec(exported bool) {
} }
func (P *Parser) ParseVarDecl(exported bool) { // TODO With method variables, we wouldn't need this dispatch function.
P.Trace("VarDecl"); func (P *Parser) ParseSpec(exported bool, keyword int) {
switch keyword {
case Scanner.CONST: P.ParseConstSpec(exported);
case Scanner.TYPE: P.ParseTypeSpec(exported);
case Scanner.VAR: P.ParseVarSpec(exported);
default: panic "UNREACHABLE";
}
}
func (P *Parser) ParseDecl(exported bool, keyword int) {
P.Trace("Decl");
P.Expect(Scanner.VAR); P.Expect(keyword);
if P.tok == Scanner.LPAREN { if P.tok == Scanner.LPAREN {
P.Next(); P.Next();
for P.tok == Scanner.IDENT { for P.tok == Scanner.IDENT {
P.ParseVarSpec(exported); P.ParseSpec(exported, keyword);
if P.tok != Scanner.RPAREN { if P.tok != Scanner.RPAREN {
P.Expect(Scanner.SEMICOLON); P.Expect(Scanner.SEMICOLON);
} }
} }
P.Next(); P.Next();
} else { } else {
P.ParseVarSpec(exported); P.ParseSpec(exported, keyword);
} }
P.Ecart(); P.Ecart();
...@@ -1643,12 +1647,8 @@ func (P *Parser) ParseDeclaration() { ...@@ -1643,12 +1647,8 @@ func (P *Parser) ParseDeclaration() {
exported = true; exported = true;
} }
switch P.tok { switch P.tok {
case Scanner.CONST: case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
P.ParseConstDecl(exported); P.ParseDecl(exported, P.tok);
case Scanner.TYPE:
P.ParseTypeDecl(exported);
case Scanner.VAR:
P.ParseVarDecl(exported);
case Scanner.FUNC: case Scanner.FUNC:
P.ParseFuncDecl(exported); P.ParseFuncDecl(exported);
case Scanner.EXPORT: case Scanner.EXPORT:
...@@ -1676,6 +1676,28 @@ func (P *Parser) ParseDeclaration() { ...@@ -1676,6 +1676,28 @@ func (P *Parser) ParseDeclaration() {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Program // Program
func (P *Parser) ResolveUndefTypes() {
if !EnableSemanticTests {
return;
}
for p := P.undef_types.first; p != nil; p = p.next {
typ := p.typ;
if typ.form != Type.POINTER {
panic "unresolved types should be pointers only";
}
if typ.elt.form != Type.UNDEF {
panic "unresolved pointer should point to undefined type";
}
obj := typ.elt.obj;
typ.elt = obj.typ;
if typ.elt.form == Type.UNDEF {
P.Error(obj.pos, `"` + obj.ident + `" is not declared`);
}
}
}
func (P *Parser) MarkExports() { func (P *Parser) MarkExports() {
if !EnableSemanticTests { if !EnableSemanticTests {
return; return;
...@@ -1685,7 +1707,7 @@ func (P *Parser) MarkExports() { ...@@ -1685,7 +1707,7 @@ func (P *Parser) MarkExports() {
for p := P.exports.first; p != nil; p = p.next { for p := P.exports.first; p != nil; p = p.next {
obj := scope.Lookup(p.str); obj := scope.Lookup(p.str);
if obj != nil { if obj != nil {
obj.mark = true; obj.exported = true;
// For now we export deep // For now we export deep
// TODO this should change eventually - we need selective export // TODO this should change eventually - we need selective export
if obj.kind == Object.TYPE { if obj.kind == Object.TYPE {
...@@ -1693,7 +1715,7 @@ func (P *Parser) MarkExports() { ...@@ -1693,7 +1715,7 @@ func (P *Parser) MarkExports() {
if typ.form == Type.STRUCT || typ.form == Type.INTERFACE { if typ.form == Type.STRUCT || typ.form == Type.INTERFACE {
scope := typ.scope; scope := typ.scope;
for p := scope.entries.first; p != nil; p = p.next { for p := scope.entries.first; p != nil; p = p.next {
p.obj.mark = true; p.obj.exported = true;
} }
} }
} }
...@@ -1726,6 +1748,7 @@ func (P *Parser) ParseProgram() { ...@@ -1726,6 +1748,7 @@ func (P *Parser) ParseProgram() {
P.Optional(Scanner.SEMICOLON); P.Optional(Scanner.SEMICOLON);
} }
P.ResolveUndefTypes();
P.MarkExports(); P.MarkExports();
P.CloseScope(); P.CloseScope();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment