func (a *stmtCompiler) compileReturnStmt(s *ast.ReturnStmt) { if a.fnType == nil { a.diag("cannot return at the top level") return } if len(s.Results) == 0 && (len(a.fnType.Out) == 0 || a.outVarsNamed) { // Simple case. Simply exit from the function. a.flow.putTerm() a.push(func(v *Thread) { v.pc = returnPC }) return } bc := a.enterChild() defer bc.exit() // Compile expressions bad := false rs := make([]*expr, len(s.Results)) for i, re := range s.Results { rs[i] = a.compileExpr(bc.block, false, re) if rs[i] == nil { bad = true } } if bad { return } // Create assigner // However, if the expression list in the "return" statement // is a single call to a multi-valued function, the values // returned from the called function will be returned from // this one. assign := a.compileAssign(s.Pos(), bc.block, NewMultiType(a.fnType.Out), rs, "return", "value") // XXX(Spec) "The result types of the current function and the // called function must match." Match is fuzzy. It should // say that they must be assignment compatible. // Compile start := len(a.fnType.In) nout := len(a.fnType.Out) a.flow.putTerm() a.push(func(t *Thread) { assign(multiV(t.f.Vars[start:start+nout]), t) t.pc = returnPC }) }
func (f *File) validRetStmt(ret *ast.ReturnStmt) *Error { // returning nothing is ok if ret.Results == nil || len(ret.Results) == 0 { return nil } // Cannot return multiple values if len(ret.Results) > 1 { return &Error{errors.New("Return statements can only have one result"), ret.Pos()} } expr := ret.Results[0] if err := f.validRetExpr(expr); err != nil { return err } return nil }