1 module d.semantic.defaultinitializer;
2 
3 import d.semantic.semantic;
4 
5 import d.ir.expression;
6 import d.ir.symbol;
7 import d.ir.type;
8 
9 import source.location;
10 
11 alias InitBuilder = DefaultInitializerVisitor!(true, false);
12 alias InstanceBuilder = DefaultInitializerVisitor!(false, false);
13 alias NewBuilder = DefaultInitializerVisitor!(false, true);
14 
15 // Conflict with Interface in object.di
16 alias Interface = d.ir.symbol.Interface;
17 
18 private:
19 struct DefaultInitializerVisitor(bool isCompileTime, bool isNew) {
20 	static assert(!isCompileTime || !isNew);
21 	
22 	static if(isCompileTime) {
23 		alias E = CompileTimeExpression;
24 	} else {
25 		alias E = Expression;
26 	}
27 	
28 	private SemanticPass pass;
29 	alias pass this;
30 	
31 	Location location;
32 	
33 	this(SemanticPass pass, Location location) {
34 		this.pass = pass;
35 		this.location = location;
36 	}
37 	
38 	E visit(Type t) {
39 		auto e = t.accept(this);
40 		e.type = e.type.qualify(t.qualifier);
41 		
42 		return e;
43 	}
44 	
45 	E visit(BuiltinType t) {
46 		final switch(t) with(BuiltinType) {
47 			case None :
48 			case Void :
49 				import d.ir.error;
50 				return new CompileError(
51 					location,
52 					Type.get(t).toString(context)
53 						~ " has no default initializer",
54 				).expression;
55 			
56 			case Bool :
57 				return new BooleanLiteral(location, false);
58 			
59 			case Char, Wchar, Dchar :
60 				return new CharacterLiteral(location, getCharInit(t), t);
61 			
62 			case Byte, Ubyte, Short, Ushort, Int, Uint :
63 			case Long, Ulong, Cent, Ucent :
64 				return new IntegerLiteral(location, 0, t);
65 			
66 			case Float, Double, Real :
67 				return new FloatLiteral(location, float.nan, t);
68 			
69 			case Null :
70 				return new NullLiteral(location);
71 		}
72 	}
73 	
74 	E visitPointerOf(Type t) {
75 		return new NullLiteral(location, t.getPointer());
76 	}
77 	
78 	E visitSliceOf(Type t) {
79 		auto sizet = pass.object.getSizeT().type.builtin;
80 		CompileTimeExpression[] init = [
81 			new NullLiteral(location, t.getPointer()),
82 			new IntegerLiteral(location, 0UL, sizet),
83 		];
84 		
85 		// XXX: Should cast to size_t, but buildImplicitCast
86 		// doesn't produce CompileTimeExpressions.
87 		return new CompileTimeTupleExpression(location, t.getSlice(), init);
88 	}
89 	
90 	E visitArrayOf(uint size, Type t) {
91 		E[] elements;
92 		elements.length = size;
93 		elements[] = visit(t);
94 		
95 		static if (isCompileTime) {
96 			return new CompileTimeTupleExpression(
97 				location,
98 				t.getArray(size),
99 				elements,
100 			);
101 		} else {
102 			return build!TupleExpression(location, t.getArray(size), elements);
103 		}
104 	}
105 	
106 	private Expression getTemporary(Expression value) {
107 		if (auto e = cast(ErrorExpression) value) {
108 			return e;
109 		}
110 		
111 		auto loc = value.location;
112 		
113 		import source.name;
114 		auto v = new Variable(loc, value.type, BuiltinName!"", value);
115 		v.step = Step.Processed;
116 		
117 		return new VariableExpression(loc, v);
118 	}
119 	
120 	E visit(Struct s) {
121 		scheduler.require(s, Step.Signed);
122 		
123 		import source.name;
124 		auto init = cast(Variable) s.resolve(location, BuiltinName!"init");
125 		assert(init, "init must be defined");
126 		
127 		scheduler.require(init);
128 		
129 		static if (isCompileTime) {
130 			auto v = cast(E) init.value;
131 			assert(v, "init must be a compile time expression");
132 			
133 			return v;
134 		} else {
135 			auto v = init.value;
136 			if (!s.hasContext) {
137 				return v;
138 			}
139 			
140 			v = getTemporary(v);
141 			
142 			import std.algorithm;
143 			auto f = cast(Field) s.members
144 				.filter!(m => m.name == BuiltinName!"__ctx")
145 				.front;
146 			
147 			assert(f, "Context must be a field");
148 			
149 			auto ft = f.type;
150 			assert(ft.kind == TypeKind.Pointer);
151 			
152 			auto ctx = new ContextExpression(location, ft.element.context);
153 			auto assign = new BinaryExpression(
154 				location,
155 				ft,
156 				BinaryOp.Assign,
157 				new FieldExpression(location, v, f),
158 				new UnaryExpression(location, ft, UnaryOp.AddressOf, ctx),
159 			);
160 			
161 			return new BinaryExpression(
162 				location,
163 				Type.get(s),
164 				BinaryOp.Comma,
165 				assign,
166 				v,
167 			);
168 		}
169 	}
170 	
171 	E visit(Class c) {
172 		static if(isNew) {
173 			scheduler.require(c);
174 			
175 			import std.algorithm, std.array;
176 			auto fields = c.members
177 				.map!(m => cast(Field) m)
178 				.filter!(f => !!f)
179 				.map!(function Expression(f) { return f.value; })
180 				.array();
181 			
182 			fields[0] = new VtblExpression(location, c);
183 			if (c.hasContext) {
184 				import std.algorithm;
185 				import source.name;
186 				auto ctxr = c.members
187 					.filter!(m => m.name == BuiltinName!"__ctx")
188 					.map!(m => cast(Field) m);
189 				
190 				foreach(f; ctxr) {
191 					assert(f, "Context must be a field");
192 					
193 					auto ft = f.type;
194 					assert(ft.kind == TypeKind.Pointer);
195 					
196 					fields[f.index] = new UnaryExpression(
197 						location,
198 						ft,
199 						UnaryOp.AddressOf,
200 						new ContextExpression(location, ft.element.context),
201 					);
202 				}
203 			}
204 			
205 			return build!TupleExpression(
206 				location,
207 				Type.get(fields.map!(f => f.type).array()),
208 				fields,
209 			);
210 		} else {
211 			return new NullLiteral(location, Type.get(c));
212 		}
213 	}
214 	
215 	E visit(Enum e) {
216 		assert(0, "Not implemented");
217 	}
218 	
219 	E visit(TypeAlias a) {
220 		// TODO: build implicit cast.
221 		return visit(a.type);
222 	}
223 	
224 	E visit(Interface i) {
225 		CompileTimeExpression[] init = [
226 			new NullLiteral(location, Type.get(pass.object.getObject())),
227 			new NullLiteral(location, Type.get(BuiltinType.Void).getPointer()),
228 		];
229 		
230 		return new CompileTimeTupleExpression(location, Type.get(i), init);
231 	}
232 	
233 	E visit(Union u) {
234 		// FIXME: Computing this properly would require layout
235 		// informations from the backend. Will do for now.
236 		return new VoidInitializer(location, Type.get(u));
237 	}
238 	
239 	E visit(Function f) {
240 		assert(0, "Not implemented");
241 	}
242 	
243 	E visit(Type[] seq) {
244 		import std.algorithm, std.array;
245 		auto elements = seq.map!(t => visit(t)).array();
246 		
247 		static if (isCompileTime) {
248 			return new CompileTimeTupleExpression(
249 				location,
250 				Type.get(seq),
251 				elements,
252 			);
253 		} else {
254 			return build!TupleExpression(location, Type.get(seq), elements);
255 		}
256 	}
257 	
258 	E visit(ParamType t) {
259 		assert(
260 			!t.isRef,
261 			"ref initializer is not implemented."
262 		);
263 		
264 		return visit(t.getType());
265 	}
266 	
267 	E visit(FunctionType f) {
268 		if (f.contexts.length == 0) {
269 			return new NullLiteral(location, f.getType());
270 		}
271 		
272 		assert(
273 			f.contexts.length == 1,
274 			"delegate initializer is not implemented."
275 		);
276 		
277 		auto elements = [
278 			visit(f.contexts[0]),
279 			visit(f.getFunction()),
280 		];
281 		
282 		static if (isCompileTime) {
283 			return new CompileTimeTupleExpression(
284 				location,
285 				f.getType(),
286 				elements,
287 			);
288 		} else {
289 			return build!TupleExpression(location, f.getType(), elements);
290 		}
291 	}
292 	
293 	E visit(Pattern p) {
294 		assert(0, "Patterns have no initializer.");
295 	}
296 	
297 	import d.ir.error;
298 	E visit(CompileError e) {
299 		return e.expression;
300 	}
301 }