go typeparam 源码

2022-07-15 浏览 (998)

golang typeparam 代码

文件路径:/src/go/types/typeparam.go

/ Copyright 2011 The Go Authors. All rights reserved.
/ Use of this source code is governed by a BSD-style
/ license that can be found in the LICENSE file.

package types

import (
	"sync/atomic"
)

/ Note: This is a uint32 rather than a uint64 because the
/ respective 64 bit atomic instructions are not available
/ on all platforms.
var lastID uint32

/ nextID returns a value increasing monotonically by 1 with
/ each call, starting with 1. It may be called concurrently.
func nextID() uint64 { return uint64(atomic.AddUint32(&lastID, 1)) }

/ A TypeParam represents a type parameter type.
type TypeParam struct {
	check *Checker  / for lazy type bound completion
	id    uint64    / unique id, for debugging only
	obj   *TypeName / corresponding type name
	index int       / type parameter index in source order, starting at 0
	bound Type      / any type, but underlying is eventually *Interface for correct programs (see TypeParam.iface)
}

/ NewTypeParam returns a new TypeParam. Type parameters may be set on a Named
/ or Signature type by calling SetTypeParams. Setting a type parameter on more
/ than one type will result in a panic.
/
/ The constraint argument can be nil, and set later via SetConstraint. If the
/ constraint is non-nil, it must be fully defined.
func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
	return (*Checker)(nil).newTypeParam(obj, constraint)
}

/ check may be nil
func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
	/ Always increment lastID, even if it is not used.
	id := nextID()
	if check != nil {
		check.nextID++
		id = check.nextID
	}
	typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: constraint}
	if obj.typ == nil {
		obj.typ = typ
	}
	/ iface may mutate typ.bound, so we must ensure that iface() is called
	/ at least once before the resulting TypeParam escapes.
	if check != nil {
		check.needsCleanup(typ)
	} else if constraint != nil {
		typ.iface()
	}
	return typ
}

/ Index returns the index of the type param within its param list, or -1 if
/ the type parameter has not yet been bound to a type.
func (t *TypeParam) Index() int {
	return t.index
}

/ Obj returns the type name for t.
func (t *TypeParam) Obj() *TypeName { return t.obj }

/ Constraint returns the type constraint specified for t.
func (t *TypeParam) Constraint() Type {
	return t.bound
}

/ SetConstraint sets the type constraint for t.
/
/ It must be called by users of NewTypeParam after the bound's underlying is
/ fully defined, and before using the type parameter in any way other than to
/ form other types. Once SetConstraint returns the receiver, t is safe for
/ concurrent use.
func (t *TypeParam) SetConstraint(bound Type) {
	if bound == nil {
		panic("nil constraint")
	}
	t.bound = bound
	/ iface may mutate t.bound (if bound is not an interface), so ensure that
	/ this is done before returning.
	t.iface()
}

func (t *TypeParam) Underlying() Type {
	return t.iface()
}

func (t *TypeParam) String() string { return TypeString(t, nil) }

/ ----------------------------------------------------------------------------
/ Implementation

func (t *TypeParam) cleanup() {
	t.iface()
	t.check = nil
}

/ iface returns the constraint interface of t.
func (t *TypeParam) iface() *Interface {
	bound := t.bound

	/ determine constraint interface
	var ityp *Interface
	switch u := under(bound).(type) {
	case *Basic:
		if u == Typ[Invalid] {
			/ error is reported elsewhere
			return &emptyInterface
		}
	case *Interface:
		if isTypeParam(bound) {
			/ error is reported in Checker.collectTypeParams
			return &emptyInterface
		}
		ityp = u
	}

	/ If we don't have an interface, wrap constraint into an implicit interface.
	if ityp == nil {
		ityp = NewInterfaceType(nil, []Type{bound})
		ityp.implicit = true
		t.bound = ityp / update t.bound for next time (optimization)
	}

	/ compute type set if necessary
	if ityp.tset == nil {
		/ pos is used for tracing output; start with the type parameter position.
		pos := t.obj.pos
		/ use the (original or possibly instantiated) type bound position if we have one
		if n, _ := bound.(*Named); n != nil {
			pos = n.obj.pos
		}
		computeInterfaceTypeSet(t.check, pos, ityp)
	}

	return ityp
}

/ is calls f with the specific type terms of t's constraint and reports whether
/ all calls to f returned true. If there are no specific terms, is
/ returns the result of f(nil).
func (t *TypeParam) is(f func(*term) bool) bool {
	return t.iface().typeSet().is(f)
}

/ underIs calls f with the underlying types of the specific type terms
/ of t's constraint and reports whether all calls to f returned true.
/ If there are no specific terms, underIs returns the result of f(nil).
func (t *TypeParam) underIs(f func(Type) bool) bool {
	return t.iface().typeSet().underIs(f)
}

相关信息

go 源码目录

相关文章

go api 源码

go api_test 源码

go array 源码

go assignments 源码

go basic 源码

go builtins 源码

go builtins_test 源码

go call 源码

go chan 源码

go check 源码

^