1 module d.ir.error; 2 3 import source.context; 4 import source.location; 5 6 import d.ir.expression; 7 import d.ir.symbol; 8 import d.ir.type; 9 10 class CompileError { 11 Location location; 12 string message; 13 14 void[StorageSize!ErrorSymbol] symStorage; 15 void[StorageSize!ErrorExpression] exprStorage; 16 17 public: 18 this(Location location, string message) { 19 this.location = location; 20 this.message = message; 21 22 import std.conv; 23 symStorage.emplace!ErrorSymbol(this); 24 exprStorage.emplace!ErrorExpression(this); 25 } 26 27 string toString(const Context) const { 28 return message; 29 } 30 31 final: 32 @property 33 auto symbol() inout { 34 return cast(inout(ErrorSymbol)) symStorage.ptr; 35 } 36 37 @property 38 auto expression() inout { 39 return cast(inout(ErrorExpression)) exprStorage.ptr; 40 } 41 42 @property 43 auto type() { 44 import d.ir.type; 45 return Type.get(this); 46 } 47 } 48 49 CompileError getError(T)(T t, Location location, string msg) { 50 import d.ir.type; 51 static if (is(T : Expression)) { 52 if (auto e = cast(ErrorExpression) t) { 53 return e.error; 54 } 55 } else static if (is(T : Symbol)) { 56 if (auto e = cast(ErrorSymbol) t) { 57 return e.error; 58 } 59 } else static if (is(T : Type)) { 60 if (t.kind == TypeKind.Error) { 61 return t.error; 62 } 63 } else { 64 static assert(0, "Unepxected " ~ typeid(t).toString()); 65 } 66 67 return new CompileError(location, msg); 68 } 69 70 CompileError errorize(E)(E e) if (is(E : Expression)) { 71 static if (is(ErrorExpression : E)) { 72 if (auto ee = cast(ErrorExpression) e) { 73 return ee.error; 74 } 75 } 76 77 return null; 78 } 79 80 CompileError errorize(S)(S s) if (is(S : Symbol)) { 81 static if (is(ErrorSymbol : S)) { 82 if (auto es = cast(ErrorSymbol) s) { 83 return es.error; 84 } 85 } 86 87 return null; 88 } 89 90 CompileError errorize(Type t) { 91 if (t.kind == TypeKind.Error) { 92 return t.error; 93 } 94 95 return null; 96 } 97 98 enum isErrorizable(T) = is(typeof(errorize(T.init))); 99 100 CompileError errorize(T)(T[] ts) if (isErrorizable!T) { 101 foreach(t; ts) { 102 if (auto ce = errorize(t)) { 103 return ce; 104 } 105 } 106 107 return null; 108 } 109 110 CompileError errorize(T...)(T ts) if (T.length > 1) { 111 foreach(t; ts) { 112 // XXX: https://issues.dlang.org/show_bug.cgi?id=15360 113 static if (isErrorizable!(typeof(t))) { 114 if (auto ce = errorize(t)) { 115 return ce; 116 } 117 } 118 } 119 120 return null; 121 } 122 123 final: 124 /** 125 * An Error occured but an Expression is expected. 126 * Useful for speculative compilation. 127 */ 128 class ErrorExpression : CompileTimeExpression { 129 // private: 130 this(CompileError error) { 131 import d.ir.type; 132 super(error.location, Type.get(error)); 133 } 134 135 invariant() { 136 import d.ir.type; 137 assert(type.kind == TypeKind.Error); 138 } 139 140 public: 141 @property 142 auto error() { 143 return type.error; 144 } 145 146 override string toString(const Context c) const { 147 return type.toString(c); 148 } 149 } 150 151 /** 152 * An Error occured but a Symbol is expected. 153 * Useful for speculative compilation. 154 */ 155 class ErrorSymbol : Symbol { 156 CompileError error; 157 158 // private: 159 this(CompileError error) { 160 import source.name; 161 super(error.location, BuiltinName!""); 162 163 this.error = error; 164 step = Step.Processed; 165 } 166 167 public: 168 override string toString(const Context c) const { 169 return "__error__(" ~ error.toString(c) ~ ")"; 170 } 171 } 172 173 private: 174 template StorageSize(T) { 175 enum InstanceSize = __traits(classInstanceSize, T); 176 enum PtrSize = ((InstanceSize - 1) / size_t.sizeof) + 1; 177 enum StorageSize = PtrSize * size_t.sizeof; 178 }