summaryrefslogtreecommitdiff
path: root/source/slang/slang-check-constraint.cpp
diff options
context:
space:
mode:
authorJulius Ikkala <julius.ikkala@gmail.com>2025-06-28 05:39:24 +0300
committerGitHub <noreply@github.com>2025-06-28 02:39:24 +0000
commit7349dc5cff49cf22c82eb912813e47f30cd7a757 (patch)
tree4d7b3e14f119e7bb48623e52c890b461fd3d9701 /source/slang/slang-check-constraint.cpp
parenta13dda4f214274a10d39f37c79622fc3e62da310 (diff)
Minimal optional constraints (#7422)
* Parse optional witness syntax * Allow failing optional constraint * Make `is` work with optional constraint * Allow using optional constraint in checked if statements * Fix tests * Make it work with structs * Fix MSVC build error * Disallow using `as` with optional constraints * Update test to match split is/as errors * Add tests * Fix uninitialized variables in tests * Add tests of incorrect uses & fix related bugs * Mention optional constraints in docs * format code * Fix type unification with NoneWitness * Fix formatting --------- Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com> Co-authored-by: Nathan V. Morrical <natemorrical@gmail.com>
Diffstat (limited to 'source/slang/slang-check-constraint.cpp')
-rw-r--r--source/slang/slang-check-constraint.cpp46
1 files changed, 35 insertions, 11 deletions
diff --git a/source/slang/slang-check-constraint.cpp b/source/slang/slang-check-constraint.cpp
index 3020554c8..7c55c440c 100644
--- a/source/slang/slang-check-constraint.cpp
+++ b/source/slang/slang-check-constraint.cpp
@@ -360,9 +360,12 @@ DeclRef<Decl> SemanticsVisitor::trySolveConstraintSystem(
for (auto constraintDeclRef :
getMembersOfType<GenericTypeConstraintDecl>(m_astBuilder, genericDeclRef))
{
+ ValUnificationContext unificationContext;
+ unificationContext.optionalConstraint =
+ constraintDeclRef.getDecl()->hasModifier<OptionalConstraintModifier>();
if (!TryUnifyTypes(
*system,
- ValUnificationContext(),
+ unificationContext,
getSub(m_astBuilder, constraintDeclRef),
getSup(m_astBuilder, constraintDeclRef)))
return DeclRef<Decl>();
@@ -487,8 +490,11 @@ DeclRef<Decl> SemanticsVisitor::trySolveConstraintSystem(
auto joinType = TryJoinTypes(system, type, cType);
if (!joinType)
{
- // failure!
- return DeclRef<Decl>();
+ if (c.isOptional)
+ joinType = type;
+ else
+ // failure!
+ return DeclRef<Decl>();
}
type = QualType(joinType, type.isLeftValue || cType.isLeftValue);
}
@@ -696,12 +702,22 @@ DeclRef<Decl> SemanticsVisitor::trySolveConstraintSystem(
subTypeWitness = nullptr;
}
- if (subTypeWitness)
+ bool witnessIsOptional = isWitnessUncheckedOptional(subTypeWitness);
+ bool constraintIsOptional = constraintDecl->hasModifier<OptionalConstraintModifier>();
+
+ if (subTypeWitness && (!witnessIsOptional || constraintIsOptional))
{
// We found a witness, so it will become an (implicit) argument.
args.add(subTypeWitness);
outBaseCost += subTypeWitness->getOverloadResolutionCost();
}
+ else if (!subTypeWitness && constraintIsOptional)
+ {
+ // Optional witness failed to resolve; not an error.
+ auto noneWitness = m_astBuilder->getOrCreate<NoneWitness>();
+ args.add(noneWitness);
+ outBaseCost += kConversionCost_FailedOptionalConstraint;
+ }
else
{
// No witness was found, so the inference will now fail.
@@ -851,13 +867,20 @@ bool SemanticsVisitor::TryUnifyVals(
// Two subtype witnesses can be unified if they exist (non-null) and
// prove that some pair of types are subtypes of types that can be unified.
//
- if (auto fstWit = as<SubtypeWitness>(fst))
- {
- if (auto sndWit = as<SubtypeWitness>(snd))
- {
- return TryUnifyTypes(constraints, unifyCtx, fstWit->getSup(), sndWit->getSup());
- }
- }
+ const auto fstSubtypeWitness = as<SubtypeWitness>(fst);
+ const auto sndSubtypeWitness = as<SubtypeWitness>(snd);
+ const auto fstNoneWitness = as<NoneWitness>(fst);
+ const auto sndNoneWitness = as<NoneWitness>(snd);
+ if (fstSubtypeWitness && sndSubtypeWitness)
+ return TryUnifyTypes(
+ constraints,
+ unifyCtx,
+ fstSubtypeWitness->getSup(),
+ sndSubtypeWitness->getSup());
+ else if (fstNoneWitness && sndNoneWitness)
+ return true;
+ else if ((fstNoneWitness && sndSubtypeWitness) || (fstSubtypeWitness && sndNoneWitness))
+ return false;
SLANG_UNIMPLEMENTED_X("value unification case");
@@ -946,6 +969,7 @@ bool SemanticsVisitor::TryUnifyTypeParam(
constraint.indexInPack = unificationContext.indexInTypePack;
constraint.val = type;
constraint.isUsedAsLValue = type.isLeftValue;
+ constraint.isOptional = unificationContext.optionalConstraint;
constraints.constraints.add(constraint);
return true;