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 decls with tuple type expressions and initialization expressions #25951

Merged
merged 2 commits into from
Sep 30, 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
73 changes: 50 additions & 23 deletions frontend/lib/resolution/Resolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1265,6 +1265,42 @@ static const Type* computeVarArgTuple(Resolver& resolver,
return typePtr;
}


static bool adjustTupleTypeIntentForDecl(Context* context,
const NamedDecl* decl,
QualifiedType::Kind declaredKind,
QualifiedType::Kind& qtKind,
const Type*& typePtr) {
// adjust tuple declarations for value / referential tuples
if (typePtr != nullptr && decl->isVarArgFormal() == false) {
if (auto tupleType = typePtr->toTupleType()) {
if (declaredKind == QualifiedType::DEFAULT_INTENT) {
typePtr = tupleType->toReferentialTuple(context);
qtKind = QualifiedType::CONST_REF;
return true;
} else if (declaredKind == QualifiedType::CONST_INTENT) {
typePtr = tupleType->toReferentialTuple(context, /* makeConst */ true);
qtKind = QualifiedType::CONST_REF;
return true;
} else if (qtKind == QualifiedType::CONST_IN ||
qtKind == QualifiedType::CONST_REF) {
typePtr = tupleType->toValueTuple(context, /* makeConst */ true);
return true;
} else if (qtKind == QualifiedType::VAR ||
qtKind == QualifiedType::CONST_VAR ||
qtKind == QualifiedType::REF ||
qtKind == QualifiedType::IN ||
qtKind == QualifiedType::OUT ||
qtKind == QualifiedType::INOUT ||
qtKind == QualifiedType::TYPE) {
typePtr = tupleType->toValueTuple(context);
return true;
}
}
}
return false;
}

/* If the type is generic with defaults, computes the defaults of a type.
Returns the original type if instantiating with defaults isn't necessary. */
static QualifiedType computeTypeDefaults(Resolver& resolver,
Expand Down Expand Up @@ -1494,6 +1530,19 @@ void Resolver::resolveNamedDecl(const NamedDecl* decl, const Type* useType) {
computeFormalIntent(decl, qtKind, typeExprT.type(), typeExprT.param());
}
}

// The type expression is a type-tuple (e.g., (type int, type bool)),
// but the actual value may be value-tuple (e.g., (int, bool)), or a ref
// tuple, etc. Need to adjust the intents so that getTypeForDecl (which
// runs canPass) doesn't balk at the mismatch.
auto adjustedQtKind = qtKind;
auto adjustedTypePtr = typeExprT.type();
if (adjustTupleTypeIntentForDecl(context, decl, qtKind,
adjustedQtKind, adjustedTypePtr)) {
typeExprT = QualifiedType(typeExprT.kind(), adjustedTypePtr, typeExprT.param());
}

//
// Check that the initExpr type is compatible with declared type
// Check kinds are OK
// Handle any implicit conversions / instantiations
Expand Down Expand Up @@ -1525,29 +1574,7 @@ void Resolver::resolveNamedDecl(const NamedDecl* decl, const Type* useType) {
qtKind, typePtr);
}

// adjust tuple declarations for value / referential tuples
if (typePtr != nullptr && decl->isVarArgFormal() == false) {
if (auto tupleType = typePtr->toTupleType()) {
if (declaredKind == QualifiedType::DEFAULT_INTENT) {
typePtr = tupleType->toReferentialTuple(context);
qtKind = QualifiedType::CONST_REF;
} else if (declaredKind == QualifiedType::CONST_INTENT) {
typePtr = tupleType->toReferentialTuple(context, /* makeConst */ true);
qtKind = QualifiedType::CONST_REF;
} else if (qtKind == QualifiedType::CONST_IN ||
qtKind == QualifiedType::CONST_REF) {
typePtr = tupleType->toValueTuple(context, /* makeConst */ true);
} else if (qtKind == QualifiedType::VAR ||
qtKind == QualifiedType::CONST_VAR ||
qtKind == QualifiedType::REF ||
qtKind == QualifiedType::IN ||
qtKind == QualifiedType::OUT ||
qtKind == QualifiedType::INOUT ||
qtKind == QualifiedType::TYPE) {
typePtr = tupleType->toValueTuple(context);
}
}
}
adjustTupleTypeIntentForDecl(context, decl, declaredKind, qtKind, typePtr);

ResolvedExpression& result = byPostorder.byAst(decl);
result.setType(QualifiedType(qtKind, typePtr, paramPtr));
Expand Down
27 changes: 27 additions & 0 deletions frontend/test/resolution/testTuples.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,32 @@ static void test20() {
}
}

static void test21() {
// Ensure that (type int, type int) tuples in type expression are properly
// handled when they are specifying the type of var or const variable.

Context ctx;
Context* context = &ctx;
auto program = R"""(
var x: 2*int = (7,3);
const y: 2*int = (7,3);
var x2: 2*int;
const y2: 2*int;

param firstMatch = x.type == x2.type;
param secondMatch = y.type == y2.type;
)""";

auto vars = resolveTypesOfVariables(context, program,
{"x", "y", "x2", "y2", "firstMatch", "secondMatch"});
assert(vars["x"].type()->isTupleType());
assert(vars["y"].type()->isTupleType());
assert(vars["x2"].type()->isTupleType());
assert(vars["y2"].type()->isTupleType());
ensureParamBool(vars["firstMatch"], true);
ensureParamBool(vars["secondMatch"], true);
}


int main() {
test1();
Expand Down Expand Up @@ -998,5 +1024,6 @@ int main() {
testTupleGeneric();

test20();
test21();
return 0;
}