1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
|
use core:lang;
use core:asm;
use lang:bs:macro;
on Compiler:
// De-reference a reference, if applicable.
Expr deref(Expr refExpr) {
if (refExpr.result.type.isCppRef) {
Deref:ref(refExpr);
} else {
refExpr;
}
}
// Assume we can cast whatever expression is available to the specified type. Throws an exception otherwise.
Expr expectCast(Expr of, Type to) {
ExprResult r = of.result;
if (r.nothing)
return of;
if (r.type.type is to)
return of;
if (of.suggestResult(to))
return of;
of = deref(of);
Value type = of.result.type;
if (type.type is to)
return of;
if (from = type.type) {
// Pointers are binary compatible, so this will work unless some of the expr:s are overly pedantic.
if (castablePtr(from, to))
return of;
}
if (inside = to.isCppRRef()) {
// Possible to make it an r-value reference?
if (of.temporary & Value(inside).mayReferTo(type.asRef(false)))
return MakeRRef(of);
} else if (inside = to.isCppRef()) {
// Regular reference?
if (!to.isCppConst() & of.temporary) {
} else if (Value(inside).mayReferTo(type.asRef(false))) {
return MakeRef(of);
}
}
throw SyntaxError(of.pos, "Expected type ${to.identifier()}, but got ${r.type}");
}
// Compute the cast penalty for a value.
Int castPenalty(Expr e, Type to) {
ExprResult r = e.result;
if (r.nothing)
return 0;
// No work to be done here!
Value type = r.type;
if (type.type is to)
return 0;
// Is 'e' able to produce the type directly?
if (e.suggestResult(to))
return 1;
// If 'e' is a reference, "dereference" that.
type = unwrapRef(type);
if (type.type is to)
return 0;
// Check if both 'type' and 'to' are pointers, but they differ in "const" or have compatible types.
if (from = type.type) {
if (castablePtr(from, to))
return 1;
}
if (inside = to.isCppRRef()) {
// If we're a temporary, we can be bound to an rvalue reference.
if (e.temporary & Value(inside).mayReferTo(type.asRef(false)))
return 0;
} else if (inside = to.isCppRef()) {
// Is it possible that "to" is a reference? Make this a bit more expensive, to make the
// rvalue ref take precedence if we have multiple options.
if (!to.isCppConst() & (e.temporary | e.constant))
return -1;
if (Value(inside).mayReferTo(type.asRef(false)))
return 1;
}
return -1;
}
// Check if 'from' and 'to' are compatible pointer types.
Bool castablePtr(Type from, Type to) {
unless (to as PtrType)
return false;
unless (from as PtrType)
return false;
if (!from.isPtr | !to.isPtr)
return false;
if (!to.params[0].mayReferTo(from.params[0]))
return false;
// Matching const, or can we add const?
if (from.isConst & !to.isConst)
return false;
true;
}
|