package interp

import (
	
	
	
	
	
	
	
	
)

// A cfgError represents an error during CFG build stage.
type cfgError struct {
	*node
	error
}

func ( *cfgError) () string { return .error.Error() }

var constOp = map[action]func(*node){
	aAdd:    addConst,
	aSub:    subConst,
	aMul:    mulConst,
	aQuo:    quoConst,
	aRem:    remConst,
	aAnd:    andConst,
	aOr:     orConst,
	aShl:    shlConst,
	aShr:    shrConst,
	aAndNot: andNotConst,
	aXor:    xorConst,
	aNot:    notConst,
	aBitNot: bitNotConst,
	aNeg:    negConst,
	aPos:    posConst,
}

var constBltn = map[string]func(*node){
	bltnComplex: complexConst,
	bltnImag:    imagConst,
	bltnReal:    realConst,
}

const nilIdent = "nil"

func init() {
	// Use init() to avoid initialization cycles for the following constant builtins.
	constBltn[bltnAlignof] = alignof
	constBltn[bltnOffsetof] = offsetof
	constBltn[bltnSizeof] = sizeof
}

// cfg generates a control flow graph (CFG) from AST (wiring successors in AST)
// and pre-compute frame sizes and indexes for all un-named (temporary) and named
// variables. A list of nodes of init functions is returned.
// Following this pass, the CFG is ready to run.
func ( *Interpreter) ( *node,  *scope, ,  string) ([]*node, error) {
	if  == nil {
		 = .initScopePkg(, )
	}
	 := typecheck{scope: }
	var  []*node
	var  error

	 := filepath.Base(.fset.Position(.pos).Filename)

	.Walk(func( *node) bool {
		// Pre-order processing
		if  != nil {
			return false
		}
		if .scope == nil {
			.scope = 
		}
		switch .kind {
		case binaryExpr, unaryExpr, parenExpr:
			if isBoolAction() {
				break
			}
			// Gather assigned type if set, to give context for type propagation at post-order.
			switch .anc.kind {
			case assignStmt, defineStmt:
				 := .anc
				 := childPos() - .nright
				if  < 0 {
					break
				}
				if len(.child) > .nright+.nleft {
					--
				}
				 := .child[]
				if .typ == nil {
					break
				}
				if .typ.incomplete {
					 = .cfgErrorf("invalid type declaration")
					return false
				}
				if !isInterface(.typ) {
					// Interface type are not propagated, and will be resolved at post-order.
					.typ = .typ
				}
			case binaryExpr, unaryExpr, parenExpr:
				.typ = .anc.typ
			}

		case defineStmt:
			// Determine type of variables initialized at declaration, so it can be propagated.
			if .nleft+.nright == len(.child) {
				// No type was specified on the left hand side, it will resolved at post-order.
				break
			}
			.typ,  = nodeType(, , .child[.nleft])
			if  != nil {
				break
			}
			for  := 0;  < .nleft; ++ {
				.child[].typ = .typ
			}

		case blockStmt:
			if .anc != nil && .anc.kind == rangeStmt {
				// For range block: ensure that array or map type is propagated to iterators
				// prior to process block. We cannot perform this at RangeStmt pre-order because
				// type of array like value is not yet known. This could be fixed in ast structure
				// by setting array/map node as 1st child of ForRangeStmt instead of 3rd child of
				// RangeStmt. The following workaround is less elegant but ok.
				 := .anc.child[1]
				if  != nil && .typ != nil && isSendChan(.typ) {
					 = .cfgErrorf("invalid operation: range %s receive from send-only channel", .ident)
					return false
				}

				if  := .rangeChanType(.anc);  != nil {
					// range over channel
					 := .anc.child[0]
					 := .add(.val)
					.sym[.ident] = &symbol{index: , kind: varSym, typ: .val}
					.typ = .val
					.findex = 
					.anc.gen = rangeChan
				} else {
					// range over array or map
					var ,  *itype
					var , ,  *node
					if len(.anc.child) == 4 {
						, ,  = .anc.child[0], .anc.child[1], .anc.child[2]
					} else {
						,  = .anc.child[0], .anc.child[1]
					}

					switch .typ.cat {
					case valueT, linkedT:
						 := .typ.rtype
						if .typ.cat == linkedT {
							 = .typ.val.TypeOf()
						}
						switch .Kind() {
						case reflect.Map:
							.anc.gen = rangeMap
							 := valueTOf(reflect.TypeOf((*reflect.MapIter)(nil)))
							.add()
							 = valueTOf(.Key())
							 = valueTOf(.Elem())
						case reflect.String:
							.add(.getType("int")) // Add a dummy type to store array shallow copy for range
							.add(.getType("int")) // Add a dummy type to store index for range
							 = .getType("int")
							 = .getType("rune")
						case reflect.Array, reflect.Slice:
							.add(.getType("int")) // Add a dummy type to store array shallow copy for range
							 = .getType("int")
							 = valueTOf(.Elem())
						}
					case mapT:
						.anc.gen = rangeMap
						 := valueTOf(reflect.TypeOf((*reflect.MapIter)(nil)))
						.add()
						 = .typ.key
						 = .typ.val
					case ptrT:
						 = .getType("int")
						 = .typ.val
						if .cat == valueT {
							 = valueTOf(.rtype.Elem())
						} else {
							 = .val
						}
					case stringT:
						.add(.getType("int")) // Add a dummy type to store array shallow copy for range
						.add(.getType("int")) // Add a dummy type to store index for range
						 = .getType("int")
						 = .getType("rune")
					case arrayT, sliceT, variadicT:
						.add(.getType("int")) // Add a dummy type to store array shallow copy for range
						 = .getType("int")
						 = .typ.val
					}

					 := .add()
					.sym[.ident] = &symbol{index: , kind: varSym, typ: }
					.typ = 
					.findex = 

					if  != nil {
						 := .add()
						.sym[.ident] = &symbol{index: , kind: varSym, typ: }
						.typ = 
						.findex = 
					}
				}
			}

			.findex = -1
			.val = nil
			 = .pushBloc()
			// Pre-define symbols for labels defined in this block, so we are sure that
			// they are already defined when met.
			// TODO(marc): labels must be stored outside of symbols to avoid collisions.
			for ,  := range .child {
				if .kind != labeledStmt {
					continue
				}
				 := .child[0].ident
				 := &symbol{kind: labelSym, node: , index: -1}
				.sym[] = 
				.sym = 
			}
			// If block is the body of a function, get declared variables in current scope.
			// This is done in order to add the func signature symbols into sc.sym,
			// as we will need them in post-processing.
			if .anc != nil && .anc.kind == funcDecl {
				for ,  := range .anc.sym {
					.sym[] = 
				}
			}

		case breakStmt, continueStmt, gotoStmt:
			if len(.child) == 0 {
				break
			}
			// Handle labeled statements.
			 := .child[0].ident
			if , ,  := .lookup();  {
				if .kind != labelSym {
					 = .child[0].cfgErrorf("label %s not defined", )
					break
				}
				.sym = 
			} else {
				.sym = &symbol{kind: labelSym, index: -1}
				.sym[] = .sym
			}
			if .kind == gotoStmt {
				.sym.from = append(.sym.from, ) // To allow forward goto statements.
			}

		case caseClause:
			 = .pushBloc()
			if  := .anc.anc; .kind == typeSwitch && .child[1].action == aAssign {
				// Type switch clause with a var defined in switch guard.
				var  *itype
				if len(.child) == 2 {
					// 1 type in clause: define the var with this type in the case clause scope.
					switch {
					case .child[0].ident == nilIdent:
						 = .getType("interface{}")
					case !.child[0].isType():
						 = .cfgErrorf("%s is not a type", .child[0].ident)
					default:
						,  = nodeType(, , .child[0])
					}
				} else {
					// Define the var with the type in the switch guard expression.
					 = .child[1].child[1].child[0].typ
				}
				if  != nil {
					return false
				}
				 := .lastChild().child[0]
				 := .add()
				.sym[.ident] = &symbol{index: , kind: varSym, typ: }
				.findex = 
				.typ = 
			}

		case commClauseDefault:
			 = .pushBloc()

		case commClause:
			 = .pushBloc()
			if len(.child) > 0 && .child[0].action == aAssign {
				 := .child[0].child[1].child[0]
				var  *itype
				if ,  = nodeType(, , );  != nil {
					return false
				}
				if !isChan() {
					 = .cfgErrorf("invalid operation: receive from non-chan type")
					return false
				}
				 := chanElement()
				 := .child[0].child[0]
				 := .add()
				.sym[.ident] = &symbol{index: , kind: varSym, typ: }
				.findex = 
				.typ = 
			}

		case compositeLitExpr:
			if len(.child) > 0 && .child[0].isType() {
				// Get type from 1st child.
				if .typ,  = nodeType(, , .child[0]);  != nil {
					return false
				}
				// Indicate that the first child is the type.
				.nleft = 1
			} else {
				// Get type from ancestor (implicit type).
				if .anc.kind == keyValueExpr &&  == .anc.child[0] {
					.typ = .anc.typ.key
				} else if  := .anc.typ;  != nil {
					if .cat == valueT && hasElem(.rtype) {
						.typ = valueTOf(.rtype.Elem())
					} else {
						.typ = .val
					}
				}
				if .typ == nil {
					// A nil type indicates either an error or a generic type.
					// A child indexExpr or indexListExpr is used for type parameters,
					// it indicates an instanciated generic.
					if .child[0].kind != indexExpr && .child[0].kind != indexListExpr {
						 = .cfgErrorf("undefined type")
						return false
					}
					,  := nodeType(, , .child[0].child[0])
					if  != nil {
						return false
					}
					if .cat != genericT {
						 = .cfgErrorf("undefined type")
						return false
					}
					// We have a composite literal of generic type, instantiate it.
					 := []*itype{}
					for ,  := range .child[0].child[1:] {
						,  := nodeType(, , )
						if  != nil {
							return false
						}
						 = append(, )
					}
					var  *node
					, _,  = genAST(, .node.anc, )
					if  != nil {
						return false
					}
					.child[0] = .lastChild()
					.typ,  = nodeType(, , .child[0])
					if  != nil {
						return false
					}
					// Generate methods if any.
					for ,  := range .method {
						, ,  := genAST(.scope, , )
						if  != nil {
							 = 
							return false
						}
						.typ,  = nodeType(, .scope, .child[2])
						if  != nil {
							return false
						}
						if _,  = .(, , .pkgID, .pkgName);  != nil {
							return false
						}
						if  = genRun();  != nil {
							return false
						}
						.typ.addMethod()
					}
					.nleft = 1 // Indictate the type of composite literal.
				}
			}

			 := .child
			if .nleft > 0 {
				.child[0].typ = .typ
				 = .child[1:]
			}
			// Propagate type to children, to handle implicit types
			for ,  := range  {
				if isBlank() {
					 = .cfgErrorf("cannot use _ as value")
					return false
				}
				switch .kind {
				case binaryExpr, unaryExpr, compositeLitExpr:
					// Do not attempt to propagate composite type to operator expressions,
					// it breaks constant folding.
				case keyValueExpr, typeAssertExpr, indexExpr:
					.typ = .typ
				default:
					if .ident == nilIdent {
						.typ = .getType(nilIdent)
						continue
					}
					if .typ,  = nodeType(, , );  != nil {
						return false
					}
				}
			}

		case forStmt0, forStmt1, forStmt2, forStmt3, forStmt4, forStmt5, forStmt6, forStmt7, forRangeStmt:
			 = .pushBloc()
			.loop, .loopRestart = , .lastChild()

		case funcLit:
			.typ = nil // to force nodeType to recompute the type
			if .typ,  = nodeType(, , );  != nil {
				return false
			}
			.findex = .add(.typ)
			fallthrough

		case funcDecl:
			// Do not allow function declarations without body.
			if len(.child) < 4 {
				 = .cfgErrorf("missing function body")
				return false
			}
			.val = 

			// Skip substree in case of a generic function.
			if len(.child[2].child[0].child) > 0 {
				return false
			}

			// Skip subtree if the function is a method with a generic receiver.
			if len(.child[0].child) > 0 {
				 := .child[0].child[0].lastChild()
				,  := nodeType(, , )
				if  != nil {
					return false
				}
				if .cat == genericT || (.val != nil && .val.cat == genericT) {
					return false
				}
				if .cat == ptrT {
					 := .child[0]
					,  := nodeType(, , )
					if  != nil {
						return false
					}
					if .kind == indexExpr && .cat == structT {
						return false
					}
				}
			}

			// Compute function type before entering local scope to avoid
			// possible collisions with function argument names.
			.child[2].typ,  = nodeType(, , .child[2])
			if  != nil {
				return false
			}
			.typ = .child[2].typ

			// Add a frame indirection level as we enter in a func.
			 = .pushFunc()
			.def = 

			// Allocate frame space for return values, define output symbols.
			if len(.child[2].child) == 3 {
				for ,  := range .child[2].child[2].child {
					var  *itype
					if ,  = nodeType(, , .lastChild());  != nil {
						return false
					}
					if len(.child) > 1 {
						for ,  := range .child[:len(.child)-1] {
							.sym[.ident] = &symbol{index: .add(), kind: varSym, typ: }
						}
					} else {
						.add()
					}
				}
			}

			// Define receiver symbol.
			if len(.child[0].child) > 0 {
				var  *itype
				 := .child[0].child[0]
				 := .lastChild()
				if ,  = nodeType(, , );  != nil {
					return false
				}
				if .cat == nilT {
					// This may happen when instantiating generic methods.
					, ,  := .lookup(.id())
					if ! {
						 = .cfgErrorf("type not found: %s", .id())
						break
					}
					 = .typ
					if .cat == nilT {
						 = .cfgErrorf("nil type: %s", .id())
						break
					}
				}
				.typ = 
				.child[2].typ.recv = 
				.typ.recv = 
				 := .add()
				if len(.child) > 1 {
					.sym[.child[0].ident] = &symbol{index: , kind: varSym, typ: }
				}
			}

			// Define input parameter symbols.
			for ,  := range .child[2].child[1].child {
				var  *itype
				if ,  = nodeType(, , .lastChild());  != nil {
					return false
				}
				for ,  := range .child[:len(.child)-1] {
					.sym[.ident] = &symbol{index: .add(), kind: varSym, typ: }
				}
			}

			if .child[1].ident == "init" && len(.child[0].child) == 0 {
				 = append(, )
			}

		case ifStmt0, ifStmt1, ifStmt2, ifStmt3:
			 = .pushBloc()

		case switchStmt, switchIfStmt, typeSwitch:
			// Make sure default clause is in last position.
			 := .lastChild().child
			if ,  := getDefault(), len()-1;  >= 0 &&  !=  {
				[], [] = [], []
			}
			 = .pushBloc()
			.loop = 

		case importSpec:
			// Already all done in GTA.
			return false

		case typeSpec:
			// Processing already done in GTA pass for global types, only parses inlined types.
			if .def == nil {
				return false
			}
			 := .child[0].ident
			var  *itype
			if ,  = nodeType(, , .child[1]);  != nil {
				return false
			}
			if .incomplete {
				// Type may still be incomplete in case of a local recursive struct declaration.
				if ,  = .finalize();  != nil {
					 = .cfgErrorf("invalid type declaration")
					return false
				}
			}

			switch .child[1].kind {
			case identExpr, selectorExpr:
				.typ = namedOf(, , )
			default:
				.typ = 
				.typ.name = 
			}
			.sym[] = &symbol{kind: typeSym, typ: .typ}
			return false

		case constDecl:
			// Early parse of constDecl subtrees, to compute all constant
			// values which may be used in further declarations.
			if !.global {
				for ,  := range .child {
					if _,  = .(, , , );  != nil {
						// No error processing here, to allow recovery in subtree nodes.
						 = nil
					}
				}
			}

		case arrayType, basicLit, chanType, chanTypeRecv, chanTypeSend, funcType, interfaceType, mapType, structType:
			.typ,  = nodeType(, , )
			return false
		}
		return true
	}, func( *node) {
		// Post-order processing
		if  != nil {
			return
		}

		defer func() {
			if  := recover();  != nil {
				// Display the exact location in input source which triggered the panic
				panic(.cfgErrorf("CFG post-order panic: %v", ))
			}
		}()

		switch .kind {
		case addressExpr:
			if isBlank(.child[0]) {
				 = .cfgErrorf("cannot use _ as value")
				break
			}
			wireChild()

			 = .addressExpr()
			if  != nil {
				break
			}

			.typ = ptrOf(.child[0].typ)
			.findex = .add(.typ)

		case assignStmt, defineStmt:
			if .anc.kind == typeSwitch && .anc.child[1] ==  {
				// type switch guard assignment: assign dest to concrete value of src
				.gen = nop
				break
			}

			var  *itype
			if .nleft+.nright < len(.child) {
				if ,  = nodeType(, , .child[.nleft]);  != nil {
					break
				}
			}

			var  int
			if .nright > 0 {
				 = len(.child) - .nright
			}

			wireChild()
			for  := 0;  < .nleft; ++ {
				,  := .child[], .child[+]
				 := false
				var  *symbol
				var  int

				if .rval.IsValid() && isConstType(.typ) {
					 = .cfgErrorf("cannot assign to %s (%s constant)", .rval, .typ.str)
					break
				}
				if isBlank() {
					 = .cfgErrorf("cannot use _ as value")
					break
				}
				if .kind == defineStmt || (.kind == assignStmt && .ident == "_") {
					if  != nil {
						.typ = 
					} else {
						if .typ,  = nodeType(, , );  != nil {
							return
						}
						if .typ.isBinMethod {
							.typ = valueTOf(.typ.methodCallType())
						} else {
							// In a new definition, propagate the source type to the destination
							// type. If the source is an untyped constant, make sure that the
							// type matches a default type.
							.typ = .fixType(.typ)
						}
					}
					if .typ.incomplete {
						return
					}
					if .global {
						// Do not overload existing symbols (defined in GTA) in global scope.
						, _, _ = .lookup(.ident)
					}
					if  == nil {
						 = &symbol{index: .add(.typ), kind: varSym, typ: .typ}
						.sym[.ident] = 
					}
					.val = .val
					.recv = .recv
					.findex = .index
					 = true
				} else {
					, , _ = .lookup(.ident)
				}

				 = .assignExpr(, , )
				if  != nil {
					break
				}

				if  {
					.typ = .typ
					.rval = .rval
					// As we are updating the sym type, we need to update the sc.type
					// when the sym has an index.
					if .index >= 0 {
						.types[.index] = .typ.frameType()
					}
				}
				.findex = .findex
				.level = .level

				// In the following, we attempt to optimize by skipping the assign
				// operation and setting the source location directly to the destination
				// location in the frame.
				//
				switch {
				case .action != aAssign:
					// Do not skip assign operation if it is combined with another operator.
				case .rval.IsValid():
					// Do not skip assign operation if setting from a constant value.
				case isMapEntry():
					// Setting a map entry requires an additional step, do not optimize.
					// As we only write, skip the default useless getIndexMap dest action.
					.gen = nop
				case isFuncField():
					// Setting a struct field of function type requires an extra step. Do not optimize.
				case isCall() && !isInterfaceSrc(.typ) && .kind != defineStmt:
					// Call action may perform the assignment directly.
					if .typ.id() != .typ.id() {
						// Skip optimitization if returned type doesn't match assigned one.
						break
					}
					.gen = nop
					.level = 
					.findex = .findex
					if .typ.untyped && !.typ.untyped {
						.typ = .typ
					}
				case .action == aRecv:
					// Assign by reading from a receiving channel.
					.gen = nop
					.findex = .findex // Set recv address to LHS.
					.typ = .typ
				case .action == aCompositeLit:
					if .typ.cat == valueT && .typ.rtype.Kind() == reflect.Interface {
						// Skip optimisation for assigned interface.
						break
					}
					if .action == aGetIndex || .action == aStar {
						// Skip optimization, as it does not work when assigning to a struct field or a dereferenced pointer.
						break
					}
					.gen = nop
					.findex = .findex
					.level = 
				case len(.child) < 4 && .kind != defineStmt && isArithmeticAction() && !isInterface(.typ):
					// Optimize single assignments from some arithmetic operations.
					.typ = .typ
					.findex = .findex
					.level = 
					.gen = nop
				case .kind == basicLit:
					// Assign to nil.
					.rval = reflect.New(.typ.TypeOf()).Elem()
				case .nright == 0:
					.gen = reset
				}

				.typ = .typ
				if  != nil {
					.typ = .typ
					.recv = .recv
				}

				.level = 

				if .anc.kind == constDecl {
					.gen = nop
					.findex = notInFrame
					if , ,  := .lookup(.ident);  {
						.kind = constSym
					}
					if childPos() == len(.anc.child)-1 {
						.iota = 0
					} else {
						.iota++
					}
				}
			}

		case incDecStmt:
			 = .unaryExpr()
			if  != nil {
				break
			}
			wireChild()
			.findex = .child[0].findex
			.level = .child[0].level
			.typ = .child[0].typ
			if , ,  := .lookup(.child[0].ident);  {
				.typ = .typ
				.level = 
			}

		case assignXStmt:
			wireChild()
			 := len(.child) - 1
			switch  := .child[]; .kind {
			case callExpr:
				if .child[-1].isType() {
					--
				}
				if  := .child[0].typ.numOut();  !=  {
					 = .cfgErrorf("assignment mismatch: %d variables but %s returns %d values", , .child[0].name(), )
				}
				if isBinCall(, ) {
					.gen = nop
				} else {
					// TODO (marc): skip if no conversion or wrapping is needed.
					.gen = assignFromCall
				}
			case indexExpr:
				.gen = getIndexMap2
				.gen = nop
			case typeAssertExpr:
				if .child[0].ident == "_" {
					.gen = typeAssertStatus
				} else {
					.gen = typeAssertLong
				}
				.gen = nop
			case unaryExpr:
				if .action == aRecv {
					.gen = recv2
					.gen = nop
				}
			}

		case defineXStmt:
			wireChild()
			if .def == nil {
				// In global scope, type definition already handled by GTA.
				break
			}
			 = compDefineX(, )

		case binaryExpr:
			wireChild()
			 := .universe.sym[nilIdent]
			,  := .child[0], .child[1]

			 = .binaryExpr()
			if  != nil {
				break
			}

			switch .action {
			case aRem:
				.typ = .typ
			case aShl, aShr:
				if .typ.untyped {
					break
				}
				.typ = .typ
			case aEqual, aNotEqual:
				.typ = .getType("bool")
				if .sym ==  || .sym ==  {
					if .action == aEqual {
						if .sym ==  {
							.gen = isNilChild(0)
						} else {
							.gen = isNilChild(1)
						}
					} else {
						.gen = isNotNil
					}
				}
			case aGreater, aGreaterEqual, aLower, aLowerEqual:
				.typ = .getType("bool")
			}
			if  != nil {
				break
			}
			if .typ == nil {
				if .typ,  = nodeType(, , );  != nil {
					break
				}
			}
			if .rval.IsValid() && .rval.IsValid() && (!isInterface(.typ)) && constOp[.action] != nil {
				.typ.TypeOf()       // Force compute of reflection type.
				constOp[.action]() // Compute a constant result now rather than during exec.
			}
			switch {
			case .rval.IsValid():
				// This operation involved constants, and the result is already computed
				// by constOp and available in n.rval. Nothing else to do at execution.
				.gen = nop
				.findex = notInFrame
			case .anc.kind == assignStmt && .anc.action == aAssign && .anc.nleft == 1:
				// To avoid a copy in frame, if the result is to be assigned, store it directly
				// at the frame location of destination.
				 := .anc.child[childPos()-.anc.nright]
				.typ = .typ
				.findex = .findex
				.level = .level
			case .anc.kind == returnStmt:
				// To avoid a copy in frame, if the result is to be returned, store it directly
				// at the frame location reserved for output arguments.
				.findex = childPos()
			default:
				// Allocate a new location in frame, and store the result here.
				.findex = .add(.typ)
			}

		case indexExpr:
			if isBlank(.child[0]) {
				 = .cfgErrorf("cannot use _ as value")
				break
			}
			wireChild()
			 := .child[0].typ
			for .cat == linkedT {
				 = .val
			}
			switch .cat {
			case ptrT:
				.typ = .val
				if .val.cat == valueT {
					.typ = valueTOf(.val.rtype.Elem())
				} else {
					.typ = .val.val
				}
			case stringT:
				.typ = .getType("byte")
			case valueT:
				if .rtype.Kind() == reflect.String {
					.typ = .getType("byte")
				} else {
					.typ = valueTOf(.rtype.Elem())
				}
			case funcT:
				// A function indexed by a type means an instantiated generic function.
				 := .child[1]
				if !.isType() {
					.typ = 
					return
				}
				, ,  := genAST(, .node.anc, []*itype{.typ})
				if  != nil {
					return
				}
				if ! {
					if _,  = .(, .node.anc.scope, , );  != nil {
						return
					}
					// Generate closures for function body.
					if  = genRun(.child[3]);  != nil {
						return
					}
				}
				// Replace generic func node by instantiated one.
				.anc.child[childPos()] = 
				.typ = .typ
				return
			case genericT:
				 := .id() + "[" + .child[1].typ.id() + "]"
				, ,  := .lookup()
				if ! {
					 = .cfgErrorf("type not found: %s", )
					return
				}
				.gen = nop
				.typ = .typ
				return
			case structT:
				// A struct indexed by a Type means an instantiated generic struct.
				 := .name + "[" + .child[1].ident + "]"
				, ,  := .lookup()
				if  {
					.typ = .typ
					.findex = .add(.typ)
					.gen = nop
					return
				}

			default:
				.typ = .val
			}
			.findex = .add(.typ)
			 := .TypeOf()
			if .Kind() == reflect.Map {
				 = .assignment(.child[1], .key, "map index")
				.gen = getIndexMap
				break
			}

			 := -1
			switch  := .Kind();  {
			case reflect.Array:
				 = .Len()
				fallthrough
			case reflect.Slice, reflect.String:
				.gen = getIndexArray
			case reflect.Ptr:
				if  := .Elem(); .Kind() == reflect.Array {
					 = .Len()
					.gen = getIndexArray
				} else {
					 = .cfgErrorf("type %v does not support indexing", )
				}
			default:
				 = .cfgErrorf("type is not an array, slice, string or map: %v", .id())
			}

			 = .index(.child[1], )

		case blockStmt:
			wireChild()
			if len(.child) > 0 {
				 := .lastChild()
				.findex = .findex
				.level = .level
				.val = .val
				.sym = .sym
				.typ = .typ
				.rval = .rval
			}
			 = .pop()

		case constDecl:
			wireChild()

		case varDecl:
			// Global varDecl do not need to be wired as this
			// will be handled after cfg.
			if .anc.kind == fileStmt {
				break
			}
			wireChild()

		case sendStmt:
			if !isChan(.child[0].typ) {
				 = .cfgErrorf("invalid operation: cannot send to non-channel %s", .child[0].typ.id())
				break
			}
			fallthrough

		case declStmt, exprStmt:
			wireChild()
			 := .lastChild()
			.findex = .findex
			.level = .level
			.val = .val
			.sym = .sym
			.typ = .typ
			.rval = .rval

		case breakStmt:
			if len(.child) == 0 {
				.tnext = .loop
				break
			}
			if !.hasAnc(.sym.node) {
				 = .cfgErrorf("invalid break label %s", .child[0].ident)
				break
			}
			.tnext = .sym.node

		case continueStmt:
			if len(.child) == 0 {
				.tnext = .loopRestart
				break
			}
			if !.hasAnc(.sym.node) {
				 = .cfgErrorf("invalid continue label %s", .child[0].ident)
				break
			}
			.tnext = .sym.node.child[1].lastChild().start

		case gotoStmt:
			if .sym.node == nil {
				// It can be only due to a forward goto, to be resolved at labeledStmt.
				// Invalid goto labels are catched at AST parsing.
				break
			}
			.tnext = .sym.node.start

		case labeledStmt:
			wireChild()
			if len(.child) > 1 {
				.start = .child[1].start
			}
			for ,  := range .sym.from {
				.tnext = .start // Resolve forward goto.
			}

		case callExpr:
			for ,  := range .child {
				if isBlank() {
					 = .cfgErrorf("cannot use _ as value")
					return
				}
			}
			wireChild()
			switch  := .child[0]; {
			case .kind == indexListExpr:
				// Instantiate a generic function then call it.
				 := .child[0].sym.node
				 := []*itype{}
				for ,  := range .child[1:] {
					 = append(, .typ)
				}
				, ,  := genAST(, , )
				if  != nil {
					return
				}
				if ! {
					_,  = .(, .scope, , )
					if  != nil {
						return
					}
					 = genRun(.child[3]) // Generate closures for function body.
					if  != nil {
						return
					}
				}
				.child[0] = 
				 = .child[0]
				wireChild()
				if  := .typ; len(.ret) > 0 {
					.typ = .ret[0]
					if .anc.kind == returnStmt && .typ.id() == .def.typ.ret[0].id() {
						// Store the result directly to the return value area of frame.
						// It can be done only if no type conversion at return is involved.
						.findex = childPos()
					} else {
						.findex = .add(.typ)
						for ,  := range .ret[1:] {
							.add()
						}
					}
				} else {
					.findex = notInFrame
				}

			case isBuiltinCall(, ):
				 := .ident
				 = .builtin(, , .child[1:], .action == aCallSlice)
				if  != nil {
					break
				}

				.gen = .sym.builtin
				.typ = &itype{cat: builtinT, name: }
				if .typ,  = nodeType(, , );  != nil {
					return
				}
				switch {
				case .typ.cat == builtinT:
					.findex = notInFrame
					.val = nil
					switch  {
					case "unsafe.alignOf", "unsafe.Offsetof", "unsafe.Sizeof":
						.gen = nop
					}
				case .anc.kind == returnStmt:
					// Store result directly to frame output location, to avoid a frame copy.
					.findex = 0
				case  == "cap" && isInConstOrTypeDecl():
					 := .child[1].typ.TypeOf()
					for .Kind() == reflect.Ptr {
						 = .Elem()
					}
					switch .Kind() {
					case reflect.Array, reflect.Chan:
						capConst()
					default:
						 = .cfgErrorf("cap argument is not an array or channel")
					}
					.findex = notInFrame
					.gen = nop
				case  == "len" && isInConstOrTypeDecl():
					 := .child[1].typ.TypeOf()
					for .Kind() == reflect.Ptr {
						 = .Elem()
					}
					switch .Kind() {
					case reflect.Array, reflect.Chan, reflect.String:
						lenConst()
					default:
						 = .cfgErrorf("len argument is not an array, channel or string")
					}
					.findex = notInFrame
					.gen = nop
				default:
					.findex = .add(.typ)
				}
				if ,  := constBltn[];  {
					()
				}

			case .isType():
				// Type conversion expression
				 := .child[1]
				switch len(.child) {
				case 1:
					 = .cfgErrorf("missing argument in conversion to %s", .typ.id())
				case 2:
					 = .conversion(, .typ)
				default:
					 = .cfgErrorf("too many arguments in conversion to %s", .typ.id())
				}
				if  != nil {
					break
				}

				.action = aConvert
				switch {
				case isInterface(.typ) && !.isNil():
					// Convert to interface: just check that all required methods are defined by concrete type.
					if !.typ.implements(.typ) {
						 = .cfgErrorf("type %v does not implement interface %v", .typ.id(), .typ.id())
					}
					// Convert type to interface while keeping a reference to the original concrete type.
					// besides type, the node value remains preserved.
					.gen = nop
					 := *.typ
					.typ = &
					.typ.val = .typ
					.findex = .findex
					.level = .level
					.val = .val
					.rval = .rval
				case .rval.IsValid() && isConstType(.typ):
					.gen = nop
					.findex = notInFrame
					.typ = .typ
					if ,  := .rval.Interface().(constant.Value);  {
						,  := constant.Int64Val(constant.ToInt())
						.rval = reflect.ValueOf().Convert(.typ.rtype)
					} else {
						.rval = .rval.Convert(.typ.rtype)
					}
				default:
					.gen = convert
					.typ = .typ
					.findex = .add(.typ)
				}

			case isBinCall(, ):
				 = .arguments(, .child[1:], , .action == aCallSlice)
				if  != nil {
					break
				}

				.gen = callBin
				 := .typ.rtype
				if .NumOut() > 0 {
					if  := .typ.val;  != nil {
						// Use the original unwrapped function type, to allow future field and
						// methods resolutions, otherwise impossible on the opaque bin type.
						.typ = .ret[0]
						.findex = .add(.typ)
						for  := 1;  < len(.ret); ++ {
							.add(.ret[])
						}
					} else {
						.typ = valueTOf(.Out(0))
						if .anc.kind == returnStmt {
							.findex = childPos()
						} else {
							.findex = .add(.typ)
							for  := 1;  < .NumOut(); ++ {
								.add(valueTOf(.Out()))
							}
						}
					}
				}

			default:
				// The call may be on a generic function. In that case, replace the
				// generic function AST by an instantiated one before going further.
				if isGeneric(.typ) {
					 := .typ.node.anc
					var  *node
					var  []*itype
					var  bool

					// Infer type parameter from function call arguments.
					if ,  = inferTypesFromCall(, , .child[1:]);  != nil {
						break
					}
					// Generate an instantiated AST from the generic function one.
					if , ,  = genAST(, , );  != nil {
						break
					}
					if ! {
						// Compile the generated function AST, so it becomes part of the scope.
						if _,  = .(, .scope, , );  != nil {
							break
						}
						// AST compilation part 2: Generate closures for function body.
						if  = genRun(.child[3]);  != nil {
							break
						}
					}
					.child[0] = 
					 = .child[0]
				}

				 = .arguments(, .child[1:], , .action == aCallSlice)
				if  != nil {
					break
				}

				if .action == aGetFunc {
					// Allocate a frame entry to store the anonymous function definition.
					.add(.typ)
				}
				if  := .typ; len(.ret) > 0 {
					.typ = .ret[0]
					if .anc.kind == returnStmt && .typ.id() == .def.typ.ret[0].id() {
						// Store the result directly to the return value area of frame.
						// It can be done only if no type conversion at return is involved.
						.findex = childPos()
					} else {
						.findex = .add(.typ)
						for ,  := range .ret[1:] {
							.add()
						}
					}
				} else {
					.findex = notInFrame
				}
			}

		case caseBody:
			wireChild()
			switch {
			case typeSwichAssign() && len(.child) > 1:
				.start = .child[1].start
			case len(.child) == 0:
				// Empty case body: jump to switch node (exit node).
				.start = .anc.anc.anc
			default:
				.start = .child[0].start
			}

		case caseClause:
			 = .pop()

		case commClauseDefault:
			wireChild()
			 = .pop()
			if len(.child) == 0 {
				return
			}
			.start = .child[0].start
			.lastChild().tnext = .anc.anc // exit node is selectStmt

		case commClause:
			wireChild()
			 = .pop()
			if len(.child) == 0 {
				return
			}
			if len(.child) > 1 {
				.start = .child[1].start // Skip chan operation, performed by select
			}
			.lastChild().tnext = .anc.anc // exit node is selectStmt

		case compositeLitExpr:
			wireChild()

			 := .child
			if .nleft > 0 {
				 = [1:]
			}

			switch .typ.cat {
			case arrayT, sliceT:
				 = .arrayLitExpr(, .typ)
			case mapT:
				 = .mapLitExpr(, .typ.key, .typ.val)
			case structT:
				 = .structLitExpr(, .typ)
			case valueT:
				 := .typ.rtype
				switch .Kind() {
				case reflect.Struct:
					 = .structBinLitExpr(, )
				case reflect.Map:
					 := valueTOf(.Key())
					 := valueTOf(.Elem())
					 = .mapLitExpr(, , )
				}
			}
			if  != nil {
				break
			}

			.findex = .add(.typ)
			// TODO: Check that composite literal expr matches corresponding type
			.gen = compositeGenerator(, .typ, nil)

		case fallthroughtStmt:
			if .anc.kind != caseBody {
				 = .cfgErrorf("fallthrough statement out of place")
			}

		case fileStmt:
			wireChild(, varDecl)
			 = .pop()
			.findex = notInFrame

		case forStmt0: // for {}
			 := .child[0]
			.start = .start
			.tnext = .start
			 = .pop()

		case forStmt1: // for init; ; {}
			,  := .child[0], .child[1]
			.start = .start
			.tnext = .start
			.tnext = .start
			 = .pop()

		case forStmt2: // for cond {}
			,  := .child[0], .child[1]
			if !isBool(.typ) {
				 = .cfgErrorf("non-bool used as for condition")
			}
			if .rval.IsValid() {
				// Condition is known at compile time, bypass test.
				if .rval.Bool() {
					.start = .start
					.tnext = .start
				}
			} else {
				.start = .start
				.tnext = .start
				.tnext = .start
			}
			setFNext(, )
			 = .pop()

		case forStmt3: // for init; cond; {}
			, ,  := .child[0], .child[1], .child[2]
			if !isBool(.typ) {
				 = .cfgErrorf("non-bool used as for condition")
			}
			.start = .start
			if .rval.IsValid() {
				// Condition is known at compile time, bypass test.
				if .rval.Bool() {
					.tnext = .start
					.tnext = .start
				} else {
					.tnext = 
				}
			} else {
				.tnext = .start
				.tnext = .start
			}
			.tnext = .start
			setFNext(, )
			 = .pop()

		case forStmt4: // for ; ; post {}
			,  := .child[0], .child[1]
			.start = .start
			.tnext = .start
			.tnext = .start
			 = .pop()

		case forStmt5: // for ; cond; post {}
			, ,  := .child[0], .child[1], .child[2]
			if !isBool(.typ) {
				 = .cfgErrorf("non-bool used as for condition")
			}
			if .rval.IsValid() {
				// Condition is known at compile time, bypass test.
				if .rval.Bool() {
					.start = .start
					.tnext = .start
				}
			} else {
				.start = .start
				.tnext = .start
			}
			.tnext = .start
			setFNext(, )
			.tnext = .start
			 = .pop()

		case forStmt6: // for init; ; post {}
			, ,  := .child[0], .child[1], .child[2]
			.start = .start
			.tnext = .start
			.tnext = .start
			.tnext = .start
			 = .pop()

		case forStmt7: // for init; cond; post {}
			, , ,  := .child[0], .child[1], .child[2], .child[3]
			if !isBool(.typ) {
				 = .cfgErrorf("non-bool used as for condition")
			}
			.start = .start
			if .rval.IsValid() {
				// Condition is known at compile time, bypass test.
				if .rval.Bool() {
					.tnext = .start
					.tnext = .start
				} else {
					.tnext = 
				}
			} else {
				.tnext = .start
				.tnext = .start
			}
			.tnext = .start
			setFNext(, )
			.tnext = .start
			 = .pop()

		case forRangeStmt:
			.start = .child[0].start
			setFNext(.child[0], )
			 = .pop()

		case funcDecl:
			.start = .child[3].start
			.types, .scope = .types, 
			 = .pop()
			 := .child[1].ident
			if  := .sym[]; !isMethod() &&  != nil && !isGeneric(.typ) {
				.index = -1 // to force value to n.val
				.typ = .typ
				.kind = funcSym
				.node = 
			}

		case funcLit:
			.types, .scope = .types, 
			 = .pop()
			 = genRun()

		case deferStmt, goStmt:
			wireChild()

		case identExpr:
			if isKey() || isNewDefine(, ) {
				break
			}
			if .anc.kind == funcDecl && .anc.child[1] ==  {
				// Dont process a function name identExpr.
				break
			}

			, ,  := .lookup(.ident)
			if ! {
				if .typ != nil {
					// Node is a generic instance with an already populated type.
					break
				}
				// retry with the filename, in case ident is a package name.
				, ,  = .lookup(filepath.Join(.ident, ))
				if ! {
					 = .cfgErrorf("undefined: %s", .ident)
					break
				}
			}
			// Found symbol, populate node info
			.sym, .typ, .findex, .level = , .typ, .index, 
			if .findex < 0 {
				.val = .node
			} else {
				switch {
				case .kind == constSym && .rval.IsValid():
					.rval = .rval
					.kind = basicLit
				case .ident == "iota":
					.rval = reflect.ValueOf(constant.MakeInt64(int64(.iota)))
					.kind = basicLit
				case .ident == nilIdent:
					.kind = basicLit
				case .kind == binSym:
					.typ = .typ
					.rval = .rval
				case .kind == bltnSym:
					if .anc.kind != callExpr {
						 = .cfgErrorf("use of builtin %s not in function call", .ident)
					}
				}
			}
			if .sym != nil {
				.recv = .sym.recv
			}

		case ifStmt0: // if cond {}
			,  := .child[0], .child[1]
			if !isBool(.typ) {
				 = .cfgErrorf("non-bool used as if condition")
			}
			if .rval.IsValid() {
				// Condition is known at compile time, bypass test.
				if .rval.Bool() {
					.start = .start
				}
			} else {
				.start = .start
				.tnext = .start
			}
			setFNext(, )
			.tnext = 
			 = .pop()

		case ifStmt1: // if cond {} else {}
			, ,  := .child[0], .child[1], .child[2]
			if !isBool(.typ) {
				 = .cfgErrorf("non-bool used as if condition")
			}
			if .rval.IsValid() {
				// Condition is known at compile time, bypass test and the useless branch.
				if .rval.Bool() {
					.start = .start
				} else {
					.start = .start
				}
			} else {
				.start = .start
				.tnext = .start
				setFNext(, .start)
			}
			.tnext = 
			.tnext = 
			 = .pop()

		case ifStmt2: // if init; cond {}
			, ,  := .child[0], .child[1], .child[2]
			if !isBool(.typ) {
				 = .cfgErrorf("non-bool used as if condition")
			}
			.start = .start
			if .rval.IsValid() {
				// Condition is known at compile time, bypass test.
				if .rval.Bool() {
					.tnext = .start
				} else {
					.tnext = 
				}
			} else {
				.tnext = .start
				.tnext = .start
			}
			.tnext = 
			setFNext(, )
			 = .pop()

		case ifStmt3: // if init; cond {} else {}
			, , ,  := .child[0], .child[1], .child[2], .child[3]
			if !isBool(.typ) {
				 = .cfgErrorf("non-bool used as if condition")
			}
			.start = .start
			if .rval.IsValid() {
				// Condition is known at compile time, bypass test.
				if .rval.Bool() {
					.tnext = .start
				} else {
					.tnext = .start
				}
			} else {
				.tnext = .start
				.tnext = .start
				setFNext(, .start)
			}
			.tnext = 
			.tnext = 
			 = .pop()

		case keyValueExpr:
			if isBlank(.child[1]) {
				 = .cfgErrorf("cannot use _ as value")
				break
			}
			wireChild()

		case landExpr:
			if isBlank(.child[0]) || isBlank(.child[1]) {
				 = .cfgErrorf("cannot use _ as value")
				break
			}
			.start = .child[0].start
			.child[0].tnext = .child[1].start
			setFNext(.child[0], )
			.child[1].tnext = 
			.typ = .child[0].typ
			.findex = .add(.typ)
			if .start.action == aNop {
				.start.gen = branch
			}

		case lorExpr:
			if isBlank(.child[0]) || isBlank(.child[1]) {
				 = .cfgErrorf("cannot use _ as value")
				break
			}
			.start = .child[0].start
			.child[0].tnext = 
			setFNext(.child[0], .child[1].start)
			.child[1].tnext = 
			.typ = .child[0].typ
			.findex = .add(.typ)
			if .start.action == aNop {
				.start.gen = branch
			}

		case parenExpr:
			wireChild()
			 := .lastChild()
			.findex = .findex
			.level = .level
			.typ = .typ
			.rval = .rval

		case rangeStmt:
			if .rangeChanType() != nil {
				.start = .child[1].start // Get chan
				.child[1].tnext =        // then go to range function
				.tnext = .child[2].start // then go to range body
				.child[2].tnext =        // then body go to range function (loop)
				.child[0].gen = empty
			} else {
				var , ,  *node
				if len(.child) == 4 {
					, ,  = .child[0], .child[2], .child[3]
				} else {
					, ,  = .child[0], .child[1], .child[2]
				}
				.start = .start    // Get array or map object
				.tnext = .start    // then go to iterator init
				.tnext =           // then go to range function
				.tnext = .start // then go to range body
				.tnext =        // then body go to range function (loop)
				.gen = empty        // init filled later by generator
			}

		case returnStmt:
			if len(.child) > .def.typ.numOut() {
				 = .cfgErrorf("too many arguments to return")
				break
			}
			for ,  := range .child {
				if isBlank() {
					 = .cfgErrorf("cannot use _ as value")
					return
				}
			}
			 := .def.child[2]
			if mustReturnValue() {
				 := len(.child)
				if  == 1 && isCall(.child[0]) {
					 = .child[0].child[0].typ.numOut()
				}
				if  < .def.typ.numOut() {
					 = .cfgErrorf("not enough arguments to return")
					break
				}
			}
			wireChild()
			.tnext = nil
			.val = .def
			for ,  := range .child {
				var  *itype
				,  = nodeType(, .upperLevel(), .child[2].fieldType())
				if  != nil {
					return
				}
				// TODO(mpl): move any of that code to typecheck?
				.typ.node = 
				if !.typ.assignableTo() {
					 = .cfgErrorf("cannot use %v (type %v) as type %v in return argument", .ident, .typ.cat, .cat)
					return
				}
				if .typ.cat == nilT {
					// nil: Set node value to zero of return type
					.rval = reflect.New(.TypeOf()).Elem()
				}
			}

		case selectorExpr:
			wireChild()
			.typ = .child[0].typ
			.recv = .child[0].recv
			if .typ == nil {
				 = .cfgErrorf("undefined type")
				break
			}
			switch {
			case .typ.cat == binPkgT:
				// Resolve binary package symbol: a type or a value
				 := .child[1].ident
				 := .child[0].sym.typ.path
				if ,  := .binPkg[][];  {
					if isBinType() {
						.typ = valueTOf(.Type().Elem())
					} else {
						.typ = valueTOf(fixPossibleConstType(.Type()), withUntyped(isValueUntyped()))
						.rval = 
						if  == "unsafe" && ( == "AlignOf" ||  == "Offsetof" ||  == "Sizeof") {
							.sym = &symbol{kind: bltnSym, node: , rval: }
							.ident =  + "." + 
						}
					}
					.action = aGetSym
					.gen = nop
				} else {
					 = .cfgErrorf("package %s \"%s\" has no symbol %s", .child[0].ident, , )
				}
			case .typ.cat == srcPkgT:
				,  := .child[0].sym.typ.path, .child[1].ident
				// Resolve source package symbol
				if ,  := .srcPkg[][];  {
					.findex = .index
					if .global {
						.level = globalFrame
					}
					.val = .node
					.gen = nop
					.action = aGetSym
					.typ = .typ
					.sym = 
					.recv = .recv
					.rval = .rval
				} else {
					 = .cfgErrorf("undefined selector: %s.%s", , )
				}
			case isStruct(.typ) || isInterfaceSrc(.typ):
				// Find a matching field.
				if  := .typ.lookupField(.child[1].ident); len() > 0 {
					if isStruct(.typ) {
						// If a method of the same name exists, use it if it is shallower than the struct field.
						// if method's depth is the same as field's, this is an error.
						 := .typ.methodDepth(.child[1].ident)
						if  >= 0 &&  < len() {
							goto 
						}
						if  == len() {
							 = .cfgErrorf("ambiguous selector: %s", .child[1].ident)
							break
						}
					}
					.val = 
					switch {
					case isInterfaceSrc(.typ):
						.typ = .typ.fieldSeq()
						.gen = getMethodByName
						.action = aMethod
					case .typ.cat == ptrT:
						.typ = .typ.fieldSeq()
						.gen = getPtrIndexSeq
						if .typ.cat == funcT {
							// Function in a struct field is always wrapped in reflect.Value.
							.typ = wrapperValueTOf(.typ.TypeOf(), .typ)
						}
					default:
						.gen = getIndexSeq
						.typ = .typ.fieldSeq()
						if .typ.cat == funcT {
							// Function in a struct field is always wrapped in reflect.Value.
							.typ = wrapperValueTOf(.typ.TypeOf(), .typ)
						}
					}
					break
				}
				if , ,  := .typ.lookupBinField(.child[1].ident);  {
					// Handle an embedded binary field into a struct field.
					.gen = getIndexSeqField
					 = append(, .Index...)
					if isStruct(.typ) {
						// If a method of the same name exists, use it if it is shallower than the struct field.
						// if method's depth is the same as field's, this is an error.
						 := .typ.methodDepth(.child[1].ident)
						if  >= 0 &&  < len() {
							goto 
						}
						if  == len() {
							 = .cfgErrorf("ambiguous selector: %s", .child[1].ident)
							break
						}
					}
					.val = 
					.typ = valueTOf(.Type)
					break
				}
				// No field (embedded or not) matched. Try to match a method.
			:
				fallthrough
			default:
				 = matchSelectorMethod(, )
			}
			if  == nil && .findex != -1 && .typ.cat != genericT {
				.findex = .add(.typ)
			}

		case selectStmt:
			wireChild()
			// Move action to block statement, so select node can be an exit point.
			.child[0].gen = _select
			// Chain channel init actions in commClauses prior to invoking select.
			var  *node
			for ,  := range .child[0].child {
				if .kind == commClauseDefault {
					// No channel init in this case.
					continue
				}
				var ,  *node // channel init action nodes
				if len(.child) > 0 {
					switch  := .child[0]; {
					case .kind == exprStmt && len(.child) == 1 && .child[0].action == aRecv:
						 = .child[0].child[0]
						 = 
					case .action == aAssign:
						 = .lastChild().child[0]
						 = 
					case .kind == sendStmt:
						 = .child[0]
						 = .child[1]
					}
				}
				if  == nil {
					continue
				}
				if  == nil {
					// First channel init action, the entry point for the select block.
					.start = .start
				} else {
					// Chain channel init action to the previous one.
					.tnext = .start
				}
				if  != nil {
					// Chain channect init action to send data init action.
					// (already done by wireChild, but let's be explicit).
					.tnext = 
					 = 
				}
			}
			if  == nil {
				// There is no channel init action, call select directly.
				.start = .child[0]
			} else {
				// Select is called after the last channel init action.
				.tnext = .child[0]
			}

		case starExpr:
			if isBlank(.child[0]) {
				 = .cfgErrorf("cannot use _ as value")
				break
			}
			switch {
			case .anc.kind == defineStmt && len(.anc.child) == 3 && .anc.child[1] == :
				// pointer type expression in a var definition
				.gen = nop
			case .anc.kind == valueSpec && .anc.lastChild() == :
				// pointer type expression in a value spec
				.gen = nop
			case .anc.kind == fieldExpr:
				// pointer type expression in a field expression (arg or struct field)
				.gen = nop
			case .child[0].isType():
				// pointer type expression
				.gen = nop
				.typ = ptrOf(.child[0].typ)
			default:
				// dereference expression
				wireChild()

				 = .starExpr(.child[0])
				if  != nil {
					break
				}

				if  := .child[0]; .typ.cat == valueT {
					.typ = valueTOf(.typ.rtype.Elem())
				} else {
					.typ = .typ.val
				}
				.findex = .add(.typ)
			}

		case typeSwitch:
			// Check that cases expressions are all different
			 := map[string]bool{}
			for ,  := range .lastChild().child {
				for ,  := range .child[:len(.child)-1] {
					 := .typ.id()
					if [] {
						 = .cfgErrorf("duplicate case %s in type switch", .ident)
						return
					}
					[] = true
				}
			}
			fallthrough

		case switchStmt:
			 = .pop()
			 := .lastChild() // switch block node
			 := .child
			 := len()
			if  == 0 {
				// Switch is empty
				break
			}
			// Chain case clauses.
			for  :=  - 1;  >= 0; -- {
				 := []
				if len(.child) == 0 {
					.tnext =  // Clause body is empty, exit.
				} else {
					 := .lastChild()
					.tnext = .start
					.child[0].tnext = 
					.start = .child[0].start

					if  < -1 && len(.child) > 0 && .lastChild().kind == fallthroughtStmt {
						if .kind == typeSwitch {
							 = .lastChild().cfgErrorf("cannot fallthrough in type switch")
						}
						if len([+1].child) == 0 {
							.tnext =  // Fallthrough to next with empty body, just exit.
						} else {
							.tnext = [+1].lastChild().start
						}
					} else {
						.tnext =  // Exit switch at end of clause body.
					}
				}

				if  == -1 {
					setFNext([], )
					continue
				}
				if len([+1].child) > 1 {
					setFNext(, [+1].start)
				} else {
					setFNext(, [+1])
				}
			}
			.start = [0].start
			.start = .child[0].start
			if .kind == typeSwitch {
				// Handle the typeSwitch init (the type assert expression).
				 := .child[1].lastChild().child[0]
				.tnext = .start
				.child[0].tnext = .start
			} else {
				.child[0].tnext = .start
			}

		case switchIfStmt: // like an if-else chain
			 = .pop()
			 := .lastChild() // switch block node
			 := .child
			 := len()
			if  == 0 {
				// Switch is empty
				break
			}
			// Wire case clauses in reverse order so the next start node is already resolved when used.
			for  :=  - 1;  >= 0; -- {
				 := []
				.gen = nop
				if len(.child) == 0 {
					.tnext = 
					.fnext = 
				} else {
					 := .lastChild()
					if len(.child) > 1 {
						 := .child[0]
						.tnext = .start
						if  == -1 {
							setFNext(, )
						} else {
							setFNext(, [+1].start)
						}
						.start = .start
					} else {
						.start = .start
					}
					// If last case body statement is a fallthrough, then jump to next case body
					if  < -1 && len(.child) > 0 && .lastChild().kind == fallthroughtStmt {
						.tnext = [+1].lastChild().start
					} else {
						.tnext = 
					}
				}
			}
			.start = [0].start
			.start = .child[0].start
			.child[0].tnext = .start

		case typeAssertExpr:
			if len(.child) == 1 {
				// The "o.(type)" is handled by typeSwitch.
				.gen = nop
				break
			}

			wireChild()
			,  := .child[0], .child[1]
			if isBlank() || isBlank() {
				 = .cfgErrorf("cannot use _ as value")
				break
			}
			if .typ == nil {
				if .typ,  = nodeType(, , );  != nil {
					return
				}
			}

			 = .typeAssertionExpr(, .typ)
			if  != nil {
				break
			}

			if .anc.action != aAssignX {
				if .typ.cat == valueT && isFunc(.typ) {
					// Avoid special wrapping of interfaces and func types.
					.typ = valueTOf(.typ.TypeOf())
				} else {
					.typ = .typ
				}
				.findex = .add(.typ)
			}

		case sliceExpr:
			wireChild()

			 = .sliceExpr()
			if  != nil {
				break
			}

			if .typ,  = nodeType(, , );  != nil {
				return
			}
			.findex = .add(.typ)

		case unaryExpr:
			wireChild()

			 = .unaryExpr()
			if  != nil {
				break
			}

			.typ = .child[0].typ
			if .action == aRecv {
				// Channel receive operation: set type to the channel data type
				if .typ.cat == valueT {
					.typ = valueTOf(.typ.rtype.Elem())
				} else {
					.typ = .typ.val
				}
			}
			if .typ == nil {
				if .typ,  = nodeType(, , );  != nil {
					return
				}
			}

			// TODO: Optimisation: avoid allocation if boolean branch op (i.e. '!' in an 'if' expr)
			if .child[0].rval.IsValid() && !isInterface(.typ) && constOp[.action] != nil {
				.typ.TypeOf() // init reflect type
				constOp[.action]()
			}
			switch {
			case .rval.IsValid():
				.gen = nop
				.findex = notInFrame
			case .anc.kind == assignStmt && .anc.action == aAssign && .anc.nright == 1:
				 := .anc.child[childPos()-.anc.nright]
				.typ = .typ
				.findex = .findex
				.level = .level
			case .anc.kind == returnStmt:
				 := childPos()
				.typ = .def.typ.ret[]
				.findex = 
			default:
				.findex = .add(.typ)
			}

		case valueSpec:
			.gen = reset
			 := len(.child) - 1
			if .typ = .child[].typ; .typ == nil {
				if .typ,  = nodeType(, , .child[]);  != nil {
					return
				}
			}

			for ,  := range .child[:] {
				var  int
				if .global {
					// Global object allocation is already performed in GTA.
					 = .sym[.ident].index
					.level = globalFrame
				} else {
					 = .add(.typ)
					.sym[.ident] = &symbol{index: , kind: varSym, typ: .typ}
				}
				.typ = .typ
				.findex = 
			}
		}
	})

	if  != .universe {
		.pop()
	}
	return , 
}

