mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 08:54:47 +01:00
Add a new kind of Witness value that carries an expression (#1324)
This renames `Witness` to `ImplWitness` and adds a new form, `SymbolicWitness`, that holds an expression by which a witness can be computed. A common base class `Witness` is provided. We form the new kind of witness when evaluation of a witness expression fails because the witness is not in scope, as happens when evaluating a subexpression such as a type expression in isolation, and retry evaluation in the larger context when the interpreter performs type instantiation when running the code. This allows us to properly handle compile-time evaluation of constructs involving witness table lookups when the witness can be statically determined. The intent is that we will eventually also form symbolic witness table references when impl selection finds a non-final witness, in order to support specialization. Simplify `NominalClassValue`: it can now always store a witness map rather than either a witness map or a witness-or-witness-expression map.
This commit is contained in:
@@ -36,28 +36,35 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
|
||||
const std::string& f = field.name();
|
||||
|
||||
if (field.witness().has_value()) {
|
||||
Nonnull<const Witness*> witness = *field.witness();
|
||||
Nonnull<const Witness*> witness = cast<Witness>(*field.witness());
|
||||
switch (witness->kind()) {
|
||||
case Value::Kind::Witness: {
|
||||
case Value::Kind::ImplWitness: {
|
||||
auto* impl_witness = cast<ImplWitness>(witness);
|
||||
if (std::optional<Nonnull<const Declaration*>> mem_decl =
|
||||
FindMember(f, witness->declaration().members());
|
||||
FindMember(f, impl_witness->declaration().members());
|
||||
mem_decl.has_value()) {
|
||||
const auto& fun_decl = cast<FunctionDeclaration>(**mem_decl);
|
||||
if (fun_decl.is_method()) {
|
||||
return arena->New<BoundMethodValue>(
|
||||
&fun_decl, v, witness->type_args(), witness->witnesses());
|
||||
return arena->New<BoundMethodValue>(&fun_decl, v,
|
||||
impl_witness->type_args(),
|
||||
impl_witness->witnesses());
|
||||
} else {
|
||||
// Class function.
|
||||
auto fun = cast<FunctionValue>(*fun_decl.constant_value());
|
||||
auto* fun = cast<FunctionValue>(*fun_decl.constant_value());
|
||||
return arena->New<FunctionValue>(&fun->declaration(),
|
||||
witness->type_args(),
|
||||
witness->witnesses());
|
||||
impl_witness->type_args(),
|
||||
impl_witness->witnesses());
|
||||
}
|
||||
} else {
|
||||
return CompilationError(source_loc)
|
||||
<< "member " << f << " not in " << *witness;
|
||||
}
|
||||
}
|
||||
case Value::Kind::SymbolicWitness: {
|
||||
return RuntimeError(source_loc)
|
||||
<< "member lookup for " << f << " in symbolic " << *witness
|
||||
<< " not implemented yet";
|
||||
}
|
||||
default:
|
||||
CARBON_FATAL() << "expected Witness, not " << *witness;
|
||||
}
|
||||
@@ -337,13 +344,6 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
out << "class ";
|
||||
PrintNameWithBindings(out, &class_type.declaration(),
|
||||
class_type.type_args());
|
||||
if (!class_type.impls().empty()) {
|
||||
out << " impls ";
|
||||
llvm::ListSeparator sep;
|
||||
for (const auto& [impl_bind, impl] : class_type.impls()) {
|
||||
out << sep << *impl;
|
||||
}
|
||||
}
|
||||
if (!class_type.witnesses().empty()) {
|
||||
out << " witnesses ";
|
||||
llvm::ListSeparator sep;
|
||||
@@ -385,12 +385,17 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Witness: {
|
||||
const auto& witness = cast<Witness>(*this);
|
||||
case Value::Kind::ImplWitness: {
|
||||
const auto& witness = cast<ImplWitness>(*this);
|
||||
out << "witness " << *witness.declaration().impl_type() << " as "
|
||||
<< witness.declaration().interface();
|
||||
break;
|
||||
}
|
||||
case Value::Kind::SymbolicWitness: {
|
||||
const auto& witness = cast<SymbolicWitness>(*this);
|
||||
out << "witness " << witness.impl_expression();
|
||||
break;
|
||||
}
|
||||
case Value::Kind::ParameterizedEntityName:
|
||||
out << *GetName(cast<ParameterizedEntityName>(*this).declaration());
|
||||
break;
|
||||
@@ -660,7 +665,8 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2) -> bool {
|
||||
CARBON_FATAL() << "TypeEqual used to compare non-type values\n"
|
||||
<< *t1 << "\n"
|
||||
<< *t2;
|
||||
case Value::Kind::Witness:
|
||||
case Value::Kind::ImplWitness:
|
||||
case Value::Kind::SymbolicWitness:
|
||||
CARBON_FATAL() << "TypeEqual: unexpected Witness";
|
||||
break;
|
||||
case Value::Kind::AutoType:
|
||||
@@ -748,7 +754,8 @@ auto ValueEqual(Nonnull<const Value*> v1, Nonnull<const Value*> v2) -> bool {
|
||||
case Value::Kind::NominalClassType:
|
||||
case Value::Kind::InterfaceType:
|
||||
case Value::Kind::ConstraintType:
|
||||
case Value::Kind::Witness:
|
||||
case Value::Kind::ImplWitness:
|
||||
case Value::Kind::SymbolicWitness:
|
||||
case Value::Kind::ChoiceType:
|
||||
case Value::Kind::ContinuationType:
|
||||
case Value::Kind::VariableType:
|
||||
|
||||
Reference in New Issue
Block a user