1 module d.semantic.typepromotion; 2 3 import d.semantic.semantic; 4 5 import d.ir.symbol; 6 import d.ir.type; 7 8 import source.location; 9 10 import source.exception; 11 12 // Conflict with Interface in object.di 13 alias Interface = d.ir.symbol.Interface; 14 15 Type getPromotedType(SemanticPass pass, Location location, Type t1, Type t2) { 16 return TypePromoter(pass, location, t1).visit(t2); 17 } 18 19 // XXX: type promotion and finding common type are mixed up in there. 20 // This need to be splitted. 21 struct TypePromoter { 22 // XXX: Used only to get to super class, should probably go away. 23 private SemanticPass pass; 24 alias pass this; 25 26 private Location location; 27 28 Type t1; 29 30 this(SemanticPass pass, Location location, Type t1) { 31 this.pass = pass; 32 this.location = location; 33 34 this.t1 = t1.getCanonical(); 35 } 36 37 Type visit(Type t) { 38 return t.accept(this); 39 } 40 41 Type visit(BuiltinType bt) { 42 auto t = t1.getCanonicalAndPeelEnum(); 43 44 if (bt == BuiltinType.Null) { 45 if (t.kind == TypeKind.Pointer || t.kind == TypeKind.Class) { 46 return t; 47 } 48 49 if (t.kind == TypeKind.Function 50 && t.asFunctionType().contexts.length == 0) { 51 return t; 52 } 53 } 54 55 if (t.kind == TypeKind.Builtin) { 56 return Type.get(promoteBuiltin(bt, t.builtin)); 57 } 58 59 import std.conv; 60 return getError( 61 t, 62 location, 63 "Can't coerce " ~ bt.to!string() ~ " to " ~ t.toString(context), 64 ).type; 65 } 66 67 Type visitPointerOf(Type t) { 68 if (t1.kind == TypeKind.Builtin && t1.builtin == BuiltinType.Null) { 69 return t.getPointer(); 70 } 71 72 if (t1.kind != TypeKind.Pointer) { 73 assert(0, "Not Implemented."); 74 } 75 76 auto e = t1.element; 77 if (t.getCanonical().unqual() == e.getCanonical().unqual()) { 78 if (canConvert(e.qualifier, t.qualifier)) { 79 return t.getPointer(); 80 } 81 82 if (canConvert(t.qualifier, e.qualifier)) { 83 return e.getPointer(); 84 } 85 } 86 87 assert(0, "Not Implemented: use caster."); 88 } 89 90 Type visitSliceOf(Type t) { 91 assert(0, "Not Implemented."); 92 } 93 94 Type visitArrayOf(uint size, Type t) { 95 assert(0, "Not Implemented."); 96 } 97 98 Type visit(Struct s) { 99 if (t1.kind == TypeKind.Struct && t1.dstruct is s) { 100 return Type.get(s); 101 } 102 103 import source.exception; 104 throw new CompileException(location, "Incompatible struct type " 105 ~ s.name.toString(context) ~ " and " ~ t1.toString(context)); 106 } 107 108 Type visit(Class c) { 109 if (t1.kind == TypeKind.Builtin && t1.builtin == BuiltinType.Null) { 110 return Type.get(c); 111 } 112 113 if (t1.kind != TypeKind.Class) { 114 assert(0, "Not Implemented."); 115 } 116 117 auto r = t1.dclass; 118 119 // Find a common superclass. 120 auto lup = c; 121 do { 122 // Avoid allocation when possible. 123 if (r is lup) { 124 return t1; 125 } 126 127 auto rup = r.base; 128 while (rup !is rup.base) { 129 if (rup is lup) { 130 return Type.get(rup); 131 } 132 133 rup = rup.base; 134 } 135 136 lup = lup.base; 137 } while (lup !is lup.base); 138 139 // lup must be Object by now. 140 return Type.get(lup); 141 } 142 143 Type visit(Enum e) { 144 return visit(e.type); 145 } 146 147 Type visit(TypeAlias a) { 148 return visit(a.type); 149 } 150 151 Type visit(Interface i) { 152 assert(0, "Not Implemented."); 153 } 154 155 Type visit(Union u) { 156 assert(0, "Not Implemented."); 157 } 158 159 Type visit(Function f) { 160 assert(0, "Not Implemented."); 161 } 162 163 Type visit(Type[] seq) { 164 assert(0, "Not Implemented."); 165 } 166 167 Type visit(FunctionType f) { 168 assert(0, "Not Implemented."); 169 } 170 171 Type visit(Pattern p) { 172 assert(0, "Not implemented."); 173 } 174 175 import d.ir.error; 176 Type visit(CompileError e) { 177 return e.type; 178 } 179 } 180 181 private: 182 183 BuiltinType getBuiltinBase(BuiltinType t) { 184 if (t == BuiltinType.Bool) { 185 return BuiltinType.Int; 186 } 187 188 if (isChar(t)) { 189 return integralOfChar(t); 190 } 191 192 return t; 193 } 194 195 BuiltinType promoteBuiltin(BuiltinType t1, BuiltinType t2) { 196 t1 = getBuiltinBase(t1); 197 t2 = getBuiltinBase(t2); 198 199 if (isIntegral(t1) && isIntegral(t2)) { 200 import std.algorithm; 201 return max(t1, t2, BuiltinType.Int); 202 } 203 204 assert(0, "Not implemented."); 205 } 206 207 unittest { 208 with (BuiltinType) { 209 foreach (t1; [Bool, Char, Wchar, Byte, Ubyte, Short, Ushort, Int]) { 210 foreach (t2; [Bool, Char, Wchar, Byte, Ubyte, Short, Ushort, Int]) { 211 assert(promoteBuiltin(t1, t2) == Int); 212 } 213 } 214 215 foreach (t1; [Bool, Char, Wchar, Dchar, Byte, Ubyte, Short, Ushort, Int, 216 Uint]) { 217 foreach (t2; [Dchar, Uint]) { 218 assert(promoteBuiltin(t1, t2) == Uint); 219 assert(promoteBuiltin(t2, t1) == Uint); 220 } 221 } 222 223 foreach (t; [Bool, Char, Wchar, Dchar, Byte, Ubyte, Short, Ushort, Int, 224 Uint, Long]) { 225 assert(promoteBuiltin(t, Long) == Long); 226 assert(promoteBuiltin(Long, t) == Long); 227 } 228 229 foreach (t; [Bool, Char, Wchar, Dchar, Byte, Ubyte, Short, Ushort, Int, 230 Uint, Long, Ulong]) { 231 assert(promoteBuiltin(t, Ulong) == Ulong); 232 assert(promoteBuiltin(Ulong, t) == Ulong); 233 } 234 235 foreach (t; [Bool, Char, Wchar, Dchar, Byte, Ubyte, Short, Ushort, Int, 236 Uint, Long, Ulong, Cent]) { 237 assert(promoteBuiltin(t, Cent) == Cent); 238 assert(promoteBuiltin(Cent, t) == Cent); 239 } 240 241 foreach (t; [Bool, Char, Wchar, Dchar, Byte, Ubyte, Short, Ushort, Int, 242 Uint, Long, Ulong, Cent, Ucent]) { 243 assert(promoteBuiltin(t, Ucent) == Ucent); 244 assert(promoteBuiltin(Ucent, t) == Ucent); 245 } 246 } 247 }