func compDefineX( *scope,  *node) error {
	 := len(.child) - 1
	 := []*itype{}

	switch  := .child[]; .kind {
	case callExpr:
		,  := nodeType(.interp, , .child[0])
		if  != nil {
			return 
		}
		for .cat == valueT && .val != nil {
			// Retrieve original interpreter type from a wrapped function.
			// Struct fields of function types are always wrapped in valueT to ensure
			// their possible use in runtime. In that case, the val field retains the
			// original interpreter type, which is used now.
			 = .val
		}
		if .cat == valueT {
			// Handle functions imported from runtime.
			for  := 0;  < .rtype.NumOut(); ++ {
				 = append(, valueTOf(.rtype.Out()))
			}
		} else {
			 = .ret
		}
		if .anc.kind == varDecl && .child[-1].isType() {
			--
		}
		if len() !=  {
			return .cfgErrorf("assignment mismatch: %d variables but %s returns %d values", , .child[0].name(), len())
		}
		if isBinCall(, ) {
			.gen = nop
		} else {
			// TODO (marc): skip if no conversion or wrapping is needed.
			.gen = assignFromCall
		}

	case indexExpr:
		 = append(, .typ, .getType("bool"))
		.child[].gen = getIndexMap2
		.gen = nop

	case typeAssertExpr:
		if .child[0].ident == "_" {
			.child[].gen = typeAssertStatus
		} else {
			.child[].gen = typeAssertLong
		}
		 = append(, .child[].child[1].typ, .getType("bool"))
		.gen = nop

	case unaryExpr:
		if .child[].action == aRecv {
			 = append(, .typ, .getType("bool"))
			.child[].gen = recv2
			.gen = nop
		}

	default:
		return .cfgErrorf("unsupported assign expression")
	}

	// Handle redeclarations: find out new symbols vs existing ones.
	 := map[string]bool{}
	 := false
	for  := range  {
		 := .child[].ident
		if  == "_" ||  == "" {
			continue
		}
		if ,  := [];  {
			return .cfgErrorf("%s repeated on left side of :=", )
		}
		// A new symbol doesn't exist in current scope. Upper scopes are not
		// taken into accout here, as a new symbol can shadow an existing one.
		if ,  := .sym[];  {
			[] = false
		} else {
			[] = true
			 = true
		}
	}

	for ,  := range  {
		var  int
		 := .child[].ident
		// A variable can be redeclared if at least one other not blank variable is created.
		// The redeclared variable must be of same type (it is reassigned, not created).
		// Careful to not reuse a variable which has been shadowed (it must not be a newSym).
		, ,  := .lookup()
		 :=  && len() > 1 && ![] && 
		if  &&  == .child[].level && .kind == varSym && .typ.id() == .id() {
			 = .index
			.child[].redeclared = true
		} else {
			 = .add()
			.sym[] = &symbol{index: , kind: varSym, typ: }
		}
		.child[].typ = 
		.child[].findex = 
	}
	return nil
}

