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 }