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 && t.asFunctionType().contexts.length == 0) { 50 return t; 51 } 52 } 53 54 if (t.kind == TypeKind.Builtin) { 55 return Type.get(promoteBuiltin(bt, t.builtin)); 56 } 57 58 import std.conv; 59 return getError( 60 t, 61 location, 62 "Can't coerce " ~ bt.to!string() ~ " to " ~ t.toString(context), 63 ).type; 64 } 65 66 Type visitPointerOf(Type t) { 67 if (t1.kind == TypeKind.Builtin && t1.builtin == BuiltinType.Null) { 68 return t.getPointer(); 69 } 70 71 if (t1.kind != TypeKind.Pointer) { 72 assert(0, "Not Implemented."); 73 } 74 75 auto e = t1.element; 76 if (t.getCanonical().unqual() == e.getCanonical().unqual()) { 77 if (canConvert(e.qualifier, t.qualifier)) { 78 return t.getPointer(); 79 } 80 81 if (canConvert(t.qualifier, e.qualifier)) { 82 return e.getPointer(); 83 } 84 } 85 86 assert(0, "Not Implemented: use caster."); 87 } 88 89 Type visitSliceOf(Type t) { 90 assert(0, "Not Implemented."); 91 } 92 93 Type visitArrayOf(uint size, Type t) { 94 assert(0, "Not Implemented."); 95 } 96 97 Type visit(Struct s) { 98 if (t1.kind == TypeKind.Struct && t1.dstruct is s) { 99 return Type.get(s); 100 } 101 102 import source.exception; 103 throw new CompileException(location, "Incompatible struct type " ~ s.name.toString(context) ~ " and " ~ t1.toString(context)); 104 } 105 106 Type visit(Class c) { 107 if (t1.kind == TypeKind.Builtin && t1.builtin == BuiltinType.Null) { 108 return Type.get(c); 109 } 110 111 if (t1.kind != TypeKind.Class) { 112 assert(0, "Not Implemented."); 113 } 114 115 auto r = t1.dclass; 116 117 // Find a common superclass. 118 auto lup = c; 119 do { 120 // Avoid allocation when possible. 121 if (r is lup) { 122 return t1; 123 } 124 125 auto rup = r.base; 126 while(rup !is rup.base) { 127 if(rup is lup) { 128 return Type.get(rup); 129 } 130 131 rup = rup.base; 132 } 133 134 lup = lup.base; 135 } while(lup !is lup.base); 136 137 // lup must be Object by now. 138 return Type.get(lup); 139 } 140 141 Type visit(Enum e) { 142 return visit(e.type); 143 } 144 145 Type visit(TypeAlias a) { 146 return visit(a.type); 147 } 148 149 Type visit(Interface i) { 150 assert(0, "Not Implemented."); 151 } 152 153 Type visit(Union u) { 154 assert(0, "Not Implemented."); 155 } 156 157 Type visit(Function f) { 158 assert(0, "Not Implemented."); 159 } 160 161 Type visit(Type[] seq) { 162 assert(0, "Not Implemented."); 163 } 164 165 Type visit(FunctionType f) { 166 assert(0, "Not Implemented."); 167 } 168 169 Type visit(Pattern p) { 170 assert(0, "Not implemented."); 171 } 172 173 import d.ir.error; 174 Type visit(CompileError e) { 175 return e.type; 176 } 177 } 178 179 private: 180 181 BuiltinType getBuiltinBase(BuiltinType t) { 182 if (t == BuiltinType.Bool) { 183 return BuiltinType.Int; 184 } 185 186 if (isChar(t)) { 187 return integralOfChar(t); 188 } 189 190 return t; 191 } 192 193 BuiltinType promoteBuiltin(BuiltinType t1, BuiltinType t2) { 194 t1 = getBuiltinBase(t1); 195 t2 = getBuiltinBase(t2); 196 197 if (isIntegral(t1) && isIntegral(t2)) { 198 import std.algorithm; 199 return max(t1, t2, BuiltinType.Int); 200 } 201 202 assert(0, "Not implemented."); 203 } 204 205 unittest { with(BuiltinType) { 206 foreach(t1; [Bool, Char, Wchar, Byte, Ubyte, Short, Ushort, Int]) { 207 foreach(t2; [Bool, Char, Wchar, Byte, Ubyte, Short, Ushort, Int]) { 208 assert(promoteBuiltin(t1, t2) == Int); 209 } 210 } 211 212 foreach(t1; [Bool, Char, Wchar, Dchar, Byte, Ubyte, Short, Ushort, Int, Uint]) { 213 foreach(t2; [Dchar, Uint]) { 214 assert(promoteBuiltin(t1, t2) == Uint); 215 assert(promoteBuiltin(t2, t1) == Uint); 216 } 217 } 218 219 foreach(t; [Bool, Char, Wchar, Dchar, Byte, Ubyte, Short, Ushort, Int, Uint, Long]) { 220 assert(promoteBuiltin(t, Long) == Long); 221 assert(promoteBuiltin(Long, t) == Long); 222 } 223 224 foreach(t; [Bool, Char, Wchar, Dchar, Byte, Ubyte, Short, Ushort, Int, Uint, Long, Ulong]) { 225 assert(promoteBuiltin(t, Ulong) == Ulong); 226 assert(promoteBuiltin(Ulong, t) == Ulong); 227 } 228 229 foreach(t; [Bool, Char, Wchar, Dchar, Byte, Ubyte, Short, Ushort, Int, Uint, Long, Ulong, Cent]) { 230 assert(promoteBuiltin(t, Cent) == Cent); 231 assert(promoteBuiltin(Cent, t) == Cent); 232 } 233 234 foreach(t; [Bool, Char, Wchar, Dchar, Byte, Ubyte, Short, Ushort, Int, Uint, Long, Ulong, Cent, Ucent]) { 235 assert(promoteBuiltin(t, Ucent) == Ucent); 236 assert(promoteBuiltin(Ucent, t) == Ucent); 237 } 238 }} 239