// TODO used for allocation optimization, temporarily disabled
// func isAncBranch(n *node) bool {
//	switch n.anc.kind {
//	case If0, If1, If2, If3:
//		return true
//	}
//	return false
// }

func childPos( *node) int {
	for ,  := range .anc.child {
		if  ==  {
			return 
		}
	}
	return -1
}

func ( *node) ( string,  ...interface{}) *cfgError {
	 := .interp.fset.Position(.pos)
	 := .interp.fset.Position(.pos).String()
	if .Filename == DefaultSourceName {
		 = strings.TrimPrefix(, DefaultSourceName+":")
	}
	 = append([]interface{}{}, ...)
	return &cfgError{, fmt.Errorf("%s: "+, ...)}
}

func genRun( *node) error {
	var  error
	 := map[*node]bool{}

	.Walk(func( *node) bool {
		if  != nil || [] {
			return false
		}
		[] = true
		switch .kind {
		case funcType:
			if len(.anc.child) == 4 {
				// function body entry point
				setExec(.anc.child[3].start)
			}
			// continue in function body as there may be inner function definitions
		case constDecl, varDecl:
			setExec(.start)
			return false
		}
		return true
	}, nil)

	return 
}

func genGlobalVars( []*node,  *scope) (*node, error) {
	var  []*node
	for ,  := range  {
		 = append(, getVars()...)
	}

	if len() == 0 {
		return nil, nil
	}

	,  := genGlobalVarDecl(, )
	if  != nil {
		return nil, 
	}
	setExec(.start)
	return , nil
}

