Пример #1
0
func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
	assert(x != nil)
	if a[0] == nil || a[1] == nil {
		return
	}
	assert(isTyped(a[0]) && isTyped(a[1]) && isBoolean(a[1]))
	if m := check.Types; m != nil {
		for {
			tv := m[x]
			assert(tv.Type != nil) // should have been recorded already
			pos := x.Pos()
			tv.Type = NewTuple(
				NewVar(pos, check.pkg, "", a[0]),
				NewVar(pos, check.pkg, "", a[1]),
			)
			m[x] = tv
			// if x is a parenthesized expression (p.X), update p.X
			p, _ := x.(*ast.ParenExpr)
			if p == nil {
				break
			}
			x = p.X
		}
	}
}
Пример #2
0
// TODO(austin) This is a hack to eliminate a circular dependency
// between type.go and expr.go
func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
	lenExpr := a.compileExpr(b, true, expr)
	if lenExpr == nil {
		return 0, false
	}

	// XXX(Spec) Are ideal floats with no fractional part okay?
	if lenExpr.t.isIdeal() {
		lenExpr = lenExpr.convertTo(IntType)
		if lenExpr == nil {
			return 0, false
		}
	}

	if !lenExpr.t.isInteger() {
		a.diagAt(expr.Pos(), "array size must be an integer")
		return 0, false
	}

	switch lenExpr.t.lit().(type) {
	case *intType:
		return lenExpr.asInt()(nil), true
	case *uintType:
		return int64(lenExpr.asUint()(nil)), true
	}
	log.Panicf("unexpected integer type %T", lenExpr.t)
	return 0, false
}
Пример #3
0
func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
	assert(obj.typ == nil)

	if obj.visited {
		obj.typ = Typ[Invalid]
		return
	}
	obj.visited = true

	// use the correct value of iota
	assert(check.iota == nil)
	check.iota = obj.val
	defer func() { check.iota = nil }()

	// provide valid constant value under all circumstances
	obj.val = exact.MakeUnknown()

	// determine type, if any
	if typ != nil {
		t := check.typ(typ)
		if !isConstType(t) {
			check.errorf(typ.Pos(), "invalid constant type %s", t)
			obj.typ = Typ[Invalid]
			return
		}
		obj.typ = t
	}

	// check initialization
	var x operand
	if init != nil {
		check.expr(&x, init)
	}
	check.initConst(obj, &x)
}
Пример #4
0
func checkCopyLocksRangeVar(f *File, rtok token.Token, e ast.Expr) {
	if e == nil {
		return
	}
	id, isId := e.(*ast.Ident)
	if isId && id.Name == "_" {
		return
	}

	var typ types.Type
	if rtok == token.DEFINE {
		if !isId {
			return
		}
		obj := f.pkg.defs[id]
		if obj == nil {
			return
		}
		typ = obj.Type()
	} else {
		typ = f.pkg.types[e].Type
	}

	if typ == nil {
		return
	}
	if path := lockPath(f.pkg.typesPkg, typ); path != nil {
		f.Badf(e.Pos(), "range var %s copies lock: %v", f.gofmt(e), path)
	}
}
Пример #5
0
func (c *conditionEvaluator) eval(e ast.Expr) bool {
	if c.stop {
		return false
	}
	switch e := e.(type) {
	case *ast.ParenExpr:
		return c.eval(e.X)
	case *ast.BinaryExpr:
		if e.Op == token.LAND {
			return c.eval(e.X) && c.eval(e.Y)
		} else if e.Op == token.LOR {
			return c.eval(e.X) || c.eval(e.Y)
		}
		assert(e.Op == token.EQL)
		value := c.getVarValue(e.X.(*ast.Ident).Name)
		if !value.isBound() {
			c.stop = true
			return false
		}
		eqValue := c.cond.equalityValues[e.Pos()]
		assert(eqValue.isBound())
		return value.compare(c.cond.equalityValues[e.Pos()]) == 0
	default:
		panic(errors.New("processCondition must have ensured condition is evaluatable"))
	}
	return false
}
Пример #6
0
func (check *checker) constDecl(obj *Const, typ, init ast.Expr) {
	if obj.visited {
		check.errorf(obj.Pos(), "illegal cycle in initialization of constant %s", obj.name)
		obj.typ = Typ[Invalid]
		return
	}
	obj.visited = true

	// use the correct value of iota
	assert(check.iota == nil)
	check.iota = obj.val

	// determine type, if any
	if typ != nil {
		t := check.typ(typ, nil, false)
		if !isConstType(t) {
			check.errorf(typ.Pos(), "invalid constant type %s", t)
			obj.typ = Typ[Invalid]
			check.iota = nil
			return
		}
		obj.typ = t
	}

	// check initialization
	var x operand
	if init != nil {
		check.expr(&x, init)
	}
	check.initConst(obj, &x)

	check.iota = nil
}
Пример #7
0
func (f *File) validRetExpr(expr ast.Expr) *Error {
	_, ok := expr.(*ast.Ident)
	// can only return identifies, i.e. variables
	if !ok {
		return &Error{errors.New("Return expression only allows identifiers"), expr.Pos()}
	}
	return nil
}
Пример #8
0
func emitTraceExpr(f *Function, event TraceEvent, syntax ast.Expr) Value {
	t := &Trace{
		Event:      event,
		Start:      syntax.Pos(),
		End:        syntax.End(),
		Breakpoint: false,
		syntax:     syntax,
	}
	return emitTraceCommon(f, t)
}
Пример #9
0
func (check *checker) recordCommaOkTypes(x ast.Expr, t1, t2 Type) {
	assert(x != nil && isTyped(t1) && isTyped(t2) && isBoolean(t2))
	if m := check.Types; m != nil {
		assert(m[x] != nil) // should have been recorded already
		pos := x.Pos()
		m[x] = NewTuple(
			NewVar(pos, check.pkg, "", t1),
			NewVar(pos, check.pkg, "", t2),
		)
	}
}
Пример #10
0
func extractText(ctx *Context, t ast.Expr) (string, error) {
	pos := ctx.Fset.Position(t.Pos())
	end := ctx.Fset.Position(t.End())

	read, err := ioutil.ReadFile(pos.Filename)
	if err != nil {
		return "", err
	}

	return string(read[pos.Offset:end.Offset]), nil
}
Пример #11
0
func (f *File) matchArgType(t printfArgType, arg ast.Expr) bool {
	// TODO: for now, we can only test builtin types and untyped constants.
	typ := f.pkg.types[arg]
	if typ == nil {
		return true
	}
	basic, ok := typ.(*types.Basic)
	if !ok {
		return true
	}
	switch basic.Kind {
	case types.Bool:
		return t&argBool != 0
	case types.Int, types.Int8, types.Int16, types.Int32, types.Int64:
		fallthrough
	case types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.Uintptr:
		return t&argInt != 0
	case types.Float32, types.Float64, types.Complex64, types.Complex128:
		return t&argFloat != 0
	case types.String:
		return t&argString != 0
	case types.UnsafePointer:
		return t&(argPointer|argInt) != 0
	case types.UntypedBool:
		return t&argBool != 0
	case types.UntypedComplex:
		return t&argFloat != 0
	case types.UntypedFloat:
		// If it's integral, we can use an int format.
		switch f.pkg.values[arg].(type) {
		case int, int8, int16, int32, int64:
			return t&(argInt|argFloat) != 0
		case uint, uint8, uint16, uint32, uint64:
			return t&(argInt|argFloat) != 0
		}
		return t&argFloat != 0
	case types.UntypedInt:
		return t&argInt != 0
	case types.UntypedRune:
		return t&(argInt|argRune) != 0
	case types.UntypedString:
		return t&argString != 0
	case types.UntypedNil:
		return t&argPointer != 0 // TODO?
	case types.Invalid:
		if *verbose {
			f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", arg)
		}
		return true // Probably a type check problem.
	}
	return false
}
Пример #12
0
// argument typechecks passing an argument arg (if arg != nil) or
// x (if arg == nil) to the i'th parameter of the given signature.
// If passSlice is set, the argument is followed by ... in the call.
//
func (check *checker) argument(sig *Signature, i int, arg ast.Expr, x *operand, passSlice bool) {
	// determine parameter
	var par *Var
	n := sig.params.Len()
	if i < n {
		par = sig.params.vars[i]
	} else if sig.isVariadic {
		par = sig.params.vars[n-1]
	} else {
		var pos token.Pos
		switch {
		case arg != nil:
			pos = arg.Pos()
		case x != nil:
			pos = x.pos()
		default:
			// TODO(gri) what position to use?
		}
		check.errorf(pos, "too many arguments")
		return
	}

	// determine argument
	var z operand
	z.mode = variable
	z.expr = nil // TODO(gri) can we do better here? (for good error messages)
	z.typ = par.typ

	if arg != nil {
		check.expr(x, arg, z.typ, -1)
	}
	if x.mode == invalid {
		return // ignore this argument
	}

	// check last argument of the form x...
	if passSlice {
		if i+1 != n {
			check.errorf(x.pos(), "can only use ... with matching parameter")
			return // ignore this argument
		}
		// spec: "If the final argument is assignable to a slice type []T,
		// it may be passed unchanged as the value for a ...T parameter if
		// the argument is followed by ..."
		z.typ = &Slice{elt: z.typ} // change final parameter type to []T
	}

	if !check.assignment(x, z.typ) && x.mode != invalid {
		check.errorf(x.pos(), "cannot pass argument %s to %s", x, &z)
	}
}
Пример #13
0
// checkAtomicAddAssignment walks the atomic.Add* method calls checking for assigning the return value
// to the same variable being used in the operation
func (f *File) checkAtomicAddAssignment(left ast.Expr, call *ast.CallExpr) {
	arg := call.Args[0]
	broken := false

	if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND {
		broken = f.gofmt(left) == f.gofmt(uarg.X)
	} else if star, ok := left.(*ast.StarExpr); ok {
		broken = f.gofmt(star.X) == f.gofmt(arg)
	}

	if broken {
		f.Warn(left.Pos(), "direct assignment to atomic value")
	}
}
Пример #14
0
func (tr *Transformer) matchWildcard(xobj *types.Var, y ast.Expr) bool {
	name := xobj.Name()

	if tr.verbose {
		fmt.Fprintf(os.Stderr, "%s: wildcard %s -> %s?: ",
			tr.fset.Position(y.Pos()), name, astString(tr.fset, y))
	}

	// Check that y is assignable to the declared type of the param.
	yt := tr.info.TypeOf(y)
	if yt == nil {
		// y has no type.
		// Perhaps it is an *ast.Ellipsis in [...]T{}, or
		// an *ast.KeyValueExpr in T{k: v}.
		// Clearly these pseudo-expressions cannot match a
		// wildcard, but it would nice if we had a way to ignore
		// the difference between T{v} and T{k:v} for structs.
		return false
	}
	if !types.AssignableTo(yt, xobj.Type()) {
		if tr.verbose {
			fmt.Fprintf(os.Stderr, "%s not assignable to %s\n", yt, xobj.Type())
		}
		return false
	}

	// A wildcard matches any expression.
	// If it appears multiple times in the pattern, it must match
	// the same expression each time.
	if old, ok := tr.env[name]; ok {
		// found existing binding
		tr.allowWildcards = false
		r := tr.matchExpr(old, y)
		if tr.verbose {
			fmt.Fprintf(os.Stderr, "%t secondary match, primary was %s\n",
				r, astString(tr.fset, old))
		}
		tr.allowWildcards = true
		return r
	}

	if tr.verbose {
		fmt.Fprintf(os.Stderr, "primary match\n")
	}

	tr.env[name] = y // record binding
	return true
}
Пример #15
0
// isUntypedConst reports whether expr is an untyped constant,
// and indicates what its default type is.
// scope may be nil.
func (f *file) isUntypedConst(expr ast.Expr) (defType string, ok bool) {
	// Re-evaluate expr outside of its context to see if it's untyped.
	// (An expr evaluated within, for example, an assignment context will get the type of the LHS.)
	exprStr := f.render(expr)
	tv, err := types.Eval(f.fset, f.pkg.typesPkg, expr.Pos(), exprStr)
	if err != nil {
		return "", false
	}
	if b, ok := tv.Type.(*types.Basic); ok {
		if dt, ok := basicTypeKinds[b.Kind()]; ok {
			return dt, true
		}
	}

	return "", false
}
Пример #16
0
// typ type-checks the type expression e and returns its type, or Typ[Invalid].
// If def != nil, e is the type specification for the named type def, declared
// in a type declaration, and def.UnderlyingT will be set to the type of e before
// any components of e are type-checked.
// If cycleOk is set, e (or elements of e) may refer to a named type that is not
// yet completely set up.
//
func (check *checker) typ(e ast.Expr, def *Named, cycleOk bool) (T Type) {
	if trace {
		check.trace(e.Pos(), "%s", e)
		check.indent++
		defer func() {
			check.indent--
			check.trace(e.Pos(), "=> %s", T)
		}()
	}

	T = check.typInternal(e, def, cycleOk)
	assert(isTyped(T))
	check.recordTypeAndValue(e, T, nil)

	return
}
Пример #17
0
// typExpr type-checks the type expression e and returns its type, or Typ[Invalid].
// If def != nil, e is the type specification for the named type def, declared
// in a type declaration, and def.underlying will be set to the type of e before
// any components of e are type-checked. Path contains the path of named types
// referring to this type.
//
func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) {
	if trace {
		check.trace(e.Pos(), "%s", e)
		check.indent++
		defer func() {
			check.indent--
			check.trace(e.Pos(), "=> %s", T)
		}()
	}

	T = check.typExprInternal(e, def, path)
	assert(isTyped(T))
	check.recordTypeAndValue(e, typexpr, T, nil)

	return
}
Пример #18
0
func hasType(pkg *grinder.Package, fn *ast.FuncDecl, x, v ast.Expr) bool {
	// Does x (by itself) default to v's type?
	// Find the scope in which x appears.
	xScope := pkg.Info.Scopes[fn.Type]
	ast.Inspect(fn.Body, func(z ast.Node) bool {
		if z == nil {
			return false
		}
		if x.Pos() < z.Pos() || z.End() <= x.Pos() {
			return false
		}
		scope := pkg.Info.Scopes[z]
		if scope != nil {
			xScope = scope
		}
		return true
	})
	xt, err := types.EvalNode(pkg.FileSet, x, pkg.Types, xScope)
	if err != nil {
		return false
	}
	vt := pkg.Info.Types[v]
	if types.Identical(xt.Type, vt.Type) {
		return true
	}

	// Might be untyped.
	vb, ok1 := vt.Type.(*types.Basic)
	xb, ok2 := xt.Type.(*types.Basic)
	if ok1 && ok2 {
		switch xb.Kind() {
		case types.UntypedInt:
			return vb.Kind() == types.Int
		case types.UntypedBool:
			return vb.Kind() == types.Bool
		case types.UntypedRune:
			return vb.Kind() == types.Rune
		case types.UntypedFloat:
			return vb.Kind() == types.Float64
		case types.UntypedComplex:
			return vb.Kind() == types.Complex128
		case types.UntypedString:
			return vb.Kind() == types.String
		}
	}
	return false
}
Пример #19
0
// typ type-checks the type expression e and returns its type, or Typ[Invalid].
// If def != nil, e is the type specification for the named type def, declared
// in a type declaration, and def.underlying will be set to the type of e before
// any components of e are type-checked.
// If cycleOk is set, e (or elements of e) may refer to a named type that is not
// yet completely set up.
//
func (check *checker) typ(e ast.Expr, def *Named, cycleOk bool) Type {
	if trace {
		check.trace(e.Pos(), "%s", e)
		check.indent++
	}

	t := check.typInternal(e, def, cycleOk)
	assert(e != nil && t != nil && isTyped(t))

	check.recordTypeAndValue(e, t, nil)

	if trace {
		check.indent--
		check.trace(e.Pos(), "=> %s", t)
	}

	return t
}
Пример #20
0
func (c *compiler) VisitExpr(expr ast.Expr) Value {
	c.setDebugLine(expr.Pos())

	// Before all else, check if we've got a constant expression.
	// go/types performs constant folding, and we store the value
	// alongside the expression's type.
	if constval := c.typeinfo.Values[expr]; constval != nil {
		return c.NewConstValue(constval, c.typeinfo.Types[expr])
	}
	// nil-literals are parsed to Ident-nodes for some reason,
	// treat them like constant values here.
	// TODO nil literals should be represented more appropriately.
	if identval, valid := expr.(*ast.Ident); valid && identval.Name == "nil" {
		return c.NewConstValue(exact.MakeUnknown(), c.typeinfo.Types[expr])
	}

	switch x := expr.(type) {
	case *ast.BinaryExpr:
		return c.VisitBinaryExpr(x)
	case *ast.FuncLit:
		return c.VisitFuncLit(x)
	case *ast.CompositeLit:
		return c.VisitCompositeLit(x)
	case *ast.UnaryExpr:
		return c.VisitUnaryExpr(x)
	case *ast.CallExpr:
		return c.VisitCallExpr(x)
	case *ast.IndexExpr:
		return c.VisitIndexExpr(x)
	case *ast.SelectorExpr:
		return c.VisitSelectorExpr(x)
	case *ast.StarExpr:
		return c.VisitStarExpr(x)
	case *ast.ParenExpr:
		return c.VisitExpr(x.X)
	case *ast.TypeAssertExpr:
		return c.VisitTypeAssertExpr(x)
	case *ast.SliceExpr:
		return c.VisitSliceExpr(x)
	case *ast.Ident:
		return c.Resolve(x)
	}
	panic(fmt.Sprintf("Unhandled Expr node: %s", reflect.TypeOf(expr)))
}
Пример #21
0
// rawExpr typechecks expression e and initializes x with the expression
// value or type. If an error occurred, x.mode is set to invalid.
// If hint != nil, it is the type of a composite literal element.
//
func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
	if trace {
		check.trace(e.Pos(), "%s", e)
		check.indent++
	}

	kind := check.exprInternal(x, e, hint)

	// convert x into a user-friendly set of values
	record := true
	var typ Type
	var val exact.Value
	switch x.mode {
	case invalid:
		typ = Typ[Invalid]
		record = false // nothing to do
	case novalue:
		typ = (*Tuple)(nil)
	case constant:
		typ = x.typ
		val = x.val
	default:
		typ = x.typ
	}
	assert(x.expr != nil && typ != nil)

	if isUntyped(typ) {
		// delay notification until it becomes typed
		// or until the end of type checking
		check.untyped[x.expr] = exprInfo{false, typ.(*Basic), val}
	} else if record {
		// TODO(gri) ensure that literals always report
		// their dynamic (never interface) type.
		// This is not the case yet.
		check.recordTypeAndValue(e, typ, val)
	}

	if trace {
		check.indent--
		check.trace(e.Pos(), "=> %s", x)
	}

	return kind
}
Пример #22
0
// compiles an expression
func (w *World) compileExpr(e ast.Expr) Expr {
	switch e := e.(type) {
	default:
		panic(err(e.Pos(), "not allowed:", typ(e)))
	case *ast.Ident:
		return w.resolve(e.Pos(), e.Name)
	case *ast.BasicLit:
		return w.compileBasicLit(e)
	case *ast.BinaryExpr:
		return w.compileBinaryExpr(e)
	case *ast.UnaryExpr:
		return w.compileUnaryExpr(e)
	case *ast.CallExpr:
		return w.compileCallExpr(e)
	case *ast.ParenExpr:
		return w.compileExpr(e.X)
	case *ast.IndexExpr:
		return w.compileIndexExpr(e)
	}
}
Пример #23
0
// checkExprOrType checks that x is an expression or a type
// (and not a raw type such as [...]T).
//
func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
	switch t := unparen(x).(type) {
	case *ast.ParenExpr:
		panic("unreachable")
	case *ast.UnaryExpr:
		if t.Op == token.RANGE {
			// the range operator is only allowed at the top of a for statement
			p.errorExpected(x.Pos(), "expression")
			x = &ast.BadExpr{x.Pos(), x.End()}
		}
	case *ast.ArrayType:
		if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
			p.error(len.Pos(), "expected array length, found '...'")
			x = &ast.BadExpr{x.Pos(), x.End()}
		}
	}

	// all other nodes are expressions or types
	return x
}
Пример #24
0
func isCreateFlag(flag ast.Expr) bool {
	foundCreate := false
	foundTrunc := false
	// OR'ing of flags: is O_CREATE on?  + or | would be fine; we just look for os.O_CREATE
	// and don't worry about the actual operator.
	p := flag.Pos()
	for {
		lhs := flag
		expr, isBinary := flag.(*ast.BinaryExpr)
		if isBinary {
			lhs = expr.Y
		}
		sel, ok := lhs.(*ast.SelectorExpr)
		if !ok || !isTopName(sel.X, "os") {
			return false
		}
		switch sel.Sel.Name {
		case "O_CREATE":
			foundCreate = true
		case "O_TRUNC":
			foundTrunc = true
		case "O_RDONLY", "O_WRONLY", "O_RDWR":
			// okay
		default:
			// Unexpected flag, like O_APPEND or O_EXCL.
			// Be conservative and do not rewrite.
			return false
		}
		if !isBinary {
			break
		}
		flag = expr.X
	}
	if !foundCreate {
		return false
	}
	if !foundTrunc {
		warn(p, "rewrote os.Open with O_CREATE but not O_TRUNC to os.Create")
	}
	return foundCreate
}
Пример #25
0
// argument typechecks passing an argument arg (if arg != nil) or
// x (if arg == nil) to the i'th parameter of the given signature.
// If passSlice is set, the argument is followed by ... in the call.
//
func (check *checker) argument(sig *Signature, i int, arg ast.Expr, x *operand, passSlice bool) {
	// determine parameter
	var par *ast.Object
	n := len(sig.Params)
	if i < n {
		par = sig.Params[i]
	} else if sig.IsVariadic {
		par = sig.Params[n-1]
	} else {
		check.errorf(arg.Pos(), "too many arguments")
		return
	}

	// determine argument
	var z operand
	z.mode = variable
	z.expr = nil // TODO(gri) can we do better here? (for good error messages)
	z.typ = par.Type.(Type)

	if arg != nil {
		check.expr(x, arg, z.typ, -1)
	}
	if x.mode == invalid {
		return // ignore this argument
	}

	// check last argument of the form x...
	if passSlice {
		if i+1 != n {
			check.errorf(x.pos(), "can only use ... with matching parameter")
			return // ignore this argument
		}
		// spec: "If the final argument is assignable to a slice type []T,
		// it may be passed unchanged as the value for a ...T parameter if
		// the argument is followed by ..."
		z.typ = &Slice{Elt: z.typ} // change final parameter type to []T
	}

	check.assignOperand(&z, x)
}
Пример #26
0
// rawExpr typechecks expression e and initializes x with the expression
// value or type. If an error occurred, x.mode is set to invalid.
// If hint != nil, it is the type of a composite literal element.
//
func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
	if trace {
		check.trace(e.Pos(), "%s", e)
		check.indent++
		defer func() {
			check.indent--
			check.trace(e.Pos(), "=> %s", x)
		}()
	}

	kind := check.exprInternal(x, e, hint)

	// convert x into a user-friendly set of values
	// TODO(gri) this code can be simplified
	var typ Type
	var val exact.Value
	switch x.mode {
	case invalid:
		typ = Typ[Invalid]
	case novalue:
		typ = (*Tuple)(nil)
	case constant:
		typ = x.typ
		val = x.val
	default:
		typ = x.typ
	}
	assert(x.expr != nil && typ != nil)

	if isUntyped(typ) {
		// delay type and value recording until we know the type
		// or until the end of type checking
		check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
	} else {
		check.recordTypeAndValue(e, x.mode, typ, val)
	}

	return kind
}
Пример #27
0
func (check *checker) argument(sig *Signature, i int, arg ast.Expr) {
	var par *ast.Object
	if n := len(sig.Params); i < n {
		par = sig.Params[i]
	} else if sig.IsVariadic {
		par = sig.Params[n-1]
	} else {
		check.errorf(arg.Pos(), "too many arguments")
		return
	}

	// TODO(gri) deal with ... last argument
	var z, x operand
	z.mode = variable
	z.expr = nil            // TODO(gri) can we do better here?
	z.typ = par.Type.(Type) // TODO(gri) should become something like checkObj(&z, ...) eventually
	check.expr(&x, arg, z.typ, -1)
	if x.mode == invalid {
		return // ignore this argument
	}
	check.assignOperand(&z, &x)
}
Пример #28
0
func (tr *Transformer) matchWildcard(xobj *types.Var, y ast.Expr) bool {
	name := xobj.Name()

	if tr.verbose {
		fmt.Fprintf(os.Stderr, "%s: wildcard %s -> %s?: ",
			tr.fset.Position(y.Pos()), name, astString(tr.fset, y))
	}

	// Check that y is assignable to the declared type of the param.
	if yt := tr.info.TypeOf(y); !types.AssignableTo(yt, xobj.Type()) {
		if tr.verbose {
			fmt.Fprintf(os.Stderr, "%s not assignable to %s\n", yt, xobj.Type())
		}
		return false
	}

	// A wildcard matches any expression.
	// If it appears multiple times in the pattern, it must match
	// the same expression each time.
	if old, ok := tr.env[name]; ok {
		// found existing binding
		tr.allowWildcards = false
		r := tr.matchExpr(old, y)
		if tr.verbose {
			fmt.Fprintf(os.Stderr, "%t secondary match, primary was %s\n",
				r, astString(tr.fset, old))
		}
		tr.allowWildcards = true
		return r
	}

	if tr.verbose {
		fmt.Fprintf(os.Stderr, "primary match\n")
	}

	tr.env[name] = y // record binding
	return true
}
Пример #29
0
// rawExpr typechecks expression e and initializes x with the expression
// value or type. If an error occurred, x.mode is set to invalid.
// If hint != nil, it is the type of a composite literal element.
//
func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
	if trace {
		check.trace(e.Pos(), "%s", e)
		check.indent++
		defer func() {
			check.indent--
			check.trace(e.Pos(), "=> %s", x)
		}()
	}

	kind := check.exprInternal(x, e, hint)

	// convert x into a user-friendly set of values
	var typ Type
	var val exact.Value
	switch x.mode {
	case invalid:
		typ = Typ[Invalid]
	case novalue:
		typ = (*Tuple)(nil)
	case constant:
		typ = x.typ
		val = x.val
	default:
		typ = x.typ
	}
	assert(x.expr != nil && typ != nil)

	if isUntyped(typ) {
		// delay notification until it becomes typed
		// or until the end of type checking
		check.untyped[x.expr] = exprInfo{false, typ.(*Basic), val}
	} else {
		check.recordTypeAndValue(e, typ, val)
	}

	return kind
}
Пример #30
0
func (c *compiler) VisitExpr(expr ast.Expr) Value {
	c.setDebugLine(expr.Pos())
	// Before all else, check if we've got a constant expression.
	// go/types performs constant folding, and we store the value
	// alongside the expression's type.
	if constval := c.typeinfo.Values[expr]; constval != nil {
		return c.NewConstValue(constval, c.typeinfo.Types[expr])
	}

	switch x := expr.(type) {
	case *ast.BinaryExpr:
		return c.VisitBinaryExpr(x)
	case *ast.FuncLit:
		return c.VisitFuncLit(x)
	case *ast.CompositeLit:
		return c.VisitCompositeLit(x)
	case *ast.UnaryExpr:
		return c.VisitUnaryExpr(x)
	case *ast.CallExpr:
		return c.VisitCallExpr(x)
	case *ast.IndexExpr:
		return c.VisitIndexExpr(x)
	case *ast.SelectorExpr:
		return c.VisitSelectorExpr(x)
	case *ast.StarExpr:
		return c.VisitStarExpr(x)
	case *ast.ParenExpr:
		return c.VisitExpr(x.X)
	case *ast.TypeAssertExpr:
		return c.VisitTypeAssertExpr(x)
	case *ast.SliceExpr:
		return c.VisitSliceExpr(x)
	case *ast.Ident:
		return c.Resolve(x)
	}
	panic(fmt.Sprintf("Unhandled Expr node: %s", reflect.TypeOf(expr)))
}