mirror of https://github.com/golang/go.git
go/types: more fixes around parameterized types
Change-Id: I81e6e70a2833e7dbb17f5155386ed3c7a75dc2ac
This commit is contained in:
parent
d5d25288d4
commit
0ffe62a473
|
|
@ -112,7 +112,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
|||
|
||||
// if type inference failed, a parametrized result must be invalidated
|
||||
// (operands cannot have a parametrized type)
|
||||
if x.mode == value && len(sig.tparams) > 0 && isParametrized(x.typ) {
|
||||
if x.mode == value && len(sig.tparams) > 0 && isParameterized(x.typ) {
|
||||
x.mode = invalid
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import (
|
|||
|
||||
// debugging/development support
|
||||
const (
|
||||
debug = false // leave on during development
|
||||
debug = true // leave on during development
|
||||
trace = false // turn on for detailed type resolution traces
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a
|
|||
var indices []int
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
par := params.At(i).typ
|
||||
if isParametrized(par) {
|
||||
if isParameterized(par) {
|
||||
indices = append(indices, i)
|
||||
}
|
||||
}
|
||||
|
|
@ -71,50 +71,53 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a
|
|||
return targs
|
||||
}
|
||||
|
||||
// isParametrized reports whether typ contains any type parameters.
|
||||
// isParameterized reports whether typ contains any type parameters.
|
||||
// TODO(gri) do we need to handle cycles here?
|
||||
func isParametrized(typ Type) bool {
|
||||
func isParameterized(typ Type) bool {
|
||||
switch t := typ.(type) {
|
||||
case nil, *Basic, *Named: // TODO(gri) should nil be handled here?
|
||||
break
|
||||
|
||||
case *Array:
|
||||
return isParametrized(t.elem)
|
||||
return isParameterized(t.elem)
|
||||
|
||||
case *Slice:
|
||||
return isParametrized(t.elem)
|
||||
return isParameterized(t.elem)
|
||||
|
||||
case *Struct:
|
||||
for _, fld := range t.fields {
|
||||
if isParametrized(fld.typ) {
|
||||
if isParameterized(fld.typ) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
case *Pointer:
|
||||
return isParametrized(t.base)
|
||||
return isParameterized(t.base)
|
||||
|
||||
case *Tuple:
|
||||
n := t.Len()
|
||||
for i := 0; i < n; i++ {
|
||||
if isParametrized(t.At(i).typ) {
|
||||
if isParameterized(t.At(i).typ) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
case *Signature:
|
||||
assert(t.tparams == nil) // TODO(gri) is this correct?
|
||||
assert(t.recv == nil || !isParametrized(t.recv.typ)) // interface method receiver may not be nil
|
||||
return isParametrized(t.params) || isParametrized(t.results)
|
||||
assert(t.tparams == nil) // TODO(gri) is this correct?
|
||||
assert(t.recv == nil || !isParameterized(t.recv.typ)) // interface method receiver may not be nil
|
||||
return isParameterized(t.params) || isParameterized(t.results)
|
||||
|
||||
case *Interface:
|
||||
panic("unimplemented")
|
||||
|
||||
case *Map:
|
||||
return isParametrized(t.key) || isParametrized(t.elem)
|
||||
return isParameterized(t.key) || isParameterized(t.elem)
|
||||
|
||||
case *Chan:
|
||||
return isParametrized(t.elem)
|
||||
return isParameterized(t.elem)
|
||||
|
||||
case *Parameterized:
|
||||
return isParameterizedList(t.targs)
|
||||
|
||||
case *TypeParam:
|
||||
return true
|
||||
|
|
@ -125,3 +128,13 @@ func isParametrized(typ Type) bool {
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
// isParameterizedList reports whether any type in list is parameterized.
|
||||
func isParameterizedList(list []Type) bool {
|
||||
for _, t := range list {
|
||||
if isParameterized(t) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,9 @@ func f(type P) (x P) List(P) {
|
|||
}
|
||||
|
||||
var (
|
||||
//_ []int = f(0)
|
||||
//_ []float32 = f(float32)(10)
|
||||
// TODO(gri) fix next line
|
||||
// [](List(int)) = f(List(int){})
|
||||
// _ List(List(int)) = [](List(int)){}
|
||||
// _ = [](List(int)){}
|
||||
_ []int = f(0)
|
||||
_ []float32 = f(float32)(10)
|
||||
_ [](List(int)) = f(List(int){})
|
||||
_ List(List(int)) = [](List(int)){}
|
||||
_ = [](List(int)){}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -33,4 +33,17 @@ func _() {
|
|||
var x1 T3(int)
|
||||
var x2 T2(int, int)
|
||||
x1.f1.f2 = x2
|
||||
}
|
||||
}
|
||||
|
||||
func f(type P) (x P) List(P) {
|
||||
return List(P){x}
|
||||
}
|
||||
|
||||
var (
|
||||
_ []int = f(0)
|
||||
_ []float32 = f(float32)(10)
|
||||
_ List(complex128) = f(1i)
|
||||
_ [](List(int)) = f(List(int){})
|
||||
_ List(List(int)) = [](List(int)){}
|
||||
_ = [](List(int)){}
|
||||
)
|
||||
|
|
@ -276,6 +276,11 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
|
|||
typ := new(Parameterized)
|
||||
def.setUnderlying(typ)
|
||||
if check.parameterizedType(typ, e) {
|
||||
if isParameterizedList(typ.targs) {
|
||||
return typ
|
||||
}
|
||||
typ := check.inst(typ.tname, typ.targs)
|
||||
def.setUnderlying(typ) // TODO(gri) do we need this?
|
||||
return typ
|
||||
}
|
||||
// TODO(gri) If we have a cycle and we reach here, "leafs" of
|
||||
|
|
@ -480,11 +485,6 @@ func (check *Checker) parameterizedType(typ *Parameterized, e *ast.CallExpr) boo
|
|||
return false
|
||||
}
|
||||
|
||||
// TODO(gri) If none of the arguments is parameterized than we can instantiate the type.
|
||||
// When instantiating, it will become a different type, at which point the outer type is
|
||||
// not correct anymore (it's not a Parameterized). If it's defined type, it may also have
|
||||
// methods and we don't deal with those either... :-(
|
||||
|
||||
// complete parameterized type
|
||||
typ.tname = tname
|
||||
typ.targs = args
|
||||
|
|
|
|||
Loading…
Reference in New Issue