func getVars( *node) ( []*node) {
	for ,  := range .child {
		if .kind == varDecl {
			 = append(, .child...)
		}
	}
	return 
}

func genGlobalVarDecl( []*node,  *scope) (*node, error) {
	 := &node{kind: varDecl, action: aNop, gen: nop}

	 := map[*node][]*node{}
	for ,  := range  {
		[] = getVarDependencies(, )
	}

	 := map[*node]bool{}
	 := []*node{}
	for {
		for ,  := range  {
			 := true
			for ,  := range [] {
				if ![] {
					 = false
				}
			}
			if ! {
				 = append(, )
				continue
			}

			.child = append(.child, )
			[] = true
		}

		if len() == 0 || equalNodes(, ) {
			break
		}

		 = 
		 = []*node{}
	}

	if len() > 0 {
		return nil, [0].cfgErrorf("variable definition loop")
	}
	wireChild()
	return , nil
}

func getVarDependencies( *node,  *scope) ( []*node) {
	.Walk(func( *node) bool {
		if .kind != identExpr {
			return true
		}
		// Process ident nodes, and avoid false dependencies.
		if .anc.kind == selectorExpr && childPos() == 1 {
			return false
		}
		, ,  := .lookup(.ident)
		if ! {
			return false
		}
		if .kind != varSym || !.global || .node ==  {
			return false
		}
		 = append(, .node)
		return false
	}, nil)
	return 
}

