aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2021-07-09 13:02:24 -0700
committerRobert Griesemer <gri@golang.org>2021-07-13 04:40:11 +0000
commit22e926546732e4ea1fb20551be4b91f51f3b6e65 (patch)
treed2f775b15c81044b86dda4a0cc119255daefecd3
parent1c783dc1480e8dec8bd4e76b744238607ea527f0 (diff)
downloadgo-22e926546732e4ea1fb20551be4b91f51f3b6e65.tar.gz
go-22e926546732e4ea1fb20551be4b91f51f3b6e65.zip
[dev.typeparams] cmd/compile/internal/types2: replace types2.Instantiate with Checker.Instantiate
Allow Checker.Instantiate to work with a nil *Checker receiver (for now). This opens the door to passing in a *Checker at all times. Also, added a verify flag to Instantiate, InstantiateLazy, and instance, to be able to control if constraint satisfaction should be checked or not. Removed types2.Instantiate. For #47103. Change-Id: Ie00ce41b3e50a0fc4341e013922e5f874276d282 Reviewed-on: https://go-review.googlesource.com/c/go/+/333569 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
-rw-r--r--src/cmd/compile/internal/importer/iimport.go3
-rw-r--r--src/cmd/compile/internal/noder/reader2.go2
-rw-r--r--src/cmd/compile/internal/types2/api_test.go4
-rw-r--r--src/cmd/compile/internal/types2/call.go4
-rw-r--r--src/cmd/compile/internal/types2/instance.go3
-rw-r--r--src/cmd/compile/internal/types2/instantiate.go64
-rw-r--r--src/cmd/compile/internal/types2/sizeof_test.go2
-rw-r--r--src/cmd/compile/internal/types2/subst.go55
-rw-r--r--src/cmd/compile/internal/types2/typexpr.go2
9 files changed, 56 insertions, 83 deletions
diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go
index 14e64891b8..453fa40f2d 100644
--- a/src/cmd/compile/internal/importer/iimport.go
+++ b/src/cmd/compile/internal/importer/iimport.go
@@ -665,7 +665,8 @@ func (r *importReader) doType(base *types2.Named) types2.Type {
baseType := r.typ()
// The imported instantiated type doesn't include any methods, so
// we must always use the methods of the base (orig) type.
- t := types2.Instantiate(pos, baseType, targs)
+ var check *types2.Checker // TODO provide a non-nil *Checker
+ t := check.Instantiate(pos, baseType, targs, nil, false)
return t
case unionType:
diff --git a/src/cmd/compile/internal/noder/reader2.go b/src/cmd/compile/internal/noder/reader2.go
index 89f224d389..92569ff843 100644
--- a/src/cmd/compile/internal/noder/reader2.go
+++ b/src/cmd/compile/internal/noder/reader2.go
@@ -224,7 +224,7 @@ func (r *reader2) doTyp() (res types2.Type) {
obj, targs := r.obj()
name := obj.(*types2.TypeName)
if len(targs) != 0 {
- return r.p.check.InstantiateLazy(syntax.Pos{}, name.Type(), targs)
+ return r.p.check.InstantiateLazy(syntax.Pos{}, name.Type(), targs, false)
}
return name.Type()
diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go
index 1c535387d4..74e3da3fe1 100644
--- a/src/cmd/compile/internal/types2/api_test.go
+++ b/src/cmd/compile/internal/types2/api_test.go
@@ -1862,7 +1862,9 @@ func TestInstantiate(t *testing.T) {
}
// instantiation should succeed (no endless recursion)
- res := Instantiate(nopos, T, []Type{Typ[Int]})
+ // even with a nil *Checker
+ var check *Checker
+ res := check.Instantiate(nopos, T, []Type{Typ[Int]}, nil, false)
// instantiated type should point to itself
if res.Underlying().(*Pointer).Elem() != res {
diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go
index 3377270ef8..0d9637e696 100644
--- a/src/cmd/compile/internal/types2/call.go
+++ b/src/cmd/compile/internal/types2/call.go
@@ -56,7 +56,7 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
}
// instantiate function signature
- res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature)
+ res := check.Instantiate(x.Pos(), sig, targs, poslist, true).(*Signature)
assert(res.tparams == nil) // signature is not generic anymore
if inferred {
check.recordInferred(inst, targs, res)
@@ -326,7 +326,7 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
}
// compute result signature
- rsig = check.instantiate(call.Pos(), sig, targs, nil).(*Signature)
+ rsig = check.Instantiate(call.Pos(), sig, targs, nil, true).(*Signature)
assert(rsig.tparams == nil) // signature is not generic anymore
check.recordInferred(call, targs, rsig)
diff --git a/src/cmd/compile/internal/types2/instance.go b/src/cmd/compile/internal/types2/instance.go
index b133fd1e65..65c2015507 100644
--- a/src/cmd/compile/internal/types2/instance.go
+++ b/src/cmd/compile/internal/types2/instance.go
@@ -16,6 +16,7 @@ type instance struct {
base *Named // parameterized type to be instantiated
targs []Type // type arguments
poslist []syntax.Pos // position of each targ; for error reporting only
+ verify bool // if set, constraint satisfaction is verified
value Type // base[targs...] after instantiation or Typ[Invalid]; nil if not yet set
}
@@ -25,7 +26,7 @@ type instance struct {
func (t *instance) expand() Type {
v := t.value
if v == nil {
- v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist)
+ v = t.check.Instantiate(t.pos, t.base, t.targs, t.poslist, t.verify)
if v == nil {
v = Typ[Invalid]
}
diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go
index 85c897a909..b289607de6 100644
--- a/src/cmd/compile/internal/types2/instantiate.go
+++ b/src/cmd/compile/internal/types2/instantiate.go
@@ -9,71 +9,19 @@ import (
"fmt"
)
-// Instantiate instantiates the type typ with the given type arguments.
-// typ must be a *Named or a *Signature type, it must be generic, and
-// its number of type parameters must match the number of provided type
-// arguments. The result is a new, instantiated (not generic) type of
-// the same kind (either a *Named or a *Signature). The type arguments
-// are not checked against the constraints of the type parameters.
-// Any methods attached to a *Named are simply copied; they are not
-// instantiated.
-func Instantiate(pos syntax.Pos, typ Type, targs []Type) (res Type) {
- // TODO(gri) This code is basically identical to the prolog
- // in Checker.instantiate. Factor.
- var tparams []*TypeName
- switch t := typ.(type) {
- case *Named:
- tparams = t.TParams()
- case *Signature:
- tparams = t.tparams
- defer func() {
- // If we had an unexpected failure somewhere don't panic below when
- // asserting res.(*Signature). Check for *Signature in case Typ[Invalid]
- // is returned.
- if _, ok := res.(*Signature); !ok {
- return
- }
- // If the signature doesn't use its type parameters, subst
- // will not make a copy. In that case, make a copy now (so
- // we can set tparams to nil w/o causing side-effects).
- if t == res {
- copy := *t
- res = &copy
- }
- // After instantiating a generic signature, it is not generic
- // anymore; we need to set tparams to nil.
- res.(*Signature).tparams = nil
- }()
-
- default:
- panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
- }
-
- // the number of supplied types must match the number of type parameters
- if len(targs) != len(tparams) {
- panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams)))
- }
-
- if len(tparams) == 0 {
- return typ // nothing to do (minor optimization)
- }
-
- smap := makeSubstMap(tparams, targs)
- return (*Checker)(nil).subst(pos, typ, smap)
-}
-
// InstantiateLazy is like Instantiate, but avoids actually
// instantiating the type until needed.
-func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type) (res Type) {
+func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, verify bool) (res Type) {
base := asNamed(typ)
if base == nil {
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
}
return &instance{
- check: check,
- pos: pos,
- base: base,
- targs: targs,
+ check: check,
+ pos: pos,
+ base: base,
+ targs: targs,
+ verify: verify,
}
}
diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go
index a51d0c43d5..f7f191f629 100644
--- a/src/cmd/compile/internal/types2/sizeof_test.go
+++ b/src/cmd/compile/internal/types2/sizeof_test.go
@@ -33,7 +33,7 @@ func TestSizeof(t *testing.T) {
{Chan{}, 12, 24},
{Named{}, 84, 160},
{TypeParam{}, 28, 48},
- {instance{}, 52, 96},
+ {instance{}, 56, 104},
{top{}, 0, 0},
// Objects
diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go
index 6e4e778b20..32cf527372 100644
--- a/src/cmd/compile/internal/types2/subst.go
+++ b/src/cmd/compile/internal/types2/subst.go
@@ -53,8 +53,24 @@ func (m *substMap) lookup(tpar *TypeParam) Type {
return tpar
}
-func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslist []syntax.Pos) (res Type) {
- if check.conf.Trace {
+// Instantiate instantiates the type typ with the given type arguments
+// targs. To check type constraint satisfaction, verify must be set.
+// pos and posList correspond to the instantiation and type argument
+// positions respectively; posList may be nil or shorter than the number
+// of type arguments provided.
+// typ must be a *Named or a *Signature type, and its number of type
+// parameters must match the number of provided type arguments.
+// The receiver (check) may be nil if and only if verify is not set.
+// The result is a new, instantiated (not generic) type of the same kind
+// (either a *Named or a *Signature).
+// Any methods attached to a *Named are simply copied; they are not
+// instantiated.
+func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos, verify bool) (res Type) {
+ if verify && check == nil {
+ panic("cannot have nil receiver if verify is set")
+ }
+
+ if check != nil && check.conf.Trace {
check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
check.indent++
defer func() {
@@ -70,7 +86,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
}()
}
- assert(len(poslist) <= len(targs))
+ assert(len(posList) <= len(targs))
// TODO(gri) What is better here: work with TypeParams, or work with TypeNames?
var tparams []*TypeName
@@ -97,18 +113,19 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
// anymore; we need to set tparams to nil.
res.(*Signature).tparams = nil
}()
-
default:
- check.dump("%v: cannot instantiate %v", pos, typ)
- unreachable() // only defined types and (defined) functions can be generic
-
+ // only types and functions can be generic
+ panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
}
// the number of supplied types must match the number of type parameters
if len(targs) != len(tparams) {
// TODO(gri) provide better error message
- check.errorf(pos, "got %d arguments but %d type parameters", len(targs), len(tparams))
- return Typ[Invalid]
+ if check != nil {
+ check.errorf(pos, "got %d arguments but %d type parameters", len(targs), len(tparams))
+ return Typ[Invalid]
+ }
+ panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams)))
}
if len(tparams) == 0 {
@@ -118,15 +135,17 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
smap := makeSubstMap(tparams, targs)
// check bounds
- for i, tname := range tparams {
- // best position for error reporting
- pos := pos
- if i < len(poslist) {
- pos = poslist[i]
- }
- // stop checking bounds after the first failure
- if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) {
- break
+ if verify {
+ for i, tname := range tparams {
+ // best position for error reporting
+ pos := pos
+ if i < len(posList) {
+ pos = posList[i]
+ }
+ // stop checking bounds after the first failure
+ if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) {
+ break
+ }
}
}
diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go
index e861f7e784..d69dd3c496 100644
--- a/src/cmd/compile/internal/types2/typexpr.go
+++ b/src/cmd/compile/internal/types2/typexpr.go
@@ -423,12 +423,14 @@ func (check *Checker) instantiatedType(x syntax.Expr, targs []syntax.Expr, def *
// create a new type instance rather than instantiate the type
// TODO(gri) should do argument number check here rather than
// when instantiating the type?
+ // TODO(gri) use InstantiateLazy here (cleanup)
typ := new(instance)
def.setUnderlying(typ)
typ.check = check
typ.pos = x.Pos()
typ.base = base
+ typ.verify = true
// evaluate arguments (always)
typ.targs = check.typeList(targs)