diff options
Diffstat (limited to 'src/go/types/decl.go')
-rw-r--r-- | src/go/types/decl.go | 67 |
1 files changed, 41 insertions, 26 deletions
diff --git a/src/go/types/decl.go b/src/go/types/decl.go index d132d30b9d..0fdcfa8023 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -65,6 +65,12 @@ func (check *Checker) objDecl(obj Object, def *Named) { }() } + // Funcs with m.instRecv set have not yet be completed. Complete them now + // so that they have a type when objDecl exits. + if m, _ := obj.(*Func); m != nil && m.instRecv != nil { + check.completeMethod(check.conf.Environment, m) + } + // Checking the declaration of obj means inferring its type // (and possibly its value, for constants). // An object's type (and thus the object) may be in one of @@ -316,7 +322,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo { } case *Named: - t.expand(check.env) + t.resolve(check.conf.Environment) // don't touch the type if it is from a different package or the Universe scope // (doing so would lead to a race condition - was issue #35049) if t.obj.pkg != check.pkg { @@ -615,7 +621,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { if tdecl.TypeParams != nil { check.openScope(tdecl, "type parameters") defer check.closeScope() - named.tparams = check.collectTypeParams(tdecl.TypeParams) + check.collectTypeParams(&named.tparams, tdecl.TypeParams) } // determine underlying type of named @@ -647,7 +653,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) { } } -func (check *Checker) collectTypeParams(list *ast.FieldList) *TypeParamList { +func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList) { var tparams []*TypeParam // Declare type parameters up-front, with empty interface as type bound. // The scope of type parameters starts at the beginning of the type parameter @@ -656,13 +662,28 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) *TypeParamList { tparams = check.declareTypeParams(tparams, f.Names) } + // Set the type parameters before collecting the type constraints because + // the parameterized type may be used by the constraints (issue #47887). + // Example: type T[P T[P]] interface{} + *dst = bindTParams(tparams) + index := 0 var bound Type + var bounds []Type + var posns []positioner // bound positions for _, f := range list.List { if f.Type == nil { goto next } - bound = check.boundType(f.Type) + // The predeclared identifier "any" is visible only as a type bound in a type parameter list. + // If we allow "any" for general use, this if-statement can be removed (issue #33232). + if name, _ := unparen(f.Type).(*ast.Ident); name != nil && name.Name == "any" && check.lookup("any") == universeAny { + bound = universeAny.Type() + } else { + bound = check.typ(f.Type) + } + bounds = append(bounds, bound) + posns = append(posns, f.Type) for i := range f.Names { tparams[index+i].bound = bound } @@ -671,13 +692,26 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) *TypeParamList { index += len(f.Names) } - return bindTParams(tparams) + check.later(func() { + for i, bound := range bounds { + u := under(bound) + if _, ok := u.(*Interface); !ok && u != Typ[Invalid] { + check.errorf(posns[i], _Todo, "%s is not an interface", bound) + } + } + }) } func (check *Checker) declareTypeParams(tparams []*TypeParam, names []*ast.Ident) []*TypeParam { + // Use Typ[Invalid] for the type constraint to ensure that a type + // is present even if the actual constraint has not been assigned + // yet. + // TODO(gri) Need to systematically review all uses of type parameter + // constraints to make sure we don't rely on them if they + // are not properly set yet. for _, name := range names { tname := NewTypeName(name.Pos(), check.pkg, name.Name, nil) - tpar := check.newTypeParam(tname, &emptyInterface) // assigns type to tpar as a side-effect + tpar := check.newTypeParam(tname, Typ[Invalid]) // assigns type to tpar as a side-effect check.declare(check.scope, name, tname, check.scope.pos) // TODO(gri) check scope position tparams = append(tparams, tpar) } @@ -689,25 +723,6 @@ func (check *Checker) declareTypeParams(tparams []*TypeParam, names []*ast.Ident return tparams } -// boundType type-checks the type expression e and returns its type, or Typ[Invalid]. -// The type must be an interface, including the predeclared type "any". -func (check *Checker) boundType(e ast.Expr) Type { - // The predeclared identifier "any" is visible only as a type bound in a type parameter list. - // If we allow "any" for general use, this if-statement can be removed (issue #33232). - if name, _ := unparen(e).(*ast.Ident); name != nil && name.Name == "any" && check.lookup("any") == universeAny { - return universeAny.Type() - } - - bound := check.typ(e) - check.later(func() { - u := under(bound) - if _, ok := u.(*Interface); !ok && u != Typ[Invalid] { - check.errorf(e, _Todo, "%s is not an interface", bound) - } - }) - return bound -} - func (check *Checker) collectMethods(obj *TypeName) { // get associated methods // (Checker.collectObjects only collects methods with non-blank names; @@ -764,7 +779,7 @@ func (check *Checker) collectMethods(obj *TypeName) { } if base != nil { - base.load() // TODO(mdempsky): Probably unnecessary. + base.resolve(nil) // TODO(mdempsky): Probably unnecessary. base.methods = append(base.methods, m) } } |