UPDATE: Check out my new answer with 2 different solutions to the similar issue here: https://ethereum.stackexchange.com/a/142712/3032
Yep, but it is tricky:
pragma solidity ^0.5.0;
contract D {
function g(uint256 a) public view returns(uint256) {
return a*2;
}
}
contract A {
D public impl;
constructor() public {
impl = new D();
}
function() external {
require(msg.sender == address(this));
(bool success, bytes memory data) = address(impl).delegatecall(msg.data);
assembly {
switch success
// delegatecall returns 0 on error.
case 0 { revert(add(data, 32), returndatasize) }
default { return(add(data, 32), returndatasize) }
}
}
function f(uint256 a)
public
view
returns(uint256)
{
(bool success, bytes memory data) = address(this).staticcall(
abi.encodeWithSelector(
impl.g.selector,
10
)
);
assembly {
switch success
// delegatecall returns 0 on error.
case 0 { revert(add(data, 32), returndatasize) }
default { return(add(data, 32), returndatasize) }
}
}
}