// setFnext sets the cond fnext field to next, propagates it for parenthesis blocks
// and sets the action to branch.
func setFNext(,  *node) {
	if .action == aNop {
		.action = aBranch
		.gen = branch
		.fnext = 
	}
	if .kind == parenExpr {
		(.lastChild(), )
		return
	}
	.fnext = 
}

// GetDefault return the index of default case clause in a switch statement, or -1.
func getDefault( *node) int {
	for ,  := range .lastChild().child {
		switch len(.child) {
		case 0:
			return 
		case 1:
			if .child[0].kind == caseBody {
				return 
			}
		}
	}
	return -1
}

func isBinType( reflect.Value) bool { return .IsValid() && .Kind() == reflect.Ptr && .IsNil() }

// isType returns true if node refers to a type definition, false otherwise.
func ( *node) ( *scope) bool {
	switch .kind {
	case arrayType, chanType, chanTypeRecv, chanTypeSend, funcType, interfaceType, mapType, structType:
		return true
	case parenExpr, starExpr:
		if len(.child) == 1 {
			return .child[0].()
		}
	case selectorExpr:
		,  := .child[0].ident, .child[1].ident
		 := filepath.Base(.interp.fset.Position(.pos).Filename)
		 := filepath.Join(, )
		, ,  := .lookup()
		if ! {
			, _,  = .lookup()
			if ! {
				return false
			}
		}
		if .kind != pkgSym {
			return false
		}
		 := .typ.path
		if ,  := .interp.binPkg[];  && isBinType([]) {
			return true // Imported binary type
		}
		if ,  := .interp.srcPkg[];  && [] != nil && [].kind == typeSym {
			return true // Imported source type
		}
	case identExpr:
		return .getType(.ident) != nil
	case indexExpr:
		// Maybe a generic type.
		, ,  := .lookup(.child[0].ident)
		return  && .kind == typeSym
	}
	return false
}

