Fix ternary operator type deduction

This commit is contained in:
wechman 2022-06-21 13:06:34 +02:00
parent a0ee14f7c2
commit 780bf4ccac
7 changed files with 127 additions and 17 deletions

View File

@ -1467,24 +1467,25 @@ bool TypeChecker::visit(Conditional const& _conditional)
_conditional.trueExpression().accept(*this);
_conditional.falseExpression().accept(*this);
Type const* trueType = type(_conditional.trueExpression())->mobileType();
Type const* falseType = type(_conditional.falseExpression())->mobileType();
Type const* trueType = type(_conditional.trueExpression());
Type const* falseType = type(_conditional.falseExpression());
Type const* trueMobileType = trueType->mobileType();
Type const* falseMobileType = falseType->mobileType();
Type const* commonType = nullptr;
if (!trueType)
m_errorReporter.typeError(9717_error, _conditional.trueExpression().location(), "Invalid mobile type in true expression.");
else
if (trueMobileType)
commonType = trueType;
if (!falseType)
m_errorReporter.typeError(3703_error, _conditional.falseExpression().location(), "Invalid mobile type in false expression.");
else
commonType = falseType;
m_errorReporter.typeError(9717_error, _conditional.trueExpression().location(), "Invalid mobile type in true expression.");
if (!trueType && !falseType)
if (falseMobileType)
commonType = falseType;
else
m_errorReporter.typeError(3703_error, _conditional.falseExpression().location(), "Invalid mobile type in false expression.");
if (!trueMobileType && !falseMobileType)
BOOST_THROW_EXCEPTION(FatalError());
else if (trueType && falseType)
else if (trueMobileType && falseMobileType)
{
commonType = Type::commonType(trueType, falseType);
@ -1494,14 +1495,14 @@ bool TypeChecker::visit(Conditional const& _conditional)
1080_error,
_conditional.location(),
"True expression's type " +
trueType->humanReadableName() +
trueMobileType->humanReadableName() +
" does not match false expression's type " +
falseType->humanReadableName() +
falseMobileType->humanReadableName() +
"."
);
// even we can't find a common type, we have to set a type here,
// otherwise the upper statement will not be able to check the type.
commonType = trueType;
commonType = trueMobileType;
}
}

View File

@ -0,0 +1,22 @@
contract C {
function f(int a, int b) public returns (int) {
return a < b ? -1 : 1;
}
function g(int a) public returns (int) {
int8 b = -1;
return a < 0 ? b : 1;
}
function h(int a) public returns (int) {
int8 b = -1;
return a < 0 ? 1 : b;
}
}
// ----
// f(int256,int256): 0, 2 -> -1
// f(int256,int256): 2, 0 -> 1
// g(int256): -2 -> -1
// g(int256): 2 -> 1
// h(int256): -2 -> 1
// h(int256): 2 -> -1

View File

@ -0,0 +1,14 @@
contract C {
function f(bool cond) public {
// OK
address a1 = cond ? 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF : payable(0x1234567890123456789012345678901234567890);
address a2 = cond ? address(0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF) : 0x1234567890123456789012345678901234567890;
// Errors
address payable a3 = cond ? 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF : payable(0x1234567890123456789012345678901234567890);
cond ? 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF : 1;
}
}
// ----
// TypeError 9574: (346-470): Type address is not implicitly convertible to expected type address payable.
// TypeError 1080: (481-534): True expression's type address does not match false expression's type uint8.

View File

@ -0,0 +1,16 @@
contract C {
function f(bool cond) public {
// OK
string memory v1 = cond ? "foo" : string("bar");
bytes1 v2 = cond ? bytes1("a") : "a";
bytes2 v3 = cond ? bytes2("a") : "a";
bytes2 v4 = cond ? bytes1("a") : bytes2("ab");
// Errors
cond ? bytes1("a") : string("b");
cond ? 1 : bytes1("a");
}
}
// ----
// TypeError 1080: (300-332): True expression's type bytes1 does not match false expression's type string memory.
// TypeError 1080: (343-365): True expression's type uint8 does not match false expression's type bytes1.

