Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dyno: fix string -> bytes cast, disallow casts that are disallowed by production. #25164

Merged
merged 5 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ ERROR_CLASS(IncompatibleTypeAndInit, const uast::AstNode*, const uast::AstNode*,
ERROR_CLASS(InvalidClassCast, const uast::PrimCall*, types::QualifiedType)
ERROR_CLASS(InvalidIndexCall, const uast::FnCall*, types::QualifiedType)
ERROR_CLASS(InvalidNewTarget, const uast::New*, types::QualifiedType)
ERROR_CLASS(InvalidParamCast, const uast::AstNode*, types::QualifiedType, types::QualifiedType)
ERROR_CLASS(InvalidSuper, const uast::Identifier*, types::QualifiedType)
ERROR_CLASS(MemManagementNonClass, const uast::New*, const types::Type*)
ERROR_CLASS(MissingInclude, const uast::Include*, std::string)
Expand Down
2 changes: 2 additions & 0 deletions frontend/lib/immediates/cast_code.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,8 @@ switch (to->const_kind) {
default:
CHPL_ASSERT(false && "Illegal case in coerce_immediate switch statement"); break;
} break;
case CONST_KIND_STRING:
to->v_string = from->v_string; break;
} break;
case NUM_KIND_COMPLEX:
switch (to->num_index) {
Expand Down
12 changes: 12 additions & 0 deletions frontend/lib/resolution/resolution-error-classes-list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,18 @@ void ErrorInvalidNewTarget::write(ErrorWriterBase& wr) const {
wr.message("The 'new' expression can only be used with records or classes.");
}

void ErrorInvalidParamCast::write(ErrorWriterBase& wr) const {
auto astForErr = std::get<0>(info_);
auto& fromQt = std::get<1>(info_);
auto& toQt = std::get<2>(info_);

wr.heading(kind_, type_, astForErr,
"cannot cast param value "
"of type '", fromQt.type(), "' to type '", toQt.type(), "'.");
wr.message("In the following expression:");
wr.code(astForErr, { astForErr });
}

void ErrorInvalidSuper::write(ErrorWriterBase& wr) const {
auto superExpr = std::get<const uast::Identifier*>(info_);
auto qt = std::get<types::QualifiedType>(info_);
Expand Down
51 changes: 51 additions & 0 deletions frontend/lib/types/Param.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "chpl/types/BoolType.h"
#include "chpl/types/CStringType.h"
#include "chpl/types/ComplexType.h"
#include "chpl/types/ErroneousType.h"
#include "chpl/types/ImagType.h"
#include "chpl/types/IntType.h"
#include "chpl/types/RealType.h"
Expand Down Expand Up @@ -491,10 +492,60 @@ static QualifiedType enumParamFromNumericValue(Context* context,
return numericValue;
}

static bool paramCastAllowed(Context* context,
const QualifiedType& a,
const QualifiedType& b) {
auto at = a.type();
auto bt = b.type();

if (!at || !bt) return false;

auto cCharType = typeForSysCType(context, USTR("c_char")).type();

bool fromEnum = at->isEnumType();
bool fromString = at->isStringType() ||
at->isCStringType() ||
(at->isCPtrType() && at->toCPtrType()->eltType() == cCharType);
bool fromBytes = at->isBytesType();
bool fromIntUint = at->isIntType() ||
at->isUintType();
bool fromRealEtc = at->isRealType() ||
at->isImagType() ||
at->isComplexType();
bool fromIntEtc = fromIntUint || fromRealEtc || at->isBoolType();

bool toEnum = bt->isEnumType();
bool toString = (bt->isStringType() ||
bt->isCStringType() ||
(bt->isCPtrType() && bt->toCPtrType()->eltType() == cCharType));
bool toBytes = bt->isBytesType();
bool toIntUint = bt->isIntType() ||
bt->isUintType();
bool toRealEtc = bt->isRealType() ||
bt->isImagType() ||
bt->isComplexType();
bool toIntEtc = toIntUint || toRealEtc || bt->isBoolType();

// Allowed casts, copied from preFold.cpp in the production compiler:
return
((fromEnum || fromIntEtc) && toIntEtc) ||
(toEnum && (fromString || fromIntUint)) ||
(fromEnum && toString) ||
(fromString && toString) ||
(fromString && toBytes) ||
(fromBytes && bt->isCStringType()) ||
(fromIntEtc && (toString || toBytes));
}

static QualifiedType handleParamCast(Context* context,
const AstNode* astForErr,
QualifiedType a,
QualifiedType b) {
if (!paramCastAllowed(context, a, b)) {
CHPL_REPORT(context, InvalidParamCast, astForErr, a, b);
return QualifiedType(QualifiedType::UNKNOWN, ErroneousType::get(context));
}

QualifiedType typeToReturnOnError;
// convert Param to Immediate
auto aImmOpt = paramToImmediate(context, astForErr, a.param(), a.type(), typeToReturnOnError);
Expand Down
24 changes: 23 additions & 1 deletion frontend/test/resolution/testCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* limitations under the License.
*/

#include "chpl/types/RecordType.h"
#include "test-resolution.h"
#include "chpl/resolution/resolution-queries.h"

Expand All @@ -27,7 +28,7 @@ static void testHelper(Context* context, std::string program, const Type* expect
QualifiedType qt = resolveQualifiedTypeOfX(context, program);

assert(qt.hasTypePtr());
assert(qt.hasParamPtr());
if (expectedParam) assert(qt.hasParamPtr());
assert(qt.type() == expectedType);
assert(qt.param() == expectedParam);
}
Expand Down Expand Up @@ -433,6 +434,25 @@ static void test42() {
assert(xInit.type()->toRecordType()->name() == "myRec");
}

// param string to bytes (formely throwing assertions)
static void test43() {
printf("test43\n");
Context ctx;
Context* context = &ctx;
testHelper(context, "param x = \"hello\" : bytes;",
RecordType::getBytesType(context),
StringParam::get(context, UniqueString::get(context, "hello")));
}

// param bytes to string (formely throwing assertions)
static void test44() {
printf("test44\n");
Context ctx;
Context* context = &ctx;
testHelper(context, "param x = b\"hello\" : string;",
ErroneousType::get(context), nullptr);
}

int main() {
test1();
test2();
Expand Down Expand Up @@ -476,6 +496,8 @@ int main() {
test40();
test41();
test42();
test43();
test44();

return 0;
}
1 change: 0 additions & 1 deletion tools/chpl-language-server/test/type_inlays.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,6 @@ async def test_type_inlays_clickable_def(client: LanguageClient):


@pytest.mark.asyncio
@pytest.mark.xfail
async def test_type_inlays_hover_string(client: LanguageClient):
"""
Ensure that `: string` as a type inlay does not break
Expand Down
Loading