mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Build value representations for all kinds of witness (#2250)
Instead of forming a `SymbolicWitness` that contains an `Expression` when we can't directly resolve a witness to an `impl`, form different kinds of `Witness` values for the various situations: - A `BindingWitness` witnesses that a type implements a constraint by reference to an `ImplBinding`. - A `ConstraintWitness` witnesses that a type implements a constraint by reference to witnesses for each of the impl constraints within the constraint. - A `ConstraintImplWitness` witnesses that a type implements a constraint by reference to a larger constraint which contains that constraint as an impl constraint. Remove `SymbolicWitness` values and `InstantiateImpl` expressions, which are now unused. In order to remove the final usage of `SymbolicWitness`, I fixed a TODO to give `Self` the proper type within an interface declaration. I don't think this is an observable change. No functional change intended.
This commit is contained in:
@@ -103,10 +103,10 @@ class Interpreter {
|
||||
Nonnull<const Value*> destination_type,
|
||||
SourceLocation source_loc) -> ErrorOr<Nonnull<const Value*>>;
|
||||
|
||||
// Evaluate an expression immediately, recursively.
|
||||
// Evaluate an expression immediately, recursively, and return its result.
|
||||
//
|
||||
// TODO: Stop using this.
|
||||
auto EvalExpRecursively(Nonnull<const Expression*> exp)
|
||||
auto EvalRecursively(std::unique_ptr<Action> action)
|
||||
-> ErrorOr<Nonnull<const Value*>>;
|
||||
|
||||
// Evaluate an associated constant by evaluating its witness and looking
|
||||
@@ -133,6 +133,8 @@ class Interpreter {
|
||||
// __Fn (Point(T)) -> Point(U)
|
||||
// becomes
|
||||
// __Fn (Point(i32)) -> Point(bool)
|
||||
//
|
||||
// TODO: This should be an Action.
|
||||
auto InstantiateType(Nonnull<const Value*> type, SourceLocation source_loc)
|
||||
-> ErrorOr<Nonnull<const Value*>>;
|
||||
|
||||
@@ -142,6 +144,11 @@ class Interpreter {
|
||||
SourceLocation source_loc)
|
||||
-> ErrorOr<Nonnull<const Bindings*>>;
|
||||
|
||||
// Instantiate a witness by replacing all type variables and impl binding
|
||||
// references that occur within it by the current values of those variables.
|
||||
auto InstantiateWitness(Nonnull<const Witness*> witness)
|
||||
-> ErrorOr<Nonnull<const Witness*>>;
|
||||
|
||||
// Call the function `fun` with the given `arg` and the `witnesses`
|
||||
// for the function's impl bindings.
|
||||
auto CallFunction(const CallExpression& call, Nonnull<const Value*> fun,
|
||||
@@ -485,21 +492,20 @@ auto Interpreter::StepLvalue() -> ErrorOr<Success> {
|
||||
case ExpressionKind::WhereExpression:
|
||||
case ExpressionKind::DotSelfExpression:
|
||||
case ExpressionKind::ArrayTypeLiteral:
|
||||
case ExpressionKind::InstantiateImpl:
|
||||
CARBON_FATAL() << "Can't treat expression as lvalue: " << exp;
|
||||
case ExpressionKind::UnimplementedExpression:
|
||||
CARBON_FATAL() << "Unimplemented: " << exp;
|
||||
}
|
||||
}
|
||||
|
||||
auto Interpreter::EvalExpRecursively(Nonnull<const Expression*> exp)
|
||||
auto Interpreter::EvalRecursively(std::unique_ptr<Action> action)
|
||||
-> ErrorOr<Nonnull<const Value*>> {
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "--- recursive eval of " << *exp << "\n";
|
||||
**trace_stream_ << "--- recursive eval\n";
|
||||
PrintState(**trace_stream_);
|
||||
}
|
||||
todo_.BeginRecursiveAction();
|
||||
CARBON_RETURN_IF_ERROR(todo_.Spawn(std::make_unique<ExpressionAction>(exp)));
|
||||
CARBON_RETURN_IF_ERROR(todo_.Spawn(std::move(action)));
|
||||
// Note that the only `RecursiveAction` we can encounter here is our own --
|
||||
// if a nested action begins a recursive action, it will run until that
|
||||
// action is finished and popped off the queue before returning to us.
|
||||
@@ -522,11 +528,8 @@ auto Interpreter::EvalAssociatedConstant(
|
||||
Nonnull<const AssociatedConstant*> assoc, SourceLocation source_loc)
|
||||
-> ErrorOr<Nonnull<const Value*>> {
|
||||
// Find the witness.
|
||||
Nonnull<const Value*> witness = &assoc->witness();
|
||||
if (auto* sym = dyn_cast<SymbolicWitness>(witness)) {
|
||||
CARBON_ASSIGN_OR_RETURN(witness,
|
||||
EvalExpRecursively(&sym->impl_expression()));
|
||||
}
|
||||
CARBON_ASSIGN_OR_RETURN(Nonnull<const Witness*> witness,
|
||||
InstantiateWitness(&assoc->witness()));
|
||||
if (!isa<ImplWitness>(witness)) {
|
||||
CARBON_CHECK(phase() == Phase::CompileTime)
|
||||
<< "symbolic witnesses should only be formed at compile time";
|
||||
@@ -605,10 +608,8 @@ auto Interpreter::InstantiateBindings(Nonnull<const Bindings*> bindings,
|
||||
|
||||
ImplWitnessMap witnesses = bindings->witnesses();
|
||||
for (auto& [bind, witness] : witnesses) {
|
||||
if (auto* sym = dyn_cast<SymbolicWitness>(witness)) {
|
||||
CARBON_ASSIGN_OR_RETURN(witness,
|
||||
EvalExpRecursively(&sym->impl_expression()));
|
||||
}
|
||||
CARBON_ASSIGN_OR_RETURN(witness,
|
||||
InstantiateWitness(cast<Witness>(witness)));
|
||||
}
|
||||
|
||||
if (args == bindings->args() && witnesses == bindings->witnesses()) {
|
||||
@@ -617,6 +618,14 @@ auto Interpreter::InstantiateBindings(Nonnull<const Bindings*> bindings,
|
||||
return arena_->New<Bindings>(std::move(args), std::move(witnesses));
|
||||
}
|
||||
|
||||
auto Interpreter::InstantiateWitness(Nonnull<const Witness*> witness)
|
||||
-> ErrorOr<Nonnull<const Witness*>> {
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> value,
|
||||
EvalRecursively(std::make_unique<WitnessAction>(witness)));
|
||||
return cast<Witness>(value);
|
||||
}
|
||||
|
||||
auto Interpreter::Convert(Nonnull<const Value*> value,
|
||||
Nonnull<const Value*> destination_type,
|
||||
SourceLocation source_loc)
|
||||
@@ -643,7 +652,9 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
|
||||
case Value::Kind::InterfaceType:
|
||||
case Value::Kind::ConstraintType:
|
||||
case Value::Kind::ImplWitness:
|
||||
case Value::Kind::SymbolicWitness:
|
||||
case Value::Kind::BindingWitness:
|
||||
case Value::Kind::ConstraintWitness:
|
||||
case Value::Kind::ConstraintImplWitness:
|
||||
case Value::Kind::ParameterizedEntityName:
|
||||
case Value::Kind::ChoiceType:
|
||||
case Value::Kind::ContinuationType:
|
||||
@@ -895,35 +906,6 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
<< " (" << exp.source_loc() << ") --->\n";
|
||||
}
|
||||
switch (exp.kind()) {
|
||||
case ExpressionKind::InstantiateImpl: {
|
||||
const InstantiateImpl& inst_impl = cast<InstantiateImpl>(exp);
|
||||
if (act.pos() == 0) {
|
||||
return todo_.Spawn(
|
||||
std::make_unique<WitnessAction>(inst_impl.generic_impl()));
|
||||
}
|
||||
if (act.pos() == 1 && isa<SymbolicWitness>(act.results()[0])) {
|
||||
return todo_.FinishAction(arena_->New<SymbolicWitness>(&exp));
|
||||
}
|
||||
if (act.pos() - 1 < int(inst_impl.impls().size())) {
|
||||
auto iter = inst_impl.impls().begin();
|
||||
std::advance(iter, act.pos() - 1);
|
||||
return todo_.Spawn(
|
||||
std::make_unique<WitnessAction>(cast<Witness>(iter->second)));
|
||||
} else {
|
||||
Nonnull<const ImplWitness*> generic_witness =
|
||||
cast<ImplWitness>(act.results()[0]);
|
||||
ImplWitnessMap witnesses;
|
||||
int i = 0;
|
||||
for (const auto& [impl_bind, impl_exp] : inst_impl.impls()) {
|
||||
witnesses[impl_bind] = cast<Witness>(act.results()[i + 1]);
|
||||
++i;
|
||||
}
|
||||
return todo_.FinishAction(arena_->New<ImplWitness>(
|
||||
&generic_witness->declaration(),
|
||||
arena_->New<Bindings>(inst_impl.type_args(),
|
||||
std::move(witnesses))));
|
||||
}
|
||||
}
|
||||
case ExpressionKind::IndexExpression: {
|
||||
if (act.pos() == 0) {
|
||||
// { { e[i] :: C, E, F} :: S, H}
|
||||
@@ -931,9 +913,6 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
return todo_.Spawn(std::make_unique<ExpressionAction>(
|
||||
&cast<IndexExpression>(exp).object()));
|
||||
} else if (act.pos() == 1) {
|
||||
if (isa<SymbolicWitness>(act.results()[0])) {
|
||||
return todo_.FinishAction(arena_->New<SymbolicWitness>(&exp));
|
||||
}
|
||||
return todo_.Spawn(std::make_unique<ExpressionAction>(
|
||||
&cast<IndexExpression>(exp).offset()));
|
||||
} else {
|
||||
@@ -1447,12 +1426,58 @@ auto Interpreter::StepWitness() -> ErrorOr<Success> {
|
||||
<< ". --->\n";
|
||||
}
|
||||
switch (witness->kind()) {
|
||||
case Value::Kind::SymbolicWitness:
|
||||
return todo_.ReplaceWith(std::make_unique<ExpressionAction>(
|
||||
&cast<SymbolicWitness>(witness)->impl_expression()));
|
||||
case Value::Kind::BindingWitness: {
|
||||
const ImplBinding* binding = cast<BindingWitness>(witness)->binding();
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> value,
|
||||
todo_.ValueOfNode(binding, binding->type_var()->source_loc()));
|
||||
if (const auto* lvalue = dyn_cast<LValue>(value)) {
|
||||
// TODO: Why do we store values for impl bindings on the heap?
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
value,
|
||||
heap_.Read(lvalue->address(), binding->type_var()->source_loc()));
|
||||
}
|
||||
return todo_.FinishAction(value);
|
||||
}
|
||||
|
||||
case Value::Kind::ImplWitness:
|
||||
return todo_.FinishAction(witness);
|
||||
case Value::Kind::ConstraintWitness: {
|
||||
llvm::ArrayRef<Nonnull<const Witness*>> witnesses =
|
||||
cast<ConstraintWitness>(witness)->witnesses();
|
||||
if (act.pos() < static_cast<int>(witnesses.size())) {
|
||||
return todo_.Spawn(
|
||||
std::make_unique<WitnessAction>(witnesses[act.pos()]));
|
||||
}
|
||||
std::vector<Nonnull<const Witness*>> new_witnesses;
|
||||
new_witnesses.reserve(witnesses.size());
|
||||
for (auto* witness : act.results()) {
|
||||
new_witnesses.push_back(cast<Witness>(witness));
|
||||
}
|
||||
return todo_.FinishAction(
|
||||
arena_->New<ConstraintWitness>(std::move(new_witnesses)));
|
||||
}
|
||||
|
||||
case Value::Kind::ConstraintImplWitness: {
|
||||
auto* constraint_impl = cast<ConstraintImplWitness>(witness);
|
||||
if (act.pos() == 0) {
|
||||
return todo_.Spawn(std::make_unique<WitnessAction>(
|
||||
constraint_impl->constraint_witness()));
|
||||
}
|
||||
return todo_.FinishAction(ConstraintImplWitness::Make(
|
||||
arena_, cast<Witness>(act.results()[0]), constraint_impl->index()));
|
||||
}
|
||||
|
||||
case Value::Kind::ImplWitness: {
|
||||
auto* impl_witness = cast<ImplWitness>(witness);
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const Bindings*> new_bindings,
|
||||
InstantiateBindings(&impl_witness->bindings(),
|
||||
impl_witness->declaration().source_loc()));
|
||||
return todo_.FinishAction(
|
||||
new_bindings == &impl_witness->bindings()
|
||||
? impl_witness
|
||||
: arena_->New<ImplWitness>(&impl_witness->declaration(),
|
||||
new_bindings));
|
||||
}
|
||||
|
||||
default:
|
||||
CARBON_FATAL() << "unexpected kind of witness " << *witness;
|
||||
|
||||
Reference in New Issue
Block a user