Make built-in conversions visible to ImplicitAs. (#2525)

Add a blanket `ImplicitAs` implementation to perform the conversions that explorer can perform as built-in conversions. This allows those conversions to be detected by constraints and to be used as part of other user-defined conversions. For now, a single monolithic conversion is exposed. I intend to split this up into multiple smaller conversion kinds for each kind of conversion in a follow-up change.

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
Richard Smith
2023-01-18 17:36:55 -08:00
committed by GitHub
co-authored by Jon Ross-Perkins
parent 94872ef6da
commit 0d279b388a
13 changed files with 319 additions and 37 deletions
+20 -3
View File
@@ -128,13 +128,15 @@ auto ImplScope::Resolve(Nonnull<const Value*> constraint_type,
witnesses.push_back(result);
}
// Check that all equality and rewrite constraints are satisfied in this
// scope.
// Check that all intrinsic, equality, and rewrite constraints
// are satisfied in this scope.
llvm::ArrayRef<IntrinsicConstraint> intrinsics =
constraint->intrinsic_constraints();
llvm::ArrayRef<EqualityConstraint> equals =
constraint->equality_constraints();
llvm::ArrayRef<RewriteConstraint> rewrites =
constraint->rewrite_constraints();
if (!equals.empty() || !rewrites.empty()) {
if (!intrinsics.empty() || !equals.empty() || !rewrites.empty()) {
std::optional<Nonnull<const Witness*>> witness;
if (constraint->self_binding()->impl_binding()) {
witness = type_checker.MakeConstraintWitness(witnesses);
@@ -142,6 +144,21 @@ auto ImplScope::Resolve(Nonnull<const Value*> constraint_type,
Bindings local_bindings = bindings;
local_bindings.Add(constraint->self_binding(), impl_type, witness);
SingleStepEqualityContext equality_ctx(this);
for (const auto& intrinsic : intrinsics) {
IntrinsicConstraint converted = {
.type = type_checker.Substitute(local_bindings, intrinsic.type),
.kind = intrinsic.kind,
.arguments = {}};
converted.arguments.reserve(intrinsic.arguments.size());
for (Nonnull<const Value*> argument : intrinsic.arguments) {
converted.arguments.push_back(
type_checker.Substitute(local_bindings, argument));
}
if (!type_checker.IsIntrinsicConstraintSatisfied(converted, *this)) {
return ProgramError(source_loc)
<< "constraint requires that " << converted;
}
}
for (const auto& equal : equals) {
auto it = equal.values.begin();
Nonnull<const Value*> first =