mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 08:41:06 +01:00
Add type_utils file (#2926)
Prerequisite for #2909. Moves some type-related functions to the separate file.
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "explorer/interpreter/pattern_match.h"
|
||||
|
||||
#include "explorer/ast/value.h"
|
||||
#include "explorer/common/arena.h"
|
||||
#include "explorer/common/trace_stream.h"
|
||||
#include "explorer/interpreter/action.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
using llvm::cast;
|
||||
using llvm::dyn_cast;
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
static auto InitializePlaceholderValue(const ValueNodeView& value_node,
|
||||
ExpressionResult v,
|
||||
Nonnull<RuntimeScope*> bindings) {
|
||||
switch (value_node.expression_category()) {
|
||||
case ExpressionCategory::Reference:
|
||||
if (v.expression_category() == ExpressionCategory::Value ||
|
||||
v.expression_category() == ExpressionCategory::Reference) {
|
||||
// Build by copying from value or reference expression.
|
||||
bindings->Initialize(value_node, v.value());
|
||||
} else {
|
||||
// Location initialized by initializing expression, bind node to
|
||||
// address.
|
||||
CARBON_CHECK(v.address())
|
||||
<< "Missing location from initializing expression";
|
||||
bindings->Bind(value_node, *v.address());
|
||||
}
|
||||
break;
|
||||
case ExpressionCategory::Value:
|
||||
if (v.expression_category() == ExpressionCategory::Value) {
|
||||
// We assume values are strictly nested for now.
|
||||
bindings->BindValue(value_node, v.value());
|
||||
} else if (v.expression_category() == ExpressionCategory::Reference) {
|
||||
// Bind the reference expression value directly.
|
||||
CARBON_CHECK(v.address())
|
||||
<< "Missing location from reference expression";
|
||||
bindings->BindAndPin(value_node, *v.address());
|
||||
} else {
|
||||
// Location initialized by initializing expression, bind node to
|
||||
// address.
|
||||
CARBON_CHECK(v.address())
|
||||
<< "Missing location from initializing expression";
|
||||
bindings->Bind(value_node, *v.address());
|
||||
}
|
||||
break;
|
||||
case ExpressionCategory::Initializing:
|
||||
CARBON_FATAL() << "Cannot pattern match an initializing expression";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto PatternMatch(Nonnull<const Value*> p, ExpressionResult v,
|
||||
SourceLocation source_loc,
|
||||
std::optional<Nonnull<RuntimeScope*>> bindings,
|
||||
BindingMap& generic_args, Nonnull<TraceStream*> trace_stream,
|
||||
Nonnull<Arena*> arena) -> bool {
|
||||
if (trace_stream->is_enabled()) {
|
||||
*trace_stream << "match pattern " << *p << "\nfrom "
|
||||
<< ExpressionCategoryToString(v.expression_category())
|
||||
<< " expression with value " << *v.value() << "\n";
|
||||
}
|
||||
const auto make_expr_result =
|
||||
[](Nonnull<const Value*> v) -> ExpressionResult {
|
||||
if (const auto* expr_v = dyn_cast<ReferenceExpressionValue>(v)) {
|
||||
return ExpressionResult::Reference(expr_v->value(), expr_v->address());
|
||||
}
|
||||
return ExpressionResult::Value(v);
|
||||
};
|
||||
if (v.value()->kind() == Value::Kind::ReferenceExpressionValue) {
|
||||
return PatternMatch(p, make_expr_result(v.value()), source_loc, bindings,
|
||||
generic_args, trace_stream, arena);
|
||||
}
|
||||
switch (p->kind()) {
|
||||
case Value::Kind::BindingPlaceholderValue: {
|
||||
CARBON_CHECK(bindings.has_value());
|
||||
const auto& placeholder = cast<BindingPlaceholderValue>(*p);
|
||||
if (placeholder.value_node().has_value()) {
|
||||
InitializePlaceholderValue(*placeholder.value_node(), v, *bindings);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Value::Kind::AddrValue: {
|
||||
const auto& addr = cast<AddrValue>(*p);
|
||||
CARBON_CHECK(v.value()->kind() == Value::Kind::LocationValue);
|
||||
const auto& location = cast<LocationValue>(*v.value());
|
||||
return PatternMatch(
|
||||
&addr.pattern(),
|
||||
ExpressionResult::Value(arena->New<PointerValue>(location.address())),
|
||||
source_loc, bindings, generic_args, trace_stream, arena);
|
||||
}
|
||||
case Value::Kind::VariableType: {
|
||||
const auto& var_type = cast<VariableType>(*p);
|
||||
generic_args[&var_type.binding()] = v.value();
|
||||
return true;
|
||||
}
|
||||
case Value::Kind::TupleType:
|
||||
case Value::Kind::TupleValue:
|
||||
switch (v.value()->kind()) {
|
||||
case Value::Kind::TupleType:
|
||||
case Value::Kind::TupleValue: {
|
||||
const auto& p_tup = cast<TupleValueBase>(*p);
|
||||
const auto& v_tup = cast<TupleValueBase>(*v.value());
|
||||
CARBON_CHECK(p_tup.elements().size() == v_tup.elements().size());
|
||||
for (size_t i = 0; i < p_tup.elements().size(); ++i) {
|
||||
if (!PatternMatch(p_tup.elements()[i],
|
||||
make_expr_result(v_tup.elements()[i]), source_loc,
|
||||
bindings, generic_args, trace_stream, arena)) {
|
||||
return false;
|
||||
}
|
||||
} // for
|
||||
return true;
|
||||
}
|
||||
case Value::Kind::UninitializedValue: {
|
||||
const auto& p_tup = cast<TupleValueBase>(*p);
|
||||
for (const auto& ele : p_tup.elements()) {
|
||||
if (!PatternMatch(ele,
|
||||
ExpressionResult::Value(
|
||||
arena->New<UninitializedValue>(ele)),
|
||||
source_loc, bindings, generic_args, trace_stream,
|
||||
arena)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
CARBON_FATAL() << "expected a tuple value in pattern, not "
|
||||
<< *v.value();
|
||||
}
|
||||
case Value::Kind::StructValue: {
|
||||
const auto& p_struct = cast<StructValue>(*p);
|
||||
const auto& v_struct = cast<StructValue>(*v.value());
|
||||
CARBON_CHECK(p_struct.elements().size() == v_struct.elements().size());
|
||||
for (size_t i = 0; i < p_struct.elements().size(); ++i) {
|
||||
CARBON_CHECK(p_struct.elements()[i].name ==
|
||||
v_struct.elements()[i].name);
|
||||
if (!PatternMatch(p_struct.elements()[i].value,
|
||||
ExpressionResult::Value(v_struct.elements()[i].value),
|
||||
source_loc, bindings, generic_args, trace_stream,
|
||||
arena)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Value::Kind::AlternativeValue:
|
||||
switch (v.value()->kind()) {
|
||||
case Value::Kind::AlternativeValue: {
|
||||
const auto& p_alt = cast<AlternativeValue>(*p);
|
||||
const auto& v_alt = cast<AlternativeValue>(*v.value());
|
||||
if (&p_alt.alternative() != &v_alt.alternative()) {
|
||||
return false;
|
||||
}
|
||||
CARBON_CHECK(p_alt.argument().has_value() ==
|
||||
v_alt.argument().has_value());
|
||||
if (!p_alt.argument().has_value()) {
|
||||
return true;
|
||||
}
|
||||
return PatternMatch(
|
||||
*p_alt.argument(), ExpressionResult::Value(*v_alt.argument()),
|
||||
source_loc, bindings, generic_args, trace_stream, arena);
|
||||
}
|
||||
default:
|
||||
CARBON_FATAL() << "expected a choice alternative in pattern, not "
|
||||
<< *v.value();
|
||||
}
|
||||
case Value::Kind::UninitializedValue:
|
||||
CARBON_FATAL() << "uninitialized value is not allowed in pattern "
|
||||
<< *v.value();
|
||||
case Value::Kind::FunctionType:
|
||||
switch (v.value()->kind()) {
|
||||
case Value::Kind::FunctionType: {
|
||||
const auto& p_fn = cast<FunctionType>(*p);
|
||||
const auto& v_fn = cast<FunctionType>(*v.value());
|
||||
if (!PatternMatch(&p_fn.parameters(),
|
||||
ExpressionResult::Value(&v_fn.parameters()),
|
||||
source_loc, bindings, generic_args, trace_stream,
|
||||
arena)) {
|
||||
return false;
|
||||
}
|
||||
if (!PatternMatch(&p_fn.return_type(),
|
||||
ExpressionResult::Value(&v_fn.return_type()),
|
||||
source_loc, bindings, generic_args, trace_stream,
|
||||
arena)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case Value::Kind::AutoType:
|
||||
// `auto` matches any type, without binding any new names. We rely
|
||||
// on the typechecker to ensure that `v.value()` is a type.
|
||||
return true;
|
||||
case Value::Kind::StaticArrayType: {
|
||||
switch (v.value()->kind()) {
|
||||
case Value::Kind::TupleType:
|
||||
case Value::Kind::TupleValue: {
|
||||
return true;
|
||||
}
|
||||
case Value::Kind::StaticArrayType: {
|
||||
const auto& v_arr = cast<StaticArrayType>(*v.value());
|
||||
return v_arr.has_size();
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return ValueEqual(p, v.value(), std::nullopt);
|
||||
}
|
||||
}
|
||||
} // namespace Carbon
|
||||
Reference in New Issue
Block a user