// wireChild wires AST nodes for CFG in subtree.
func wireChild( *node,  ...nkind) {
	 := excludeNodeKind(.child, )

	// Set start node, in subtree (propagated to ancestors by post-order processing)
	for ,  := range  {
		switch .kind {
		case arrayType, chanType, chanTypeRecv, chanTypeSend, funcDecl, importDecl, mapType, basicLit, identExpr, typeDecl:
			continue
		default:
			.start = .start
		}
		break
	}

	// Chain sequential operations inside a block (next is right sibling)
	for  := 1;  < len(); ++ {
		switch [].kind {
		case funcDecl:
			[-1].tnext = []
		default:
			switch [-1].kind {
			case breakStmt, continueStmt, gotoStmt, returnStmt:
				// tnext is already computed, no change
			default:
				[-1].tnext = [].start
			}
		}
	}

	// Chain subtree next to self
	for  := len() - 1;  >= 0; -- {
		switch [].kind {
		case arrayType, chanType, chanTypeRecv, chanTypeSend, importDecl, mapType, funcDecl, basicLit, identExpr, typeDecl:
			continue
		case breakStmt, continueStmt, gotoStmt, returnStmt:
			// tnext is already computed, no change
		default:
			[].tnext = 
		}
		break
	}
}

func excludeNodeKind( []*node,  []nkind) []*node {
	if len() == 0 {
		return 
	}
	var  []*node
	for ,  := range  {
		 := false
		for ,  := range  {
			if .kind ==  {
				 = true
			}
		}
		if ! {
			 = append(, )
		}
	}
	return 
}

