errors.go raw

   1  package interp
   2  
   3  // This file provides useful types for errors encountered during IR evaluation.
   4  
   5  import (
   6  	"errors"
   7  	"go/scanner"
   8  	"go/token"
   9  	"path/filepath"
  10  
  11  	"tinygo.org/x/go-llvm"
  12  )
  13  
  14  // These errors are expected during normal execution and can be recovered from
  15  // by running the affected function at runtime instead of compile time.
  16  var (
  17  	errIntegerAsPointer       = errors.New("interp: trying to use an integer as a pointer (memory-mapped I/O?)")
  18  	errUnsupportedInst        = errors.New("interp: unsupported instruction")
  19  	errUnsupportedRuntimeInst = errors.New("interp: unsupported instruction (to be emitted at runtime)")
  20  	errMapAlreadyCreated      = errors.New("interp: map already created")
  21  	errLoopUnrolled           = errors.New("interp: loop unrolled")
  22  )
  23  
  24  // This is one of the errors that can be returned from toLLVMValue when the
  25  // passed type does not fit the data to serialize. It is recoverable by
  26  // serializing without a type (using rawValue.rawLLVMValue).
  27  var errInvalidPtrToIntSize = errors.New("interp: ptrtoint integer size does not equal pointer size")
  28  
  29  func isRecoverableError(err error) bool {
  30  	return err == errIntegerAsPointer || err == errUnsupportedInst ||
  31  		err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated ||
  32  		err == errLoopUnrolled
  33  }
  34  
  35  // ErrorLine is one line in a traceback. The position may be missing.
  36  type ErrorLine struct {
  37  	Pos  token.Position
  38  	Inst string
  39  }
  40  
  41  // Error encapsulates compile-time interpretation errors with an associated
  42  // import path. The errors may not have a precise location attached.
  43  type Error struct {
  44  	ImportPath string
  45  	Inst       string
  46  	Pos        token.Position
  47  	Err        error
  48  	Traceback  []ErrorLine
  49  }
  50  
  51  // Error returns the string of the first error in the list of errors.
  52  func (e *Error) Error() string {
  53  	return e.Pos.String() + ": " + e.Err.Error()
  54  }
  55  
  56  // errorAt returns an error value for the currently interpreted package at the
  57  // location of the instruction. The location information may not be complete as
  58  // it depends on debug information in the IR.
  59  func (r *runner) errorAt(inst instruction, err error) *Error {
  60  	pos := getPosition(inst.llvmInst)
  61  	return &Error{
  62  		ImportPath: r.pkgName,
  63  		Inst:       inst.llvmInst.String(),
  64  		Pos:        pos,
  65  		Err:        err,
  66  		Traceback:  []ErrorLine{{pos, inst.llvmInst.String()}},
  67  	}
  68  }
  69  
  70  // errorAt returns an error value at the location of the instruction.
  71  // The location information may not be complete as it depends on debug
  72  // information in the IR.
  73  func errorAt(inst llvm.Value, msg string) scanner.Error {
  74  	return scanner.Error{
  75  		Pos: getPosition(inst),
  76  		Msg: msg,
  77  	}
  78  }
  79  
  80  // getPosition returns the position information for the given instruction, as
  81  // far as it is available.
  82  func getPosition(inst llvm.Value) token.Position {
  83  	if inst.IsAInstruction().IsNil() {
  84  		return token.Position{}
  85  	}
  86  	loc := inst.InstructionDebugLoc()
  87  	if loc.IsNil() {
  88  		return token.Position{}
  89  	}
  90  	file := loc.LocationScope().ScopeFile()
  91  	return token.Position{
  92  		Filename: filepath.Join(file.FileDirectory(), file.FileFilename()),
  93  		Line:     int(loc.LocationLine()),
  94  		Column:   int(loc.LocationColumn()),
  95  	}
  96  }
  97