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 }