func ( *node) () ( string) {
	switch {
	case .ident != "":
		 = .ident
	case .action == aGetSym:
		 = .child[0].ident + "." + .child[1].ident
	}
	return 
}

// isNatural returns true if node type is natural, false otherwise.
func ( *node) () bool {
	if isUint(.typ.TypeOf()) {
		return true
	}
	if .rval.IsValid() {
		 := .rval.Type()
		if isUint() {
			return true
		}
		if isInt() && .rval.Int() >= 0 {
			// positive untyped integer constant is ok
			return true
		}
		if isFloat() {
			// positive untyped float constant with null decimal part is ok
			 := .rval.Float()
			if  == math.Trunc() &&  >= 0 {
				.rval = reflect.ValueOf(uint())
				.typ.rtype = .rval.Type()
				return true
			}
		}
		if isConstantValue() {
			 := .rval.Interface().(constant.Value)
			switch .Kind() {
			case constant.Int:
				,  := constant.Int64Val()
				if  >= 0 {
					return true
				}
			case constant.Float:
				,  := constant.Float64Val()
				if  == math.Trunc() {
					.rval = reflect.ValueOf(constant.ToInt())
					.typ.rtype = .rval.Type()
					return true
				}
			}
		}
	}
	return false
}

// isNil returns true if node is a literal nil value, false otherwise.
func ( *node) () bool { return .kind == basicLit && !.rval.IsValid() }

// fieldType returns the nth parameter field node (type) of a fieldList node.
func ( *node) ( int) *node {
	 := 0
	 := len(.child)
	for  := 0;  < ; ++ {
		 := len(.child[].child)
		if  < 2 {
			if  ==  {
				return .child[].lastChild()
			}
			++
			continue
		}
		for  := 0;  < -1; ++ {
			if  ==  {
				return .child[].lastChild()
			}
			++
		}
	}
	return nil
}

// lastChild returns the last child of a node.
func ( *node) () *node { return .child[len(.child)-1] }

func ( *node) ( *node) bool {
	for  := .anc;  != nil;  = .anc {
		if  ==  {
			return true
		}
	}
	return false
}

func isKey( *node) bool {
	return .anc.kind == fileStmt ||
		(.anc.kind == selectorExpr && .anc.child[0] != ) ||
		(.anc.kind == funcDecl && isMethod(.anc)) ||
		(.anc.kind == keyValueExpr && isStruct(.anc.typ) && .anc.child[0] == ) ||
		(.anc.kind == fieldExpr && len(.anc.child) > 1 && .anc.child[0] == )
}

func isField( *node) bool {
	return .kind == selectorExpr && len(.child) > 0 && .child[0].typ != nil && isStruct(.child[0].typ)
}

func isInInterfaceType( *node) bool {
	 := .anc
	for  != nil {
		if .kind == interfaceType {
			return true
		}
		 = .anc
	}
	return false
}

func isInConstOrTypeDecl( *node) bool {
	 := .anc
	for  != nil {
		switch .kind {
		case constDecl, typeDecl, arrayType, chanType:
			return true
		case varDecl, funcDecl:
			return false
		}
		 = .anc
	}
	return false
}

// isNewDefine returns true if node refers to a new definition.
func isNewDefine( *node,  *scope) bool {
	if .ident == "_" {
		return true
	}
	if (.anc.kind == defineXStmt || .anc.kind == defineStmt || .anc.kind == valueSpec) && childPos() < .anc.nleft {
		return true
	}
	if .anc.kind == rangeStmt {
		if .anc.child[0] ==  {
			return true // array or map key, or chan element
		}
		if .rangeChanType(.anc) == nil && .anc.child[1] ==  && len(.anc.child) == 4 {
			return true // array or map value
		}
		return false // array, map or channel are always pre-defined in range expression
	}
	return false
}

func isMethod( *node) bool {
	return len(.child[0].child) > 0 // receiver defined
}

func isFuncField( *node) bool {
	return isField() && isFunc(.typ)
}

func isMapEntry( *node) bool {
	return .action == aGetIndex && isMap(.child[0].typ)
}

func isCall( *node) bool {
	return .action == aCall || .action == aCallSlice
}

