mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Track witnesses wherever possible (#2263)
Change explorer's handling of witnesses to track them wherever possible. Associated constant support needs witnesses to be available much more pervasively. The main changes here are: - `Substitute` now takes a set of bindings covering both `Value`s for `GenericBinding`s and `Witness`es for `ImplBinding`s, and substitutes both. - Witnesses are now tracked within `ConstraintType`s. The `.Self` type has an `ImplBinding` that self-references from parts of the constraint to other parts of the constraint can use to access the witness for the constraint. - The constraint type for an `impl` and for a `GenericBinding` are now stored in pre-substituted form, with references to the actual constrained type rather than symbolic references to `.Self`. This results in minor changes in diagnostic text. Argument deduction still performs substitutions without remapping witnesses.
This commit is contained in:
@@ -26,16 +26,10 @@ void ImplScope::Add(Nonnull<const Value*> iface,
|
||||
llvm::ArrayRef<Nonnull<const ImplBinding*>> impl_bindings,
|
||||
Nonnull<const Witness*> witness,
|
||||
const TypeChecker& type_checker) {
|
||||
if (auto* orig_constraint = dyn_cast<ConstraintType>(iface)) {
|
||||
BindingMap map;
|
||||
map[orig_constraint->self_binding()] = type;
|
||||
const ConstraintType* constraint =
|
||||
cast<ConstraintType>(type_checker.Substitute(map, orig_constraint));
|
||||
for (size_t i = 0; i != constraint->impl_constraints().size(); ++i) {
|
||||
ConstraintType::ImplConstraint impl = constraint->impl_constraints()[i];
|
||||
Add(impl.interface, deduced, impl.type, impl_bindings,
|
||||
type_checker.MakeConstraintWitnessAccess(witness, i), type_checker);
|
||||
}
|
||||
if (auto* constraint = dyn_cast<ConstraintType>(iface)) {
|
||||
// The caller should have substituted `.Self` for `type` already.
|
||||
Add(constraint->impl_constraints(), deduced, impl_bindings, witness,
|
||||
type_checker);
|
||||
// A parameterized impl declaration doesn't contribute any equality
|
||||
// constraints to the scope. Instead, we'll resolve the equality
|
||||
// constraints by resolving a witness when needed.
|
||||
@@ -54,6 +48,18 @@ void ImplScope::Add(Nonnull<const Value*> iface,
|
||||
.witness = witness});
|
||||
}
|
||||
|
||||
void ImplScope::Add(llvm::ArrayRef<ConstraintType::ImplConstraint> impls,
|
||||
llvm::ArrayRef<Nonnull<const GenericBinding*>> deduced,
|
||||
llvm::ArrayRef<Nonnull<const ImplBinding*>> impl_bindings,
|
||||
Nonnull<const Witness*> witness,
|
||||
const TypeChecker& type_checker) {
|
||||
for (size_t i = 0; i != impls.size(); ++i) {
|
||||
ConstraintType::ImplConstraint impl = impls[i];
|
||||
Add(impl.interface, deduced, impl.type, impl_bindings,
|
||||
type_checker.MakeConstraintWitnessAccess(witness, i), type_checker);
|
||||
}
|
||||
}
|
||||
|
||||
void ImplScope::AddParent(Nonnull<const ImplScope*> parent) {
|
||||
parent_scopes_.push_back(parent);
|
||||
}
|
||||
@@ -68,15 +74,29 @@ auto ImplScope::Resolve(Nonnull<const Value*> constraint_type,
|
||||
}
|
||||
if (const auto* constraint = dyn_cast<ConstraintType>(constraint_type)) {
|
||||
std::vector<Nonnull<const Witness*>> witnesses;
|
||||
BindingMap map;
|
||||
map[constraint->self_binding()] = impl_type;
|
||||
for (auto impl : constraint->impl_constraints()) {
|
||||
// Note that later impl constraints can refer to earlier impl constraints
|
||||
// via impl bindings. For example, in
|
||||
// `C where .Self.AssocType is D`,
|
||||
// ... the `.Self.AssocType is D` constraint refers to the `.Self is C`
|
||||
// constraint when naming `AssocType`. So incrementally build up a
|
||||
// partial constraint witness as we go.
|
||||
std::optional<Nonnull<const Witness*>> witness;
|
||||
if (constraint->self_binding()->impl_binding()) {
|
||||
// Note, this is a partial impl binding covering only the impl
|
||||
// constraints that we've already seen. Earlier impl constraints should
|
||||
// not be able to refer to impl bindings for later impl constraints.
|
||||
witness = type_checker.MakeConstraintWitness(*constraint, witnesses,
|
||||
source_loc);
|
||||
}
|
||||
Bindings bindings;
|
||||
bindings.Add(constraint->self_binding(), impl_type, witness);
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const Witness*> result,
|
||||
ResolveInterface(
|
||||
cast<InterfaceType>(type_checker.Substitute(map, impl.interface)),
|
||||
type_checker.Substitute(map, impl.type), source_loc,
|
||||
type_checker));
|
||||
ResolveInterface(cast<InterfaceType>(type_checker.Substitute(
|
||||
bindings, impl.interface)),
|
||||
type_checker.Substitute(bindings, impl.type),
|
||||
source_loc, type_checker));
|
||||
witnesses.push_back(result);
|
||||
}
|
||||
// TODO: Check satisfaction of same-type constraints.
|
||||
|
||||
Reference in New Issue
Block a user