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 errTimeout = errors.New("interp: timeout")
23 )
24 25 // This is one of the errors that can be returned from toLLVMValue when the
26 // passed type does not fit the data to serialize. It is recoverable by
27 // serializing without a type (using rawValue.rawLLVMValue).
28 var errInvalidPtrToIntSize = errors.New("interp: ptrtoint integer size does not equal pointer size")
29 30 func isRecoverableError(err error) bool {
31 return err == errIntegerAsPointer || err == errUnsupportedInst ||
32 err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated ||
33 err == errLoopUnrolled || err == errTimeout
34 }
35 36 // ErrorLine is one line in a traceback. The position may be missing.
37 type ErrorLine struct {
38 Pos token.Position
39 Inst string
40 }
41 42 // Error encapsulates compile-time interpretation errors with an associated
43 // import path. The errors may not have a precise location attached.
44 type Error struct {
45 ImportPath string
46 Inst string
47 Pos token.Position
48 Err error
49 Traceback []ErrorLine
50 }
51 52 // Error returns the string of the first error in the list of errors.
53 func (e *Error) Error() string {
54 return e.Pos.String() + ": " + e.Err.Error()
55 }
56 57 // errorAt returns an error value for the currently interpreted package at the
58 // location of the instruction. The location information may not be complete as
59 // it depends on debug information in the IR.
60 func (r *runner) errorAt(inst instruction, err error) *Error {
61 pos := getPosition(inst.llvmInst)
62 return &Error{
63 ImportPath: r.pkgName,
64 Inst: inst.llvmInst.String(),
65 Pos: pos,
66 Err: err,
67 Traceback: []ErrorLine{{pos, inst.llvmInst.String()}},
68 }
69 }
70 71 // errorAt returns an error value at the location of the instruction.
72 // The location information may not be complete as it depends on debug
73 // information in the IR.
74 func errorAt(inst llvm.Value, msg string) scanner.Error {
75 return scanner.Error{
76 Pos: getPosition(inst),
77 Msg: msg,
78 }
79 }
80 81 // getPosition returns the position information for the given instruction, as
82 // far as it is available.
83 func getPosition(inst llvm.Value) token.Position {
84 if inst.IsAInstruction().IsNil() {
85 return token.Position{}
86 }
87 loc := inst.InstructionDebugLoc()
88 if loc.IsNil() {
89 return token.Position{}
90 }
91 file := loc.LocationScope().ScopeFile()
92 return token.Position{
93 Filename: filepath.Join(file.FileDirectory(), file.FileFilename()),
94 Line: int(loc.LocationLine()),
95 Column: int(loc.LocationColumn()),
96 }
97 }
98