func isBinCall( *node,  *scope) bool {
	if !isCall() || len(.child) == 0 {
		return false
	}
	 := .child[0]
	if .typ == nil {
		// If called early in parsing, child type may not be known yet.
		.typ, _ = nodeType(.interp, , )
		if .typ == nil {
			return false
		}
	}
	return .typ.cat == valueT && .typ.rtype.Kind() == reflect.Func
}

func mustReturnValue( *node) bool {
	if len(.child) < 3 {
		return false
	}
	for ,  := range .child[2].child {
		if len(.child) > 1 {
			return false
		}
	}
	return true
}

func isRegularCall( *node) bool {
	return isCall() && .child[0].typ.cat == funcT
}

func variadicPos( *node) int {
	if len(.child[0].typ.arg) == 0 {
		return -1
	}
	 := len(.child[0].typ.arg) - 1
	if .child[0].typ.arg[].cat == variadicT {
		return 
	}
	return -1
}

func canExport( string) bool {
	if  := []rune(); len() > 0 && unicode.IsUpper([0]) {
		return true
	}
	return false
}

func getExec( *node) bltn {
	if  == nil {
		return nil
	}
	if .exec == nil {
		setExec()
	}
	return .exec
}

// setExec recursively sets the node exec builtin function by walking the CFG
// from the entry point (first node to exec).
func setExec( *node) {
	if .exec != nil {
		return
	}
	 := map[*node]bool{}
	var  func( *node)

	 = func( *node) {
		if  == nil || .exec != nil {
			return
		}
		[] = true
		if .tnext != nil && .tnext.exec == nil {
			if [.tnext] {
				 := .tnext
				.tnext.exec = func( *frame) bltn { return .exec() }
			} else {
				(.tnext)
			}
		}
		if .fnext != nil && .fnext.exec == nil {
			if [.fnext] {
				 := .fnext
				.fnext.exec = func( *frame) bltn { return .exec() }
			} else {
				(.fnext)
			}
		}
		.gen()
	}

	()
}

func typeSwichAssign( *node) bool {
	 := .anc.anc.anc
	return .kind == typeSwitch && .child[1].action == aAssign
}

func compositeGenerator( *node,  *itype,  reflect.Type) ( bltnGenerator) {
	switch .cat {
	case linkedT, ptrT:
		 = (, .val, )
	case arrayT, sliceT:
		 = arrayLit
	case mapT:
		 = mapLit
	case structT:
		switch {
		case len(.child) == 0:
			 = compositeLitNotype
		case .lastChild().kind == keyValueExpr:
			if .nleft == 1 {
				 = compositeLitKeyed
			} else {
				 = compositeLitKeyedNotype
			}
		default:
			if .nleft == 1 {
				 = compositeLit
			} else {
				 = compositeLitNotype
			}
		}
	case valueT:
		if  == nil {
			 = .typ.TypeOf()
		}
		switch  := .Kind();  {
		case reflect.Struct:
			if .nleft == 1 {
				 = compositeBinStruct
			} else {
				 = compositeBinStructNotype
			}
		case reflect.Map:
			// TODO(mpl): maybe needs a NoType version too
			 = compositeBinMap
		case reflect.Ptr:
			 = (, , .typ.val.rtype)
		case reflect.Slice, reflect.Array:
			 = compositeBinSlice
		default:
			log.Panic(.cfgErrorf("compositeGenerator not implemented for type kind: %s", ))
		}
	}
	return 
}

// matchSelectorMethod, given that n represents a selector for a method, tries
// to find the corresponding method, and populates n accordingly.
func matchSelectorMethod( *scope,  *node) ( error) {
	 := .child[1].ident
	if .typ.cat == valueT || .typ.cat == errorT {
		switch ,  := .typ.rtype.MethodByName(); {
		case :
			 := .typ.TypeOf().Kind() != reflect.Interface
			.val = .Index
			.gen = getIndexBinMethod
			.action = aGetMethod
			.recv = &receiver{node: .child[0]}
			.typ = valueTOf(.Type, isBinMethod())
			if  {
				.typ.recv = .typ
			}
		case .typ.TypeOf().Kind() == reflect.Ptr:
			if ,  := .typ.rtype.Elem().FieldByName();  {
				.typ = valueTOf(.Type)
				.val = .Index
				.gen = getPtrIndexSeq
				break
			}
			 = .cfgErrorf("undefined method: %s", )
		case .typ.TypeOf().Kind() == reflect.Struct:
			if ,  := .typ.rtype.FieldByName();  {
				.typ = valueTOf(.Type)
				.val = .Index
				.gen = getIndexSeq
				break
			}
			fallthrough
		default:
			// method lookup failed on type, now lookup on pointer to type
			 := reflect.PtrTo(.typ.rtype)
			if ,  := .MethodByName();  {
				.val = .Index
				.gen = getIndexBinPtrMethod
				.typ = valueTOf(.Type, isBinMethod(), withRecv(valueTOf()))
				.recv = &receiver{node: .child[0]}
				.action = aGetMethod
				break
			}
			 = .cfgErrorf("undefined method: %s", )
		}
		return 
	}

	if .typ.cat == ptrT && (.typ.val.cat == valueT || .typ.val.cat == errorT) {
		// Handle pointer on object defined in runtime
		if ,  := .typ.val.rtype.MethodByName();  {
			.val = .Index
			.typ = valueTOf(.Type, isBinMethod(), withRecv(.typ))
			.recv = &receiver{node: .child[0]}
			.gen = getIndexBinElemMethod
			.action = aGetMethod
		} else if ,  := reflect.PtrTo(.typ.val.rtype).MethodByName();  {
			.val = .Index
			.gen = getIndexBinMethod
			.typ = valueTOf(.Type, withRecv(valueTOf(reflect.PtrTo(.typ.val.rtype), isBinMethod())))
			.recv = &receiver{node: .child[0]}
			.action = aGetMethod
		} else if ,  := .typ.val.rtype.FieldByName();  {
			.typ = valueTOf(.Type)
			.val = .Index
			.gen = getPtrIndexSeq
		} else {
			 = .cfgErrorf("undefined selector: %s", )
		}
		return 
	}

	if ,  := .typ.lookupMethod();  != nil {
		.action = aGetMethod
		if .child[0].isType() {
			// Handle method as a function with receiver in 1st argument.
			.val = 
			.findex = notInFrame
			.gen = nop
			.typ = &itype{}
			*.typ = *.typ
			.typ.arg = append([]*itype{.child[0].typ}, .typ.arg...)
		} else {
			// Handle method with receiver.
			.gen = getMethod
			.val = 
			.typ = .typ
			.recv = &receiver{node: .child[0], index: }
		}
		return nil
	}

	if , , ,  := .typ.lookupBinMethod();  {
		.action = aGetMethod
		switch {
		case  && .typ.fieldSeq().cat != ptrT:
			.gen = getIndexSeqPtrMethod
		case isInterfaceSrc(.typ):
			.gen = getMethodByName
		default:
			.gen = getIndexSeqMethod
		}
		.recv = &receiver{node: .child[0], index: }
		.val = append([]int{.Index}, ...)
		.typ = valueTOf(.Type, isBinMethod(), withRecv(.child[0].typ))
		return nil
	}

	if  := .typ.interfaceMethod();  != nil {
		.typ = 
		.action = aGetMethod
		.gen = getMethodByName
		return nil
	}

	return .cfgErrorf("undefined selector: %s", )
}

// arrayTypeLen returns the node's array length. If the expression is an
// array variable it is determined from the value's type, otherwise it is
// computed from the source definition.
func arrayTypeLen( *node,  *scope) (int, error) {
	if .typ != nil && .typ.cat == arrayT {
		return .typ.length, nil
	}
	 := -1
	for ,  := range .child[1:] {
		var  int

		if .kind != keyValueExpr {
			 =  + 1
			 = 
			continue
		}

		 := .child[0]
		 := .rval
		if .IsValid() {
			 = int(.Int())
		} else {
			// Resolve array key value as a constant.
			if .kind == identExpr {
				// Key is defined by a symbol which must be a constant integer.
				, ,  := .lookup(.ident)
				if ! {
					return 0, .cfgErrorf("undefined: %s", .ident)
				}
				if .kind != constSym {
					return 0, .cfgErrorf("non-constant array bound %q", .ident)
				}
				 = int(vInt(.rval))
			} else {
				// Key is defined by a numeric constant expression.
				if ,  := .interp.cfg(, , .pkgID, .pkgName);  != nil {
					return 0, 
				}
				,  := .rval.Interface().(constant.Value)
				if ! {
					return 0, .cfgErrorf("non-constant expression")
				}
				 = constToInt()
			}
		}

		if  >  {
			 = 
		}
	}
	return  + 1, nil
}

// isValueUntyped returns true if value is untyped.
func isValueUntyped( reflect.Value) bool {
	// Consider only constant values.
	if .CanSet() {
		return false
	}
	return .Type().Implements(constVal)
}

// isArithmeticAction returns true if the node action is an arithmetic operator.
func isArithmeticAction( *node) bool {
	switch .action {
	case aAdd, aAnd, aAndNot, aBitNot, aMul, aNeg, aOr, aPos, aQuo, aRem, aShl, aShr, aSub, aXor:
		return true
	}
	return false
}

func isBoolAction( *node) bool {
	switch .action {
	case aEqual, aGreater, aGreaterEqual, aLand, aLor, aLower, aLowerEqual, aNot, aNotEqual:
		return true
	}
	return false
}

func isBlank( *node) bool {
	if .kind == parenExpr && len(.child) > 0 {
		return (.child[0])
	}
	return .ident == "_"
}

func alignof( *node) {
	.gen = nop
	.typ = .scope.getType("uintptr")
	.rval = reflect.ValueOf(uintptr(.child[1].typ.TypeOf().Align()))
}

func offsetof( *node) {
	.gen = nop
	.typ = .scope.getType("uintptr")
	 := .child[1]
	if ,  := .child[0].typ.rtype.FieldByName(.child[1].ident);  {
		.rval = reflect.ValueOf(.Offset)
	}
}

func sizeof( *node) {
	.gen = nop
	.typ = .scope.getType("uintptr")
	.rval = reflect.ValueOf(.child[1].typ.TypeOf().Size())
}