View File

@ -0,0 +1,27 @@
contract C {
function f(bool cond, bytes calldata cbytes) public view {
bytes1[2] memory marray;
bytes1[2] storage sarray;
uint8[2] memory uint8Array;
int16[2] memory int16Array;
bytes memory mbytes;
// OK
bytes1[2] memory marray1 = cond ? sarray : marray;
bytes1[2] memory marray2 = cond ? marray : sarray;
bytes memory mbytes1 = cond ? cbytes[1:2] : mbytes;
bytes memory mbytes2 = cond ? mbytes : cbytes[1:2];
// Errors
bytes1[2] storage sarray1 = cond ? sarray : marray;
bytes1[2] storage sarray2 = cond ? marray : sarray;
cond ? uint8Array : int16Array;
cond ? [1, 2] : [-1, -3];
}
}
// ----
// TypeError 9574: (517-567): Type bytes1[2] memory is not implicitly convertible to expected type bytes1[2] storage pointer.
// TypeError 9574: (577-627): Type bytes1[2] memory is not implicitly convertible to expected type bytes1[2] storage pointer.
// TypeError 1080: (638-668): True expression's type uint8[2] memory does not match false expression's type int16[2] memory.
// TypeError 1080: (678-702): True expression's type uint8[2] memory does not match false expression's type int8[2] memory.

View File

@ -0,0 +1,30 @@
contract C {
function f(bool cond) public {
// OK
int8 v1 = cond ? -1 : 1;
int16 v2 = cond ? -32768 : 1;
int16 v3 = cond ? -32768 : -1;
int16 v4 = cond ? -32768 : int8(1);
int16 v5 = cond ? int16(1) : 1;
uint16 v6 = cond ? uint16(1) : 1;
ufixed8x1 v7 = cond ? 1.0 : 1.1;
ufixed8x1 v8 = cond ? 0 : 1.1;
fixed8x1 v9 = cond ? -1.0 : -1.1;
fixed8x1 v10 = cond ? -1.1 : 1;
// Errors
cond ? 32768 : -1;
cond ? int16(-1) : uint8(1);
cond ? int8(-1) : uint8(1);
cond ? -1 : 1.1;
cond ? -1.0 : 1.1;
cond ? true : 1;
}
}
// ----
// TypeError 1080: (500-517): True expression's type uint16 does not match false expression's type int8.
// TypeError 1080: (528-555): True expression's type int16 does not match false expression's type uint8.
// TypeError 1080: (566-592): True expression's type int8 does not match false expression's type uint8.
// TypeError 1080: (603-618): True expression's type int8 does not match false expression's type ufixed8x1.
// TypeError 1080: (629-646): True expression's type int8 does not match false expression's type ufixed8x1.
// TypeError 1080: (657-672): True expression's type bool does not match false expression's type uint8.

View File

@ -9,8 +9,8 @@ contract C {
}
// ----
// TypeError 9717: (94-100): Invalid mobile type in true expression.
// TypeError 9553: (87-105): Invalid type for argument in function call. Invalid implicit conversion from uint8 to bytes1 requested.
// TypeError 9553: (87-105): Invalid type for argument in function call. Invalid implicit conversion from int_const 99 to bytes1 requested.
// TypeError 3703: (130-136): Invalid mobile type in false expression.
// TypeError 9553: (118-136): Invalid type for argument in function call. Invalid implicit conversion from uint8 to bytes1 requested.
// TypeError 9553: (118-136): Invalid type for argument in function call. Invalid implicit conversion from int_const 99 to bytes1 requested.
// TypeError 9717: (157-163): Invalid mobile type in true expression.
// TypeError 3703: (166-172): Invalid mobile type in false expression.