示例#1
0
文件: check.go 项目: mm120/gcc
// assocMethod associates a method declaration with the respective
// receiver base type. meth.Recv must exist.
//
func (check *checker) assocMethod(meth *ast.FuncDecl) {
	// The receiver type is one of the following (enforced by parser):
	// - *ast.Ident
	// - *ast.StarExpr{*ast.Ident}
	// - *ast.BadExpr (parser error)
	typ := meth.Recv.List[0].Type
	if ptr, ok := typ.(*ast.StarExpr); ok {
		typ = ptr.X
	}
	// determine receiver base type object (or nil if error)
	var obj *ast.Object
	if ident, ok := typ.(*ast.Ident); ok && ident.Obj != nil {
		obj = ident.Obj
		if obj.Kind != ast.Typ {
			check.errorf(ident.Pos(), "%s is not a type", ident.Name)
			obj = nil
		}
		// TODO(gri) determine if obj was defined in this package
		/*
			if check.notLocal(obj) {
				check.errorf(ident.Pos(), "cannot define methods on non-local type %s", ident.Name)
				obj = nil
			}
		*/
	} else {
		// If it's not an identifier or the identifier wasn't declared/resolved,
		// the parser/resolver already reported an error. Nothing to do here.
	}
	// determine base type scope (or nil if error)
	var scope *ast.Scope
	if obj != nil {
		if obj.Data != nil {
			scope = obj.Data.(*ast.Scope)
		} else {
			scope = ast.NewScope(nil)
			obj.Data = scope
		}
	} else {
		// use a dummy scope so that meth can be declared in
		// presence of an error and get an associated object
		// (always use a new scope so that we don't get double
		// declaration errors)
		scope = ast.NewScope(nil)
	}
	check.declare(scope, ast.Fun, meth.Name, meth)
}
示例#2
0
文件: check.go 项目: timnau/golang
// assocMethod associates a method declaration with the respective
// receiver base type. meth.Recv must exist.
//
func (check *checker) assocMethod(meth *ast.FuncDecl) {
	// The receiver type is one of the following (enforced by parser):
	// - *ast.Ident
	// - *ast.StarExpr{*ast.Ident}
	// - *ast.BadExpr (parser error)
	typ := meth.Recv.List[0].Type
	if ptr, ok := typ.(*ast.StarExpr); ok {
		typ = ptr.X
	}
	// determine receiver base type object
	var obj *ast.Object
	if ident, ok := typ.(*ast.Ident); ok && ident.Obj != nil {
		obj = ident.Obj
		if obj.Kind != ast.Typ {
			check.errorf(ident.Pos(), "%s is not a type", ident.Name)
			return // ignore this method
		}
		// TODO(gri) determine if obj was defined in this package
		/*
			if check.notLocal(obj) {
				check.errorf(ident.Pos(), "cannot define methods on non-local type %s", ident.Name)
				return // ignore this method
			}
		*/
	} else {
		// If it's not an identifier or the identifier wasn't declared/resolved,
		// the parser/resolver already reported an error. Nothing to do here.
		return // ignore this method
	}
	// declare method in receiver base type scope
	var scope *ast.Scope
	if obj.Data != nil {
		scope = obj.Data.(*ast.Scope)
	} else {
		scope = ast.NewScope(nil)
		obj.Data = scope
	}
	check.declare(scope, ast.Fun, meth.Name, meth)
}
示例#3
0
文件: check.go 项目: timnau/golang
// object typechecks an object by assigning it a type; obj.Type must be nil.
// Callers must check obj.Type before calling object; this eliminates a call
// for each identifier that has been typechecked already, a common scenario.
//
func (check *checker) object(obj *ast.Object, cycleOk bool) {
	assert(obj.Type == nil)

	switch obj.Kind {
	case ast.Bad, ast.Pkg:
		// nothing to do

	case ast.Con, ast.Var:
		// The obj.Data field for constants and variables is initialized
		// to the respective (hypothetical, for variables) iota value by
		// the parser. The object's fields can be in one of the following
		// states:
		// Type != nil  =>  the constant value is Data
		// Type == nil  =>  the object is not typechecked yet, and Data can be:
		// Data is int  =>  Data is the value of iota for this declaration
		// Data == nil  =>  the object's expression is being evaluated
		if obj.Data == nil {
			check.errorf(obj.Pos(), "illegal cycle in initialization of %s", obj.Name)
			obj.Type = Typ[Invalid]
			return
		}
		spec := obj.Decl.(*ast.ValueSpec)
		iota := obj.Data.(int)
		obj.Data = nil
		// determine initialization expressions
		values := spec.Values
		if len(values) == 0 && obj.Kind == ast.Con {
			values = check.initexprs[spec]
		}
		check.valueSpec(spec.Pos(), obj, spec.Names, spec.Type, values, iota)

	case ast.Typ:
		typ := &NamedType{Obj: obj}
		obj.Type = typ // "mark" object so recursion terminates
		typ.Underlying = underlying(check.typ(obj.Decl.(*ast.TypeSpec).Type, cycleOk))
		// typecheck associated method signatures
		if obj.Data != nil {
			scope := obj.Data.(*ast.Scope)
			switch t := typ.Underlying.(type) {
			case *Struct:
				// struct fields must not conflict with methods
				for _, f := range t.Fields {
					if m := scope.Lookup(f.Name); m != nil {
						check.errorf(m.Pos(), "type %s has both field and method named %s", obj.Name, f.Name)
						// ok to continue
					}
				}
			case *Interface:
				// methods cannot be associated with an interface type
				for _, m := range scope.Objects {
					recv := m.Decl.(*ast.FuncDecl).Recv.List[0].Type
					check.errorf(recv.Pos(), "invalid receiver type %s (%s is an interface type)", obj.Name, obj.Name)
					// ok to continue
				}
			}
			// typecheck method signatures
			for _, obj := range scope.Objects {
				mdecl := obj.Decl.(*ast.FuncDecl)
				sig := check.typ(mdecl.Type, cycleOk).(*Signature)
				params, _ := check.collectParams(mdecl.Recv, false)
				sig.Recv = params[0] // the parser/assocMethod ensure there is exactly one parameter
				obj.Type = sig
				check.later(obj, sig, mdecl.Body)
			}
		}

	case ast.Fun:
		fdecl := obj.Decl.(*ast.FuncDecl)
		// methods are typechecked when their receivers are typechecked
		if fdecl.Recv == nil {
			sig := check.typ(fdecl.Type, cycleOk).(*Signature)
			if obj.Name == "init" && (len(sig.Params) != 0 || len(sig.Results) != 0) {
				check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
				// ok to continue
			}
			obj.Type = sig
			check.later(obj, sig, fdecl.Body)
		}

	default:
		panic("unreachable")
	}
}
示例#4
0
文件: decl.go 项目: c0der007/llgo
func (c *compiler) VisitValueSpec(valspec *ast.ValueSpec, isconst bool) {
	var value_type types.Type
	if valspec.Type != nil {
		value_type = c.GetType(valspec.Type)
	}

	var iota_obj *ast.Object = types.Universe.Lookup("iota")
	defer func(data interface{}) {
		iota_obj.Data = data
	}(iota_obj.Data)

	for i, name_ := range valspec.Names {
		// We may resolve constants in the process of resolving others.
		obj := name_.Obj
		if _, isvalue := (obj.Data).(Value); isvalue {
			continue
		}

		// Set iota if necessary.
		if isconst {
			if iota_, isint := (name_.Obj.Data).(int); isint {
				iota_value := c.NewConstValue(token.INT, strconv.Itoa(iota_))
				iota_obj.Data = iota_value

				// Con objects with an iota have an embedded ValueSpec
				// in the Decl field. We'll just pull it out and use it
				// for evaluating the expression below.
				valspec = (name_.Obj.Decl).(*ast.ValueSpec)
			}
		}

		// Expression may have side-effects, so compute it regardless of
		// whether it'll be assigned to a name.
		var expr ast.Expr
		if i < len(valspec.Values) && valspec.Values[i] != nil {
			expr = valspec.Values[i]
		}

		// For constants, we just pass the ConstValue around. Otherwise, we
		// will convert it to an LLVMValue.
		var value Value
		name := name_.String()
		if !isconst {
			ispackagelevel := len(c.functions) == 0
			if !ispackagelevel {
				// Visit the expression.
				var init_ Value
				if expr != nil {
					init_ = c.VisitExpr(expr)
					if value_type == nil {
						value_type = init_.Type()
					}
				}

				// The variable should be allocated on the stack if it's
				// declared inside a function.
				var llvm_init llvm.Value
				stack_value := c.builder.CreateAlloca(
					c.types.ToLLVM(value_type), name)
				if init_ == nil {
					// If no initialiser was specified, set it to the
					// zero value.
					llvm_init = llvm.ConstNull(c.types.ToLLVM(value_type))
				} else {
					llvm_init = init_.Convert(value_type).LLVMValue()
				}
				c.builder.CreateStore(llvm_init, stack_value)
				llvm_value := c.NewLLVMValue(stack_value, &types.Pointer{Base: value_type})
				value = llvm_value.makePointee()
			} else { // ispackagelevel
				// Set the initialiser. If it's a non-const value, then
				// we'll have to do the assignment in a global constructor
				// function.
				export := name_.IsExported()
				value = c.createGlobal(expr, value_type, name, export)
			}
		} else { // isconst
			value = c.VisitExpr(expr).(ConstValue)
			if value_type != nil {
				value = value.Convert(value_type)
			}
		}

		if name != "_" {
			obj.Data = value
		}
	}
}
示例#5
0
文件: check.go 项目: mm120/gcc
// object typechecks an object by assigning it a type; obj.Type must be nil.
// Callers must check obj.Type before calling object; this eliminates a call
// for each identifier that has been typechecked already, a common scenario.
//
func (check *checker) object(obj *ast.Object, cycleOk bool) {
	assert(obj.Type == nil)

	switch obj.Kind {
	case ast.Bad, ast.Pkg:
		// nothing to do

	case ast.Con, ast.Var:
		// The obj.Data field for constants and variables is initialized
		// to the respective (hypothetical, for variables) iota value by
		// the parser. The object's fields can be in one of the following
		// states:
		// Type != nil  =>  the constant value is Data
		// Type == nil  =>  the object is not typechecked yet, and Data can be:
		// Data is int  =>  Data is the value of iota for this declaration
		// Data == nil  =>  the object's expression is being evaluated
		if obj.Data == nil {
			check.errorf(obj.Pos(), "illegal cycle in initialization of %s", obj.Name)
			obj.Type = Typ[Invalid]
			return
		}
		spec := obj.Decl.(*ast.ValueSpec)
		iota := obj.Data.(int)
		obj.Data = nil
		// determine initialization expressions
		values := spec.Values
		if len(values) == 0 && obj.Kind == ast.Con {
			values = check.initexprs[spec]
		}
		check.valueSpec(spec.Pos(), obj, spec.Names, spec.Type, values, iota)

	case ast.Typ:
		typ := &NamedType{Obj: obj}
		obj.Type = typ // "mark" object so recursion terminates
		typ.Underlying = underlying(check.typ(obj.Decl.(*ast.TypeSpec).Type, cycleOk))
		// typecheck associated method signatures
		if obj.Data != nil {
			scope := obj.Data.(*ast.Scope)
			switch t := typ.Underlying.(type) {
			case *Struct:
				// struct fields must not conflict with methods
				for _, f := range t.Fields {
					if m := scope.Lookup(f.Name); m != nil {
						check.errorf(m.Pos(), "type %s has both field and method named %s", obj.Name, f.Name)
					}
				}
				// ok to continue
			case *Interface:
				// methods cannot be associated with an interface type
				for _, m := range scope.Objects {
					recv := m.Decl.(*ast.FuncDecl).Recv.List[0].Type
					check.errorf(recv.Pos(), "invalid receiver type %s (%s is an interface type)", obj.Name, obj.Name)
				}
				// ok to continue
			}
			// typecheck method signatures
			for _, m := range scope.Objects {
				mdecl := m.Decl.(*ast.FuncDecl)
				// TODO(gri) At the moment, the receiver is type-checked when checking
				// the method body. Also, we don't properly track if the receiver is
				// a pointer (i.e., currently, method sets are too large). FIX THIS.
				mtyp := check.typ(mdecl.Type, cycleOk).(*Signature)
				m.Type = mtyp
			}
		}

	case ast.Fun:
		fdecl := obj.Decl.(*ast.FuncDecl)
		if fdecl.Recv != nil {
			// This will ensure that the method base type is
			// type-checked
			check.collectFields(token.FUNC, fdecl.Recv, true)
		}
		ftyp := check.typ(fdecl.Type, cycleOk).(*Signature)
		obj.Type = ftyp
		check.function(ftyp, fdecl.Body)

	default:
		panic("unreachable")
	}
}
示例#6
0
文件: compiler.go 项目: c0der007/llgo
func (c *compiler) Resolve(obj *ast.Object) Value {
	if obj.Kind == ast.Pkg {
		return nil
	} else if obj.Kind == ast.Typ {
		return TypeValue{obj.Type.(types.Type)}
	}

	value, isvalue := (obj.Data).(Value)
	if isvalue {
		return value
	}

	switch obj.Kind {
	case ast.Con:
		if obj.Decl != nil {
			valspec := obj.Decl.(*ast.ValueSpec)
			c.VisitValueSpec(valspec, true)
			value = (obj.Data).(Value)
		} else if obj == types.Nil {
			return NilValue{c}
		} else {
			var typ types.Type
			switch x := obj.Type.(type) {
			case *types.Basic:
				typ = x
			case *types.Name:
				typ = x.Underlying.(*types.Basic)
			default:
				panic(fmt.Sprintf("unreachable (%T)", x))
			}
			value = ConstValue{(obj.Data.(types.Const)), c, typ}
			obj.Data = value
		}

	case ast.Fun:
		var funcdecl *ast.FuncDecl
		if obj.Decl != nil {
			funcdecl = obj.Decl.(*ast.FuncDecl)
		} else {
			funcdecl = &ast.FuncDecl{
				Name: &ast.Ident{Name: obj.Name, Obj: obj},
			}
		}
		value = c.VisitFuncProtoDecl(funcdecl)
		obj.Data = value

	case ast.Var:
		switch x := (obj.Decl).(type) {
		case *ast.ValueSpec:
			c.VisitValueSpec(x, false)
		case *ast.Field:
			// No-op. Fields will be yielded for function
			// arg/recv/ret. We update the .Data field of the
			// object when we enter the function definition.
			if obj.Data == nil {
				panic("expected obj.Data value")
			}
		}

		// If it's an external variable, we'll need to create a global
		// value reference here.
		if obj.Data == nil {
			module := c.module.Module
			t := obj.Type.(types.Type)
			name := c.pkgmap[obj] + "." + obj.Name
			g := llvm.AddGlobal(module, c.types.ToLLVM(t), name)
			g.SetLinkage(llvm.AvailableExternallyLinkage)
			obj.Data = c.NewLLVMValue(g, t)
		}

		value = (obj.Data).(Value)
	}

	return value
}
示例#7
0
文件: compiler.go 项目: dtcaciuc/llgo
func (c *compiler) Resolve(obj *ast.Object) Value {
	if obj.Kind == ast.Pkg {
		return nil
	} else if obj.Kind == ast.Typ {
		return TypeValue{obj.Type.(types.Type)}
	}

	value, isvalue := (obj.Data).(Value)
	if isvalue {
		return value
	}

	switch obj.Kind {
	case ast.Con:
		if obj.Decl != nil {
			valspec := obj.Decl.(*ast.ValueSpec)
			c.VisitValueSpec(valspec, true)
			value = (obj.Data).(Value)
		} else if obj == types.Nil {
			return NilValue{c}
		} else {
			typ := obj.Type.(types.Type)
			value = ConstValue{(obj.Data.(types.Const)), c, typ}
			obj.Data = value
		}

	case ast.Fun:
		var funcdecl *ast.FuncDecl
		if obj.Decl != nil {
			funcdecl = obj.Decl.(*ast.FuncDecl)
		} else {
			funcdecl = &ast.FuncDecl{
				Name: &ast.Ident{Name: obj.Name, Obj: obj},
			}
		}
		value = c.VisitFuncProtoDecl(funcdecl)
		obj.Data = value

	case ast.Var:
		switch x := (obj.Decl).(type) {
		case *ast.ValueSpec:
			c.VisitValueSpec(x, false)
		case *ast.Field:
			// No-op. Fields will be yielded for function
			// arg/recv/ret. We update the .Data field of the
			// object when we enter the function definition.
			if obj.Data == nil {
				panic("expected obj.Data value")
			}
		}

		// If it's an external variable, we'll need to create a global
		// value reference here. It may be possible for multiple objects
		// to refer to the same variable.
		if obj.Data == nil {
			module := c.module.Module
			t := obj.Type.(types.Type)
			name := c.pkgmap[obj] + "." + obj.Name
			g := module.NamedGlobal(name)
			if g.IsNil() {
				g = llvm.AddGlobal(module, c.types.ToLLVM(t), name)
			}
			obj.Data = c.NewLLVMValue(g, &types.Pointer{Base: t}).makePointee()
		}

		value = (obj.Data).(Value)
	}

	return value
}
示例#8
0
func check(fset *token.FileSet, pkg *ast.Package, types map[ast.Expr]Type) error {
	var check checker
	check.fset = fset
	check.pkg = pkg
	check.types = types

	// Compute sorted list of file names so that
	// package file iterations are reproducible (needed for testing).
	filenames := make([]string, len(pkg.Files))
	{
		i := 0
		for filename := range pkg.Files {
			filenames[i] = filename
			i++
		}
		sort.Strings(filenames)
	}

	// Associate methods with types
	// TODO(gri) All other objects are resolved by the parser.
	//           Consider doing this in the parser (and provide the info
	//           in the AST. In the long-term (might require Go 1 API
	//           changes) it's probably easier to do all the resolution
	//           in one place in the type checker. See also comment
	//           with checker.declare.
	for _, filename := range filenames {
		file := pkg.Files[filename]
		for _, decl := range file.Decls {
			if meth, ok := decl.(*ast.FuncDecl); ok && meth.Recv != nil {
				// The receiver type is one of the following (enforced by parser):
				// - *ast.Ident
				// - *ast.StarExpr{*ast.Ident}
				// - *ast.BadExpr (parser error)
				typ := meth.Recv.List[0].Type
				if ptr, ok := typ.(*ast.StarExpr); ok {
					typ = ptr.X
				}
				// determine receiver base type object (or nil if error)
				var obj *ast.Object
				if ident, ok := typ.(*ast.Ident); ok && ident.Obj != nil {
					obj = ident.Obj
					if obj.Kind != ast.Typ {
						check.errorf(ident.Pos(), "%s is not a type", ident.Name)
						obj = nil
					}
					// TODO(gri) determine if obj was defined in this package
					/*
						if check.notLocal(obj) {
							check.errorf(ident.Pos(), "cannot define methods on non-local type %s", ident.Name)
							obj = nil
						}
					*/
				} else {
					// If it's not an identifier or the identifier wasn't declared/resolved,
					// the parser/resolver already reported an error. Nothing to do here.
				}
				// determine base type scope (or nil if error)
				var scope *ast.Scope
				if obj != nil {
					if obj.Data != nil {
						scope = obj.Data.(*ast.Scope)
					} else {
						scope = ast.NewScope(nil)
						obj.Data = scope
					}
				} else {
					// use a dummy scope so that meth can be declared in
					// presence of an error and get an associated object
					// (always use a new scope so that we don't get double
					// declaration errors)
					scope = ast.NewScope(nil)
				}
				check.declare(scope, ast.Fun, meth.Name, meth)
			}
		}
	}

	// Sort objects so that we get reproducible error
	// positions (this is only needed for testing).
	// TODO(gri): Consider ast.Scope implementation that
	// provides both a list and a map for fast lookup.
	// Would permit the use of scopes instead of ObjMaps
	// elsewhere.
	list := make(ObjList, len(pkg.Scope.Objects))
	{
		i := 0
		for _, obj := range pkg.Scope.Objects {
			list[i] = obj
			i++
		}
		list.Sort()
	}

	// Check global objects.
	for _, obj := range list {
		check.obj(obj, false)
	}

	// TODO(gri) Missing pieces:
	// - blank (_) objects and init functions are not in scopes but should be type-checked

	// do not remove multiple errors per line - depending on
	// order or error reporting this may hide the real error
	return check.errors.Err()
}
示例#9
0
// obj type checks an object.
func (check *checker) obj(obj *ast.Object, cycleOk bool) {
	if trace {
		fmt.Printf("obj(%s)\n", obj.Name)
	}

	if obj.Type != nil {
		// object has already been type checked
		return
	}

	switch obj.Kind {
	case ast.Bad, ast.Pkg:
		// nothing to do

	case ast.Con:
		if obj.Data == nil {
			check.errorf(obj.Pos(), "illegal cycle in initialization of %s", obj.Name)
			return
		}
		spec, ok := obj.Decl.(*ast.ValueSpec)
		assert(ok)
		// The Data stored with the constant is the value of iota for that
		// ast.ValueSpec. Use it for the evaluation of the initialization
		// expressions.
		iota := obj.Data.(int)
		obj.Data = nil
		check.decl(spec.Pos(), obj, spec.Names, spec.Type, check.specValues(spec), iota)

	case ast.Var:
		// TODO(gri) missing cycle detection
		spec, ok := obj.Decl.(*ast.ValueSpec)
		if !ok {
			// TODO(gri) the assertion fails for "x, y := 1, 2, 3" it seems
			fmt.Printf("var = %s\n", obj.Name)
		}
		assert(ok)
		check.decl(spec.Pos(), obj, spec.Names, spec.Type, spec.Values, 0)

	case ast.Typ:
		typ := &NamedType{Obj: obj}
		obj.Type = typ // "mark" object so recursion terminates
		typ.Underlying = underlying(check.typ(obj.Decl.(*ast.TypeSpec).Type, cycleOk))
		// collect associated methods, if any
		if obj.Data != nil {
			scope := obj.Data.(*ast.Scope)
			// struct fields must not conflict with methods
			if t, ok := typ.Underlying.(*Struct); ok {
				for _, f := range t.Fields {
					if m := scope.Lookup(f.Name); m != nil {
						check.errorf(m.Pos(), "type %s has both field and method named %s", obj.Name, f.Name)
					}
				}
			}
			// collect methods
			methods := make(ObjList, len(scope.Objects))
			i := 0
			for _, m := range scope.Objects {
				methods[i] = m
				i++
			}
			methods.Sort()
			typ.Methods = methods
			// methods cannot be associated with an interface type
			// (do this check after sorting for reproducible error positions - needed for testing)
			if _, ok := typ.Underlying.(*Interface); ok {
				for _, m := range methods {
					recv := m.Decl.(*ast.FuncDecl).Recv.List[0].Type
					check.errorf(recv.Pos(), "invalid receiver type %s (%s is an interface type)", obj.Name, obj.Name)
				}
			}
		}

	case ast.Fun:
		fdecl := obj.Decl.(*ast.FuncDecl)
		ftyp := check.typ(fdecl.Type, cycleOk).(*Signature)
		obj.Type = ftyp
		if fdecl.Recv != nil {
			// TODO(gri) handle method receiver
		}
		check.stmt(fdecl.Body)

	default:
		panic("unreachable")
	}
}
示例#10
0
文件: decl.go 项目: kisielk/llgo
func (c *compiler) VisitValueSpec(valspec *ast.ValueSpec, isconst bool) {
	// Check if the value-spec has already been visited (referenced
	// before definition visited.)
	if len(valspec.Names) > 0 {
		if _, ok := valspec.Names[0].Obj.Data.(Value); ok {
			return
		}
	}

	var iotaObj *ast.Object = types.Universe.Lookup("iota")
	defer func(data interface{}) {
		iotaObj.Data = data
	}(iotaObj.Data)

	pkgname, ispackagelevel := c.pkgmap[valspec.Names[0].Obj]
	if ispackagelevel && !isconst {
		c.createGlobals(valspec.Names, valspec.Values, pkgname)
		return
	}

	var values []Value
	if len(valspec.Values) == 1 && len(valspec.Names) > 1 {
		values = c.destructureExpr(valspec.Values[0])
	} else if len(valspec.Values) > 0 {
		values = make([]Value, len(valspec.Names))
		for i, name_ := range valspec.Names {
			if isconst {
				if iota_, isint := (name_.Obj.Data).(int); isint {
					iotaValue := c.NewConstValue(token.INT, strconv.Itoa(iota_))
					iotaObj.Data = iotaValue
				}
			}
			values[i] = c.VisitExpr(valspec.Values[i])
		}
	}

	for i, name := range valspec.Names {
		if name.Name == "_" {
			continue
		}

		// For constants, we just pass the ConstValue around. Otherwise, we
		// will convert it to an LLVMValue.
		var value Value
		if isconst {
			value = values[i].Convert(name.Obj.Type.(types.Type))
		} else {
			// The variable should be allocated on the stack if it's
			// declared inside a function.
			var llvmInit llvm.Value
			typ := name.Obj.Type.(types.Type)
			ptr := c.builder.CreateAlloca(c.types.ToLLVM(typ), name.Name)
			if values == nil || values[i] == nil {
				// If no initialiser was specified, set it to the
				// zero value.
				llvmInit = llvm.ConstNull(c.types.ToLLVM(typ))
			} else {
				llvmInit = values[i].Convert(typ).LLVMValue()
			}
			c.builder.CreateStore(llvmInit, ptr)
			value = c.NewLLVMValue(ptr, &types.Pointer{Base: typ}).makePointee()
		}
		name.Obj.Data = value
	}
}