mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Switch Value to Ptr (#799)
Co-authored-by: Geoff Romer <gromer@google.com>
This commit is contained in:
committed by
GitHub
co-authored by
Geoff Romer
parent
31b4f1e7ac
commit
0601f5620b
@@ -41,10 +41,7 @@ void Action::Print(llvm::raw_ostream& out) const {
|
||||
out << "(";
|
||||
llvm::ListSeparator sep;
|
||||
for (auto& result : results) {
|
||||
out << sep;
|
||||
if (result) {
|
||||
out << *result;
|
||||
}
|
||||
out << sep << *result;
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
|
||||
@@ -38,11 +38,13 @@ class Action {
|
||||
auto Pos() const -> int { return pos; }
|
||||
|
||||
// Results from a subexpression.
|
||||
auto Results() const -> const std::vector<const Value*>& { return results; }
|
||||
auto Results() const -> const std::vector<Ptr<const Value>>& {
|
||||
return results;
|
||||
}
|
||||
|
||||
void SetPos(int pos) { this->pos = pos; }
|
||||
|
||||
void AddResult(const Value* result) { results.push_back(result); }
|
||||
void AddResult(Ptr<const Value> result) { results.push_back(result); }
|
||||
|
||||
void Clear() {
|
||||
pos = 0;
|
||||
@@ -65,7 +67,7 @@ class Action {
|
||||
|
||||
private:
|
||||
int pos = 0;
|
||||
std::vector<const Value*> results;
|
||||
std::vector<Ptr<const Value>> results;
|
||||
|
||||
const Kind tag;
|
||||
};
|
||||
|
||||
@@ -9,25 +9,23 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
auto Heap::AllocateValue(const Value* v) -> Address {
|
||||
auto Heap::AllocateValue(Ptr<const Value> v) -> Address {
|
||||
// Putting the following two side effects together in this function
|
||||
// ensures that we don't do anything else in between, which is really bad!
|
||||
// Consider whether to include a copy of the input v in this function
|
||||
// or to leave it up to the caller.
|
||||
CHECK(v != nullptr);
|
||||
Address a(values_.size());
|
||||
values_.push_back(v);
|
||||
alive_.push_back(true);
|
||||
return a;
|
||||
}
|
||||
|
||||
auto Heap::Read(const Address& a, SourceLocation loc) -> const Value* {
|
||||
auto Heap::Read(const Address& a, SourceLocation loc) -> Ptr<const Value> {
|
||||
this->CheckAlive(a, loc);
|
||||
return values_[a.index]->GetField(a.field_path, loc);
|
||||
}
|
||||
|
||||
void Heap::Write(const Address& a, const Value* v, SourceLocation loc) {
|
||||
CHECK(v != nullptr);
|
||||
void Heap::Write(const Address& a, Ptr<const Value> v, SourceLocation loc) {
|
||||
this->CheckAlive(a, loc);
|
||||
values_[a.index] = values_[a.index]->SetField(a.field_path, v, loc);
|
||||
}
|
||||
|
||||
@@ -25,14 +25,14 @@ class Heap {
|
||||
|
||||
// Returns the value at the given address in the heap after
|
||||
// checking that it is alive.
|
||||
auto Read(const Address& a, SourceLocation loc) -> const Value*;
|
||||
auto Read(const Address& a, SourceLocation loc) -> Ptr<const Value>;
|
||||
|
||||
// Writes the given value at the address in the heap after
|
||||
// checking that the address is alive.
|
||||
void Write(const Address& a, const Value* v, SourceLocation loc);
|
||||
void Write(const Address& a, Ptr<const Value> v, SourceLocation loc);
|
||||
|
||||
// Put the given value on the heap and mark it as alive.
|
||||
auto AllocateValue(const Value* v) -> Address;
|
||||
auto AllocateValue(Ptr<const Value> v) -> Address;
|
||||
|
||||
// Marks the object at this address, and all of its sub-objects, as dead.
|
||||
void Deallocate(const Address& address);
|
||||
@@ -49,7 +49,7 @@ class Heap {
|
||||
// Signal an error if the address is no longer alive.
|
||||
void CheckAlive(const Address& address, SourceLocation loc);
|
||||
|
||||
std::vector<const Value*> values_;
|
||||
std::vector<Ptr<const Value>> values_;
|
||||
std::vector<bool> alive_;
|
||||
};
|
||||
|
||||
|
||||
@@ -75,32 +75,32 @@ void Interpreter::PrintState(llvm::raw_ostream& out) {
|
||||
out << "\n}\n";
|
||||
}
|
||||
|
||||
static auto EvalPrim(Operator op, const std::vector<const Value*>& args,
|
||||
SourceLocation loc) -> const Value* {
|
||||
static auto EvalPrim(Operator op, const std::vector<Ptr<const Value>>& args,
|
||||
SourceLocation loc) -> Ptr<const Value> {
|
||||
switch (op) {
|
||||
case Operator::Neg:
|
||||
return global_arena->RawNew<IntValue>(-cast<IntValue>(*args[0]).Val());
|
||||
return global_arena->New<IntValue>(-cast<IntValue>(*args[0]).Val());
|
||||
case Operator::Add:
|
||||
return global_arena->RawNew<IntValue>(cast<IntValue>(*args[0]).Val() +
|
||||
cast<IntValue>(*args[1]).Val());
|
||||
return global_arena->New<IntValue>(cast<IntValue>(*args[0]).Val() +
|
||||
cast<IntValue>(*args[1]).Val());
|
||||
case Operator::Sub:
|
||||
return global_arena->RawNew<IntValue>(cast<IntValue>(*args[0]).Val() -
|
||||
cast<IntValue>(*args[1]).Val());
|
||||
return global_arena->New<IntValue>(cast<IntValue>(*args[0]).Val() -
|
||||
cast<IntValue>(*args[1]).Val());
|
||||
case Operator::Mul:
|
||||
return global_arena->RawNew<IntValue>(cast<IntValue>(*args[0]).Val() *
|
||||
cast<IntValue>(*args[1]).Val());
|
||||
return global_arena->New<IntValue>(cast<IntValue>(*args[0]).Val() *
|
||||
cast<IntValue>(*args[1]).Val());
|
||||
case Operator::Not:
|
||||
return global_arena->RawNew<BoolValue>(!cast<BoolValue>(*args[0]).Val());
|
||||
return global_arena->New<BoolValue>(!cast<BoolValue>(*args[0]).Val());
|
||||
case Operator::And:
|
||||
return global_arena->RawNew<BoolValue>(cast<BoolValue>(*args[0]).Val() &&
|
||||
cast<BoolValue>(*args[1]).Val());
|
||||
return global_arena->New<BoolValue>(cast<BoolValue>(*args[0]).Val() &&
|
||||
cast<BoolValue>(*args[1]).Val());
|
||||
case Operator::Or:
|
||||
return global_arena->RawNew<BoolValue>(cast<BoolValue>(*args[0]).Val() ||
|
||||
cast<BoolValue>(*args[1]).Val());
|
||||
return global_arena->New<BoolValue>(cast<BoolValue>(*args[0]).Val() ||
|
||||
cast<BoolValue>(*args[1]).Val());
|
||||
case Operator::Eq:
|
||||
return global_arena->RawNew<BoolValue>(ValueEqual(args[0], args[1], loc));
|
||||
return global_arena->New<BoolValue>(ValueEqual(args[0], args[1], loc));
|
||||
case Operator::Ptr:
|
||||
return global_arena->RawNew<PointerType>(args[0]);
|
||||
return global_arena->New<PointerType>(args[0]);
|
||||
case Operator::Deref:
|
||||
FATAL() << "dereference not implemented yet";
|
||||
}
|
||||
@@ -114,13 +114,13 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) {
|
||||
Env new_env = *env;
|
||||
// Bring the deduced parameters into scope.
|
||||
for (const auto& deduced : func_def.deduced_parameters) {
|
||||
Address a = heap.AllocateValue(
|
||||
global_arena->RawNew<VariableType>(deduced.name));
|
||||
Address a =
|
||||
heap.AllocateValue(global_arena->New<VariableType>(deduced.name));
|
||||
new_env.Set(deduced.name, a);
|
||||
}
|
||||
auto pt = InterpPattern(new_env, func_def.param_pattern);
|
||||
auto f =
|
||||
global_arena->RawNew<FunctionValue>(func_def.name, pt, func_def.body);
|
||||
global_arena->New<FunctionValue>(func_def.name, pt, func_def.body);
|
||||
Address a = heap.AllocateValue(f);
|
||||
env->Set(func_def.name, a);
|
||||
break;
|
||||
@@ -142,8 +142,8 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) {
|
||||
}
|
||||
}
|
||||
}
|
||||
auto st = global_arena->RawNew<ClassType>(
|
||||
class_def.name, std::move(fields), std::move(methods));
|
||||
auto st = global_arena->New<ClassType>(class_def.name, std::move(fields),
|
||||
std::move(methods));
|
||||
auto a = heap.AllocateValue(st);
|
||||
env->Set(class_def.name, a);
|
||||
break;
|
||||
@@ -156,8 +156,7 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) {
|
||||
auto t = InterpExp(Env(), signature);
|
||||
alts.push_back(make_pair(name, t));
|
||||
}
|
||||
auto ct =
|
||||
global_arena->RawNew<ChoiceType>(choice.Name(), std::move(alts));
|
||||
auto ct = global_arena->New<ChoiceType>(choice.Name(), std::move(alts));
|
||||
auto a = heap.AllocateValue(ct);
|
||||
env->Set(choice.Name(), a);
|
||||
break;
|
||||
@@ -196,7 +195,8 @@ void Interpreter::DeallocateLocals(Ptr<Frame> frame) {
|
||||
}
|
||||
}
|
||||
|
||||
static const Value* CreateTuple(Ptr<Action> act, Ptr<const Expression> exp) {
|
||||
static Ptr<const Value> CreateTuple(Ptr<Action> act,
|
||||
Ptr<const Expression> exp) {
|
||||
// { { (v1,...,vn) :: C, E, F} :: S, H}
|
||||
// -> { { `(v1,...,vn) :: C, E, F} :: S, H}
|
||||
const auto& tup_lit = cast<TupleLiteral>(*exp);
|
||||
@@ -207,10 +207,10 @@ static const Value* CreateTuple(Ptr<Action> act, Ptr<const Expression> exp) {
|
||||
{.name = tup_lit.Fields()[i].name, .value = act->Results()[i]});
|
||||
}
|
||||
|
||||
return global_arena->RawNew<TupleValue>(std::move(elements));
|
||||
return global_arena->New<TupleValue>(std::move(elements));
|
||||
}
|
||||
|
||||
auto Interpreter::PatternMatch(const Value* p, const Value* v,
|
||||
auto Interpreter::PatternMatch(Ptr<const Value> p, Ptr<const Value> v,
|
||||
SourceLocation loc) -> std::optional<Env> {
|
||||
switch (p->Tag()) {
|
||||
case Value::Kind::BindingPlaceholderValue: {
|
||||
@@ -305,7 +305,7 @@ auto Interpreter::PatternMatch(const Value* p, const Value* v,
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::PatternAssignment(const Value* pat, const Value* val,
|
||||
void Interpreter::PatternAssignment(Ptr<const Value> pat, Ptr<const Value> val,
|
||||
SourceLocation loc) {
|
||||
switch (pat->Tag()) {
|
||||
case Value::Kind::PointerValue:
|
||||
@@ -322,12 +322,13 @@ void Interpreter::PatternAssignment(const Value* pat, const Value* val,
|
||||
<< pat_tup << "\n value: " << val_tup;
|
||||
}
|
||||
for (const TupleElement& pattern_element : pat_tup.Elements()) {
|
||||
const Value* value_field = val_tup.FindField(pattern_element.name);
|
||||
if (value_field == nullptr) {
|
||||
std::optional<Ptr<const Value>> value_field =
|
||||
val_tup.FindField(pattern_element.name);
|
||||
if (!value_field) {
|
||||
FATAL_RUNTIME_ERROR(loc)
|
||||
<< "field " << pattern_element.name << "not in " << *val;
|
||||
}
|
||||
PatternAssignment(pattern_element.value, value_field, loc);
|
||||
PatternAssignment(pattern_element.value, *value_field, loc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -370,7 +371,7 @@ auto Interpreter::StepLvalue() -> Transition {
|
||||
// -> { {E(x) :: C, E, F} :: S, H}
|
||||
Address pointer =
|
||||
GetFromEnv(exp->SourceLoc(), cast<IdentifierExpression>(*exp).Name());
|
||||
const Value* v = global_arena->RawNew<PointerValue>(pointer);
|
||||
Ptr<const Value> v = global_arena->New<PointerValue>(pointer);
|
||||
return Done{v};
|
||||
}
|
||||
case Expression::Kind::FieldAccessExpression: {
|
||||
@@ -385,7 +386,7 @@ auto Interpreter::StepLvalue() -> Transition {
|
||||
Address aggregate = cast<PointerValue>(*act->Results()[0]).Val();
|
||||
Address field = aggregate.SubobjectAddress(
|
||||
cast<FieldAccessExpression>(*exp).Field());
|
||||
return Done{global_arena->RawNew<PointerValue>(field)};
|
||||
return Done{global_arena->New<PointerValue>(field)};
|
||||
}
|
||||
}
|
||||
case Expression::Kind::IndexExpression: {
|
||||
@@ -405,7 +406,7 @@ auto Interpreter::StepLvalue() -> Transition {
|
||||
std::string f =
|
||||
std::to_string(cast<IntValue>(*act->Results()[1]).Val());
|
||||
Address field = aggregate.SubobjectAddress(f);
|
||||
return Done{global_arena->RawNew<PointerValue>(field)};
|
||||
return Done{global_arena->New<PointerValue>(field)};
|
||||
}
|
||||
}
|
||||
case Expression::Kind::TupleLiteral: {
|
||||
@@ -464,19 +465,19 @@ auto Interpreter::StepExp() -> Transition {
|
||||
} else {
|
||||
// { { v :: [][i] :: C, E, F} :: S, H}
|
||||
// -> { { v_i :: C, E, F} : S, H}
|
||||
auto* tuple = dyn_cast<TupleValue>(act->Results()[0]);
|
||||
auto* tuple = dyn_cast<TupleValue>(act->Results()[0].Get());
|
||||
if (tuple == nullptr) {
|
||||
FATAL_RUNTIME_ERROR_NO_LINE()
|
||||
<< "expected a tuple in field access, not " << *tuple;
|
||||
<< "expected a tuple in field access, not " << *act->Results()[0];
|
||||
}
|
||||
std::string f =
|
||||
std::to_string(cast<IntValue>(*act->Results()[1]).Val());
|
||||
const Value* field = tuple->FindField(f);
|
||||
if (field == nullptr) {
|
||||
std::optional<Ptr<const Value>> field = tuple->FindField(f);
|
||||
if (!field) {
|
||||
FATAL_RUNTIME_ERROR_NO_LINE()
|
||||
<< "field " << f << " not in " << *tuple;
|
||||
}
|
||||
return Done{field};
|
||||
return Done{*field};
|
||||
}
|
||||
}
|
||||
case Expression::Kind::TupleLiteral: {
|
||||
@@ -526,12 +527,11 @@ auto Interpreter::StepExp() -> Transition {
|
||||
case Expression::Kind::IntLiteral:
|
||||
CHECK(act->Pos() == 0);
|
||||
// { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
|
||||
return Done{global_arena->RawNew<IntValue>(cast<IntLiteral>(*exp).Val())};
|
||||
return Done{global_arena->New<IntValue>(cast<IntLiteral>(*exp).Val())};
|
||||
case Expression::Kind::BoolLiteral:
|
||||
CHECK(act->Pos() == 0);
|
||||
// { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
|
||||
return Done{
|
||||
global_arena->RawNew<BoolValue>(cast<BoolLiteral>(*exp).Val())};
|
||||
return Done{global_arena->New<BoolValue>(cast<BoolLiteral>(*exp).Val())};
|
||||
case Expression::Kind::PrimitiveOperatorExpression: {
|
||||
const auto& op = cast<PrimitiveOperatorExpression>(*exp);
|
||||
if (act->Pos() != static_cast<int>(op.Arguments().size())) {
|
||||
@@ -561,20 +561,22 @@ auto Interpreter::StepExp() -> Transition {
|
||||
// -> { {C',E',F'} :: {C, E, F} :: S, H}
|
||||
switch (act->Results()[0]->Tag()) {
|
||||
case Value::Kind::ClassType: {
|
||||
const Value* arg = CopyVal(act->Results()[1], exp->SourceLoc());
|
||||
return Done{
|
||||
global_arena->RawNew<StructValue>(act->Results()[0], arg)};
|
||||
Ptr<const Value> arg = CopyVal(act->Results()[1], exp->SourceLoc());
|
||||
return Done{global_arena->New<StructValue>(act->Results()[0], arg)};
|
||||
}
|
||||
case Value::Kind::AlternativeConstructorValue: {
|
||||
const auto& alt =
|
||||
cast<AlternativeConstructorValue>(*act->Results()[0]);
|
||||
const Value* arg = CopyVal(act->Results()[1], exp->SourceLoc());
|
||||
return Done{global_arena->RawNew<AlternativeValue>(
|
||||
Ptr<const Value> arg = CopyVal(act->Results()[1], exp->SourceLoc());
|
||||
return Done{global_arena->New<AlternativeValue>(
|
||||
alt.AltName(), alt.ChoiceName(), arg)};
|
||||
}
|
||||
case Value::Kind::FunctionValue:
|
||||
return CallFunction{
|
||||
.function = cast<FunctionValue>(act->Results()[0]),
|
||||
// TODO: Think about a cleaner way to cast between Ptr types.
|
||||
// (multiple TODOs)
|
||||
.function = Ptr<const FunctionValue>(
|
||||
cast<FunctionValue>(act->Results()[0].Get())),
|
||||
.args = act->Results()[1],
|
||||
.loc = exp->SourceLoc()};
|
||||
default:
|
||||
@@ -590,24 +592,24 @@ auto Interpreter::StepExp() -> Transition {
|
||||
switch (cast<IntrinsicExpression>(*exp).Intrinsic()) {
|
||||
case IntrinsicExpression::IntrinsicKind::Print:
|
||||
Address pointer = GetFromEnv(exp->SourceLoc(), "format_str");
|
||||
const Value* pointee = heap.Read(pointer, exp->SourceLoc());
|
||||
Ptr<const Value> pointee = heap.Read(pointer, exp->SourceLoc());
|
||||
CHECK(pointee->Tag() == Value::Kind::StringValue);
|
||||
// TODO: This could eventually use something like llvm::formatv.
|
||||
llvm::outs() << cast<StringValue>(*pointee).Val();
|
||||
return Done{&TupleValue::Empty()};
|
||||
return Done{TupleValue::Empty()};
|
||||
}
|
||||
|
||||
case Expression::Kind::IntTypeLiteral: {
|
||||
CHECK(act->Pos() == 0);
|
||||
return Done{global_arena->RawNew<IntType>()};
|
||||
return Done{global_arena->New<IntType>()};
|
||||
}
|
||||
case Expression::Kind::BoolTypeLiteral: {
|
||||
CHECK(act->Pos() == 0);
|
||||
return Done{global_arena->RawNew<BoolType>()};
|
||||
return Done{global_arena->New<BoolType>()};
|
||||
}
|
||||
case Expression::Kind::TypeTypeLiteral: {
|
||||
CHECK(act->Pos() == 0);
|
||||
return Done{global_arena->RawNew<TypeType>()};
|
||||
return Done{global_arena->New<TypeType>()};
|
||||
}
|
||||
case Expression::Kind::FunctionTypeLiteral: {
|
||||
if (act->Pos() == 0) {
|
||||
@@ -621,23 +623,23 @@ auto Interpreter::StepExp() -> Transition {
|
||||
} else {
|
||||
// { { rt :: fn pt -> [] :: C, E, F} :: S, H}
|
||||
// -> { fn pt -> rt :: {C, E, F} :: S, H}
|
||||
return Done{global_arena->RawNew<FunctionType>(
|
||||
return Done{global_arena->New<FunctionType>(
|
||||
std::vector<GenericBinding>(), act->Results()[0],
|
||||
act->Results()[1])};
|
||||
}
|
||||
}
|
||||
case Expression::Kind::ContinuationTypeLiteral: {
|
||||
CHECK(act->Pos() == 0);
|
||||
return Done{global_arena->RawNew<ContinuationType>()};
|
||||
return Done{global_arena->New<ContinuationType>()};
|
||||
}
|
||||
case Expression::Kind::StringLiteral:
|
||||
CHECK(act->Pos() == 0);
|
||||
// { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
|
||||
return Done{
|
||||
global_arena->RawNew<StringValue>(cast<StringLiteral>(*exp).Val())};
|
||||
global_arena->New<StringValue>(cast<StringLiteral>(*exp).Val())};
|
||||
case Expression::Kind::StringTypeLiteral: {
|
||||
CHECK(act->Pos() == 0);
|
||||
return Done{global_arena->RawNew<StringType>()};
|
||||
return Done{global_arena->New<StringType>()};
|
||||
}
|
||||
} // switch (exp->Tag)
|
||||
}
|
||||
@@ -651,14 +653,14 @@ auto Interpreter::StepPattern() -> Transition {
|
||||
switch (pattern->Tag()) {
|
||||
case Pattern::Kind::AutoPattern: {
|
||||
CHECK(act->Pos() == 0);
|
||||
return Done{global_arena->RawNew<AutoType>()};
|
||||
return Done{global_arena->New<AutoType>()};
|
||||
}
|
||||
case Pattern::Kind::BindingPattern: {
|
||||
const auto& binding = cast<BindingPattern>(*pattern);
|
||||
if (act->Pos() == 0) {
|
||||
return Spawn{global_arena->New<PatternAction>(binding.Type())};
|
||||
} else {
|
||||
return Done{global_arena->RawNew<BindingPlaceholderValue>(
|
||||
return Done{global_arena->New<BindingPlaceholderValue>(
|
||||
binding.Name(), act->Results()[0])};
|
||||
}
|
||||
}
|
||||
@@ -666,7 +668,7 @@ auto Interpreter::StepPattern() -> Transition {
|
||||
const auto& tuple = cast<TuplePattern>(*pattern);
|
||||
if (act->Pos() == 0) {
|
||||
if (tuple.Fields().empty()) {
|
||||
return Done{&TupleValue::Empty()};
|
||||
return Done{TupleValue::Empty()};
|
||||
} else {
|
||||
Ptr<const Pattern> p1 = tuple.Fields()[0].pattern;
|
||||
return Spawn{(global_arena->New<PatternAction>(p1))};
|
||||
@@ -684,7 +686,7 @@ auto Interpreter::StepPattern() -> Transition {
|
||||
elements.push_back(
|
||||
{.name = tuple.Fields()[i].name, .value = act->Results()[i]});
|
||||
}
|
||||
return Done{global_arena->RawNew<TupleValue>(std::move(elements))};
|
||||
return Done{global_arena->New<TupleValue>(std::move(elements))};
|
||||
}
|
||||
}
|
||||
case Pattern::Kind::AlternativePattern: {
|
||||
@@ -697,7 +699,7 @@ auto Interpreter::StepPattern() -> Transition {
|
||||
} else {
|
||||
CHECK(act->Pos() == 2);
|
||||
const auto& choice_type = cast<ChoiceType>(*act->Results()[0]);
|
||||
return Done{global_arena->RawNew<AlternativeValue>(
|
||||
return Done{global_arena->New<AlternativeValue>(
|
||||
alternative.AlternativeName(), choice_type.Name(),
|
||||
act->Results()[1])};
|
||||
}
|
||||
@@ -867,8 +869,8 @@ auto Interpreter::StepStmt() -> Transition {
|
||||
} else {
|
||||
// { { v :: (x = []) :: C, E, F} :: S, H}
|
||||
// -> { { C, E(x := a), F} :: S, H(a := copy(v))}
|
||||
const Value* v = act->Results()[0];
|
||||
const Value* p = act->Results()[1];
|
||||
Ptr<const Value> v = act->Results()[0];
|
||||
Ptr<const Value> p = act->Results()[1];
|
||||
|
||||
std::optional<Env> matches = PatternMatch(p, v, stmt->SourceLoc());
|
||||
CHECK(matches)
|
||||
@@ -937,7 +939,8 @@ auto Interpreter::StepStmt() -> Transition {
|
||||
} else {
|
||||
// { {v :: return [] :: C, E, F} :: {C', E', F'} :: S, H}
|
||||
// -> { {v :: C', E', F'} :: S, H}
|
||||
const Value* ret_val = CopyVal(act->Results()[0], stmt->SourceLoc());
|
||||
Ptr<const Value> ret_val =
|
||||
CopyVal(act->Results()[0], stmt->SourceLoc());
|
||||
return UnwindFunctionCall{ret_val};
|
||||
}
|
||||
case Statement::Kind::Sequence: {
|
||||
@@ -968,7 +971,7 @@ auto Interpreter::StepStmt() -> Transition {
|
||||
auto continuation_frame =
|
||||
global_arena->New<Frame>("__continuation", scopes, todo);
|
||||
Address continuation_address =
|
||||
heap.AllocateValue(global_arena->RawNew<ContinuationValue>(
|
||||
heap.AllocateValue(global_arena->New<ContinuationValue>(
|
||||
std::vector<Ptr<Frame>>({continuation_frame})));
|
||||
// Store the continuation's address in the frame.
|
||||
continuation_frame->continuation = continuation_address;
|
||||
@@ -1013,7 +1016,7 @@ auto Interpreter::StepStmt() -> Transition {
|
||||
} while (paused.back()->continuation == std::nullopt);
|
||||
// Update the continuation with the paused stack.
|
||||
heap.Write(*paused.back()->continuation,
|
||||
global_arena->RawNew<ContinuationValue>(paused),
|
||||
global_arena->New<ContinuationValue>(paused),
|
||||
stmt->SourceLoc());
|
||||
return ManualTransition{};
|
||||
}
|
||||
@@ -1027,15 +1030,15 @@ class Interpreter::DoTransition {
|
||||
void operator()(const Done& done) {
|
||||
Ptr<Frame> frame = interpreter->stack.Top();
|
||||
if (frame->todo.Top()->Tag() != Action::Kind::StatementAction) {
|
||||
CHECK(done.result != nullptr);
|
||||
CHECK(done.result);
|
||||
frame->todo.Pop();
|
||||
if (frame->todo.IsEmpty()) {
|
||||
interpreter->program_value = done.result;
|
||||
interpreter->program_value = *done.result;
|
||||
} else {
|
||||
frame->todo.Top()->AddResult(done.result);
|
||||
frame->todo.Top()->AddResult(*done.result);
|
||||
}
|
||||
} else {
|
||||
CHECK(done.result == nullptr);
|
||||
CHECK(!done.result);
|
||||
frame->todo.Pop();
|
||||
}
|
||||
}
|
||||
@@ -1168,7 +1171,7 @@ auto Interpreter::InterpProgram(const std::list<Ptr<const Declaration>>& fs)
|
||||
}
|
||||
|
||||
auto Interpreter::InterpExp(Env values, Ptr<const Expression> e)
|
||||
-> const Value* {
|
||||
-> Ptr<const Value> {
|
||||
CHECK(program_value == std::nullopt);
|
||||
auto program_value_guard =
|
||||
llvm::make_scope_exit([&] { program_value = std::nullopt; });
|
||||
@@ -1185,7 +1188,7 @@ auto Interpreter::InterpExp(Env values, Ptr<const Expression> e)
|
||||
}
|
||||
|
||||
auto Interpreter::InterpPattern(Env values, Ptr<const Pattern> p)
|
||||
-> const Value* {
|
||||
-> Ptr<const Value> {
|
||||
CHECK(program_value == std::nullopt);
|
||||
auto program_value_guard =
|
||||
llvm::make_scope_exit([&] { program_value = std::nullopt; });
|
||||
|
||||
@@ -29,18 +29,18 @@ class Interpreter {
|
||||
auto InterpProgram(const std::list<Ptr<const Declaration>>& fs) -> int;
|
||||
|
||||
// Interpret an expression at compile-time.
|
||||
auto InterpExp(Env values, Ptr<const Expression> e) -> const Value*;
|
||||
auto InterpExp(Env values, Ptr<const Expression> e) -> Ptr<const Value>;
|
||||
|
||||
// Interpret a pattern at compile-time.
|
||||
auto InterpPattern(Env values, Ptr<const Pattern> p) -> const Value*;
|
||||
auto InterpPattern(Env values, Ptr<const Pattern> p) -> Ptr<const Value>;
|
||||
|
||||
// Attempts to match `v` against the pattern `p`. If matching succeeds,
|
||||
// returns the bindings of pattern variables to their matched values.
|
||||
auto PatternMatch(const Value* p, const Value* v, SourceLocation loc)
|
||||
auto PatternMatch(Ptr<const Value> p, Ptr<const Value> v, SourceLocation loc)
|
||||
-> std::optional<Env>;
|
||||
|
||||
// Support TypeChecker allocating values on the heap.
|
||||
auto AllocateValue(const Value* v) -> Address {
|
||||
auto AllocateValue(Ptr<const Value> v) -> Address {
|
||||
return heap.AllocateValue(v);
|
||||
}
|
||||
|
||||
@@ -58,9 +58,9 @@ class Interpreter {
|
||||
|
||||
// Transition type which indicates that the current Action is now done.
|
||||
struct Done {
|
||||
// The value computed by the Action. Should always be null for Statement
|
||||
// The value computed by the Action. Should always be nullopt for Statement
|
||||
// Actions, and never null for any other kind of Action.
|
||||
const Value* result = nullptr;
|
||||
std::optional<Ptr<const Value>> result;
|
||||
};
|
||||
|
||||
// Transition type which spawns a new Action on the todo stack above the
|
||||
@@ -88,15 +88,15 @@ class Interpreter {
|
||||
// Transition type which unwinds the entire current stack frame, and returns
|
||||
// a specified value to the caller.
|
||||
struct UnwindFunctionCall {
|
||||
const Value* return_val;
|
||||
Ptr<const Value> return_val;
|
||||
};
|
||||
|
||||
// Transition type which removes the current action from the top of the todo
|
||||
// stack, then creates a new stack frame which calls the specified function
|
||||
// with the specified arguments.
|
||||
struct CallFunction {
|
||||
const FunctionValue* function;
|
||||
const Value* args;
|
||||
Ptr<const FunctionValue> function;
|
||||
Ptr<const Value> args;
|
||||
SourceLocation loc;
|
||||
};
|
||||
|
||||
@@ -131,7 +131,7 @@ class Interpreter {
|
||||
void DeallocateScope(Ptr<Scope> scope);
|
||||
void DeallocateLocals(Ptr<Frame> frame);
|
||||
|
||||
void PatternAssignment(const Value* pat, const Value* val,
|
||||
void PatternAssignment(Ptr<const Value> pat, Ptr<const Value> val,
|
||||
SourceLocation loc);
|
||||
|
||||
void PrintState(llvm::raw_ostream& out);
|
||||
@@ -141,7 +141,7 @@ class Interpreter {
|
||||
|
||||
Stack<Ptr<Frame>> stack;
|
||||
Heap heap;
|
||||
std::optional<const Value*> program_value;
|
||||
std::optional<Ptr<const Value>> program_value;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -33,7 +33,7 @@ void PrintTypeEnv(TypeEnv types, llvm::raw_ostream& out) {
|
||||
}
|
||||
|
||||
static void ExpectType(SourceLocation loc, const std::string& context,
|
||||
const Value* expected, const Value* actual) {
|
||||
Ptr<const Value> expected, Ptr<const Value> actual) {
|
||||
if (!TypeEqual(expected, actual)) {
|
||||
FATAL_COMPILATION_ERROR(loc) << "type error in " << context << "\n"
|
||||
<< "expected: " << *expected << "\n"
|
||||
@@ -42,7 +42,7 @@ static void ExpectType(SourceLocation loc, const std::string& context,
|
||||
}
|
||||
|
||||
static void ExpectPointerType(SourceLocation loc, const std::string& context,
|
||||
const Value* actual) {
|
||||
Ptr<const Value> actual) {
|
||||
if (actual->Tag() != Value::Kind::PointerType) {
|
||||
FATAL_COMPILATION_ERROR(loc) << "type error in " << context << "\n"
|
||||
<< "expected a pointer type\n"
|
||||
@@ -55,7 +55,7 @@ static SourceLocation ReifyFakeSourceLoc() {
|
||||
}
|
||||
|
||||
// Reify type to type expression.
|
||||
static auto ReifyType(const Value* t, SourceLocation loc)
|
||||
static auto ReifyType(Ptr<const Value> t, SourceLocation loc)
|
||||
-> Ptr<const Expression> {
|
||||
switch (t->Tag()) {
|
||||
case Value::Kind::IntType:
|
||||
@@ -119,11 +119,12 @@ static auto ReifyType(const Value* t, SourceLocation loc)
|
||||
// The `deduced` parameter is an accumulator, that is, it holds the
|
||||
// results so-far.
|
||||
static auto ArgumentDeduction(SourceLocation loc, TypeEnv deduced,
|
||||
const Value* param, const Value* arg) -> TypeEnv {
|
||||
Ptr<const Value> param, Ptr<const Value> arg)
|
||||
-> TypeEnv {
|
||||
switch (param->Tag()) {
|
||||
case Value::Kind::VariableType: {
|
||||
const auto& var_type = cast<VariableType>(*param);
|
||||
std::optional<const Value*> d = deduced.Get(var_type.Name());
|
||||
std::optional<Ptr<const Value>> d = deduced.Get(var_type.Name());
|
||||
if (!d) {
|
||||
deduced.Set(var_type.Name(), arg);
|
||||
} else {
|
||||
@@ -199,10 +200,11 @@ static auto ArgumentDeduction(SourceLocation loc, TypeEnv deduced,
|
||||
}
|
||||
}
|
||||
|
||||
static auto Substitute(TypeEnv dict, const Value* type) -> const Value* {
|
||||
static auto Substitute(TypeEnv dict, Ptr<const Value> type)
|
||||
-> Ptr<const Value> {
|
||||
switch (type->Tag()) {
|
||||
case Value::Kind::VariableType: {
|
||||
std::optional<const Value*> t =
|
||||
std::optional<Ptr<const Value>> t =
|
||||
dict.Get(cast<VariableType>(*type).Name());
|
||||
if (!t) {
|
||||
return type;
|
||||
@@ -216,17 +218,17 @@ static auto Substitute(TypeEnv dict, const Value* type) -> const Value* {
|
||||
auto t = Substitute(dict, elt.value);
|
||||
elts.push_back({.name = elt.name, .value = t});
|
||||
}
|
||||
return global_arena->RawNew<TupleValue>(elts);
|
||||
return global_arena->New<TupleValue>(elts);
|
||||
}
|
||||
case Value::Kind::FunctionType: {
|
||||
const auto& fn_type = cast<FunctionType>(*type);
|
||||
auto param = Substitute(dict, fn_type.Param());
|
||||
auto ret = Substitute(dict, fn_type.Ret());
|
||||
return global_arena->RawNew<FunctionType>(std::vector<GenericBinding>(),
|
||||
param, ret);
|
||||
return global_arena->New<FunctionType>(std::vector<GenericBinding>(),
|
||||
param, ret);
|
||||
}
|
||||
case Value::Kind::PointerType: {
|
||||
return global_arena->RawNew<PointerType>(
|
||||
return global_arena->New<PointerType>(
|
||||
Substitute(dict, cast<PointerType>(*type).Type()));
|
||||
}
|
||||
case Value::Kind::AutoType:
|
||||
@@ -273,15 +275,16 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
|
||||
cast<IntValue>(*interpreter.InterpExp(values, index.Offset()))
|
||||
.Val();
|
||||
std::string f = std::to_string(i);
|
||||
const Value* field_t = cast<TupleValue>(*t).FindField(f);
|
||||
if (field_t == nullptr) {
|
||||
std::optional<Ptr<const Value>> field_t =
|
||||
cast<TupleValue>(*t).FindField(f);
|
||||
if (!field_t) {
|
||||
FATAL_COMPILATION_ERROR(e->SourceLoc())
|
||||
<< "field " << f << " is not in the tuple " << *t;
|
||||
}
|
||||
auto new_e = global_arena->New<IndexExpression>(
|
||||
e->SourceLoc(), res.exp,
|
||||
global_arena->New<IntLiteral>(e->SourceLoc(), i));
|
||||
return TCExpression(new_e, field_t, res.types);
|
||||
return TCExpression(new_e, *field_t, res.types);
|
||||
}
|
||||
default:
|
||||
FATAL_COMPILATION_ERROR(e->SourceLoc()) << "expected a tuple";
|
||||
@@ -298,7 +301,7 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
|
||||
arg_types.push_back({.name = arg.name, .value = arg_res.type});
|
||||
}
|
||||
auto tuple_e = global_arena->New<TupleLiteral>(e->SourceLoc(), new_args);
|
||||
auto tuple_t = global_arena->RawNew<TupleValue>(std::move(arg_types));
|
||||
auto tuple_t = global_arena->New<TupleValue>(std::move(arg_types));
|
||||
return TCExpression(tuple_e, tuple_t, new_types);
|
||||
}
|
||||
case Expression::Kind::FieldAccessExpression: {
|
||||
@@ -350,7 +353,7 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
|
||||
Ptr<const Expression> new_e =
|
||||
global_arena->New<FieldAccessExpression>(
|
||||
e->SourceLoc(), res.exp, access.Field());
|
||||
auto fun_ty = global_arena->RawNew<FunctionType>(
|
||||
auto fun_ty = global_arena->New<FunctionType>(
|
||||
std::vector<GenericBinding>(), vt.second, t);
|
||||
return TCExpression(new_e, fun_ty, res.types);
|
||||
}
|
||||
@@ -367,7 +370,7 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
|
||||
}
|
||||
case Expression::Kind::IdentifierExpression: {
|
||||
const auto& ident = cast<IdentifierExpression>(*e);
|
||||
std::optional<const Value*> type = types.Get(ident.Name());
|
||||
std::optional<Ptr<const Value>> type = types.Get(ident.Name());
|
||||
if (type) {
|
||||
return TCExpression(e, *type, types);
|
||||
} else {
|
||||
@@ -376,13 +379,13 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
|
||||
}
|
||||
}
|
||||
case Expression::Kind::IntLiteral:
|
||||
return TCExpression(e, global_arena->RawNew<IntType>(), types);
|
||||
return TCExpression(e, global_arena->New<IntType>(), types);
|
||||
case Expression::Kind::BoolLiteral:
|
||||
return TCExpression(e, global_arena->RawNew<BoolType>(), types);
|
||||
return TCExpression(e, global_arena->New<BoolType>(), types);
|
||||
case Expression::Kind::PrimitiveOperatorExpression: {
|
||||
const auto& op = cast<PrimitiveOperatorExpression>(*e);
|
||||
std::vector<Ptr<const Expression>> es;
|
||||
std::vector<const Value*> ts;
|
||||
std::vector<Ptr<const Value>> ts;
|
||||
auto new_types = types;
|
||||
for (Ptr<const Expression> argument : op.Arguments()) {
|
||||
auto res = TypeCheckExp(argument, types, values);
|
||||
@@ -394,63 +397,52 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
|
||||
e->SourceLoc(), op.Op(), es);
|
||||
switch (op.Op()) {
|
||||
case Operator::Neg:
|
||||
ExpectType(e->SourceLoc(), "negation",
|
||||
global_arena->RawNew<IntType>(), ts[0]);
|
||||
return TCExpression(new_e, global_arena->RawNew<IntType>(),
|
||||
new_types);
|
||||
ExpectType(e->SourceLoc(), "negation", global_arena->New<IntType>(),
|
||||
ts[0]);
|
||||
return TCExpression(new_e, global_arena->New<IntType>(), new_types);
|
||||
case Operator::Add:
|
||||
ExpectType(e->SourceLoc(), "addition(1)",
|
||||
global_arena->RawNew<IntType>(), ts[0]);
|
||||
global_arena->New<IntType>(), ts[0]);
|
||||
ExpectType(e->SourceLoc(), "addition(2)",
|
||||
global_arena->RawNew<IntType>(), ts[1]);
|
||||
return TCExpression(new_e, global_arena->RawNew<IntType>(),
|
||||
new_types);
|
||||
global_arena->New<IntType>(), ts[1]);
|
||||
return TCExpression(new_e, global_arena->New<IntType>(), new_types);
|
||||
case Operator::Sub:
|
||||
ExpectType(e->SourceLoc(), "subtraction(1)",
|
||||
global_arena->RawNew<IntType>(), ts[0]);
|
||||
global_arena->New<IntType>(), ts[0]);
|
||||
ExpectType(e->SourceLoc(), "subtraction(2)",
|
||||
global_arena->RawNew<IntType>(), ts[1]);
|
||||
return TCExpression(new_e, global_arena->RawNew<IntType>(),
|
||||
new_types);
|
||||
global_arena->New<IntType>(), ts[1]);
|
||||
return TCExpression(new_e, global_arena->New<IntType>(), new_types);
|
||||
case Operator::Mul:
|
||||
ExpectType(e->SourceLoc(), "multiplication(1)",
|
||||
global_arena->RawNew<IntType>(), ts[0]);
|
||||
global_arena->New<IntType>(), ts[0]);
|
||||
ExpectType(e->SourceLoc(), "multiplication(2)",
|
||||
global_arena->RawNew<IntType>(), ts[1]);
|
||||
return TCExpression(new_e, global_arena->RawNew<IntType>(),
|
||||
new_types);
|
||||
global_arena->New<IntType>(), ts[1]);
|
||||
return TCExpression(new_e, global_arena->New<IntType>(), new_types);
|
||||
case Operator::And:
|
||||
ExpectType(e->SourceLoc(), "&&(1)", global_arena->RawNew<BoolType>(),
|
||||
ExpectType(e->SourceLoc(), "&&(1)", global_arena->New<BoolType>(),
|
||||
ts[0]);
|
||||
ExpectType(e->SourceLoc(), "&&(2)", global_arena->RawNew<BoolType>(),
|
||||
ExpectType(e->SourceLoc(), "&&(2)", global_arena->New<BoolType>(),
|
||||
ts[1]);
|
||||
return TCExpression(new_e, global_arena->RawNew<BoolType>(),
|
||||
new_types);
|
||||
return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
|
||||
case Operator::Or:
|
||||
ExpectType(e->SourceLoc(), "||(1)", global_arena->RawNew<BoolType>(),
|
||||
ExpectType(e->SourceLoc(), "||(1)", global_arena->New<BoolType>(),
|
||||
ts[0]);
|
||||
ExpectType(e->SourceLoc(), "||(2)", global_arena->RawNew<BoolType>(),
|
||||
ExpectType(e->SourceLoc(), "||(2)", global_arena->New<BoolType>(),
|
||||
ts[1]);
|
||||
return TCExpression(new_e, global_arena->RawNew<BoolType>(),
|
||||
new_types);
|
||||
return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
|
||||
case Operator::Not:
|
||||
ExpectType(e->SourceLoc(), "!", global_arena->RawNew<BoolType>(),
|
||||
ts[0]);
|
||||
return TCExpression(new_e, global_arena->RawNew<BoolType>(),
|
||||
new_types);
|
||||
ExpectType(e->SourceLoc(), "!", global_arena->New<BoolType>(), ts[0]);
|
||||
return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
|
||||
case Operator::Eq:
|
||||
ExpectType(e->SourceLoc(), "==", ts[0], ts[1]);
|
||||
return TCExpression(new_e, global_arena->RawNew<BoolType>(),
|
||||
new_types);
|
||||
return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
|
||||
case Operator::Deref:
|
||||
ExpectPointerType(e->SourceLoc(), "*", ts[0]);
|
||||
return TCExpression(new_e, cast<PointerType>(*ts[0]).Type(),
|
||||
new_types);
|
||||
case Operator::Ptr:
|
||||
ExpectType(e->SourceLoc(), "*", global_arena->RawNew<TypeType>(),
|
||||
ts[0]);
|
||||
return TCExpression(new_e, global_arena->RawNew<TypeType>(),
|
||||
new_types);
|
||||
ExpectType(e->SourceLoc(), "*", global_arena->New<TypeType>(), ts[0]);
|
||||
return TCExpression(new_e, global_arena->New<TypeType>(), new_types);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -500,34 +492,32 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
|
||||
e->SourceLoc(), ReifyType(pt, e->SourceLoc()),
|
||||
ReifyType(rt, e->SourceLoc()),
|
||||
/*is_omitted_return_type=*/false);
|
||||
return TCExpression(new_e, global_arena->RawNew<TypeType>(), types);
|
||||
return TCExpression(new_e, global_arena->New<TypeType>(), types);
|
||||
}
|
||||
case Expression::Kind::StringLiteral:
|
||||
return TCExpression(e, global_arena->RawNew<StringType>(), types);
|
||||
return TCExpression(e, global_arena->New<StringType>(), types);
|
||||
case Expression::Kind::IntrinsicExpression:
|
||||
switch (cast<IntrinsicExpression>(*e).Intrinsic()) {
|
||||
case IntrinsicExpression::IntrinsicKind::Print:
|
||||
return TCExpression(e, &TupleValue::Empty(), types);
|
||||
return TCExpression(e, TupleValue::Empty(), types);
|
||||
}
|
||||
case Expression::Kind::IntTypeLiteral:
|
||||
case Expression::Kind::BoolTypeLiteral:
|
||||
case Expression::Kind::StringTypeLiteral:
|
||||
case Expression::Kind::TypeTypeLiteral:
|
||||
case Expression::Kind::ContinuationTypeLiteral:
|
||||
return TCExpression(e, global_arena->RawNew<TypeType>(), types);
|
||||
return TCExpression(e, global_arena->New<TypeType>(), types);
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent to TypeCheckExp, but operates on Patterns instead of Expressions.
|
||||
// `expected` is the type that this pattern is expected to have, if the
|
||||
// surrounding context gives us that information. Otherwise, it is null.
|
||||
auto TypeChecker::TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types,
|
||||
Env values, const Value* expected)
|
||||
Env values,
|
||||
std::optional<Ptr<const Value>> expected)
|
||||
-> TCPattern {
|
||||
if (tracing_output) {
|
||||
llvm::outs() << "checking pattern " << *p;
|
||||
if (expected) {
|
||||
llvm::outs() << ", expecting " << *expected;
|
||||
llvm::outs() << ", expecting " << **expected;
|
||||
}
|
||||
llvm::outs() << "\ntypes: ";
|
||||
PrintTypeEnv(types, llvm::outs());
|
||||
@@ -537,27 +527,26 @@ auto TypeChecker::TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types,
|
||||
}
|
||||
switch (p->Tag()) {
|
||||
case Pattern::Kind::AutoPattern: {
|
||||
return {.pattern = p,
|
||||
.type = global_arena->RawNew<TypeType>(),
|
||||
.types = types};
|
||||
return {
|
||||
.pattern = p, .type = global_arena->New<TypeType>(), .types = types};
|
||||
}
|
||||
case Pattern::Kind::BindingPattern: {
|
||||
const auto& binding = cast<BindingPattern>(*p);
|
||||
TCPattern binding_type_result =
|
||||
TypeCheckPattern(binding.Type(), types, values, nullptr);
|
||||
const Value* type =
|
||||
TypeCheckPattern(binding.Type(), types, values, std::nullopt);
|
||||
Ptr<const Value> type =
|
||||
interpreter.InterpPattern(values, binding_type_result.pattern);
|
||||
if (expected != nullptr) {
|
||||
if (expected) {
|
||||
std::optional<Env> values = interpreter.PatternMatch(
|
||||
type, expected, binding.Type()->SourceLoc());
|
||||
type, *expected, binding.Type()->SourceLoc());
|
||||
if (values == std::nullopt) {
|
||||
FATAL_COMPILATION_ERROR(binding.Type()->SourceLoc())
|
||||
<< "Type pattern '" << *type << "' does not match actual type '"
|
||||
<< *expected << "'";
|
||||
<< **expected << "'";
|
||||
}
|
||||
CHECK(values->begin() == values->end())
|
||||
<< "Name bindings within type patterns are unsupported";
|
||||
type = expected;
|
||||
type = *expected;
|
||||
}
|
||||
auto new_p = global_arena->New<BindingPattern>(
|
||||
binding.SourceLoc(), binding.Name(),
|
||||
@@ -573,20 +562,20 @@ auto TypeChecker::TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types,
|
||||
std::vector<TuplePattern::Field> new_fields;
|
||||
std::vector<TupleElement> field_types;
|
||||
auto new_types = types;
|
||||
if (expected && expected->Tag() != Value::Kind::TupleValue) {
|
||||
if (expected && (*expected)->Tag() != Value::Kind::TupleValue) {
|
||||
FATAL_COMPILATION_ERROR(p->SourceLoc()) << "didn't expect a tuple";
|
||||
}
|
||||
if (expected && tuple.Fields().size() !=
|
||||
cast<TupleValue>(*expected).Elements().size()) {
|
||||
cast<TupleValue>(**expected).Elements().size()) {
|
||||
FATAL_COMPILATION_ERROR(tuple.SourceLoc())
|
||||
<< "tuples of different length";
|
||||
}
|
||||
for (size_t i = 0; i < tuple.Fields().size(); ++i) {
|
||||
const TuplePattern::Field& field = tuple.Fields()[i];
|
||||
const Value* expected_field_type = nullptr;
|
||||
if (expected != nullptr) {
|
||||
std::optional<Ptr<const Value>> expected_field_type;
|
||||
if (expected) {
|
||||
const TupleElement& expected_element =
|
||||
cast<TupleValue>(*expected).Elements()[i];
|
||||
cast<TupleValue>(**expected).Elements()[i];
|
||||
if (expected_element.name != field.name) {
|
||||
FATAL_COMPILATION_ERROR(tuple.SourceLoc())
|
||||
<< "field names do not match, expected "
|
||||
@@ -603,32 +592,33 @@ auto TypeChecker::TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types,
|
||||
}
|
||||
auto new_tuple =
|
||||
global_arena->New<TuplePattern>(tuple.SourceLoc(), new_fields);
|
||||
auto tuple_t = global_arena->RawNew<TupleValue>(std::move(field_types));
|
||||
auto tuple_t = global_arena->New<TupleValue>(std::move(field_types));
|
||||
return {.pattern = new_tuple, .type = tuple_t, .types = new_types};
|
||||
}
|
||||
case Pattern::Kind::AlternativePattern: {
|
||||
const auto& alternative = cast<AlternativePattern>(*p);
|
||||
const Value* choice_type =
|
||||
Ptr<const Value> choice_type =
|
||||
interpreter.InterpExp(values, alternative.ChoiceType());
|
||||
if (choice_type->Tag() != Value::Kind::ChoiceType) {
|
||||
FATAL_COMPILATION_ERROR(alternative.SourceLoc())
|
||||
<< "alternative pattern does not name a choice type.";
|
||||
}
|
||||
if (expected != nullptr) {
|
||||
ExpectType(alternative.SourceLoc(), "alternative pattern", expected,
|
||||
if (expected) {
|
||||
ExpectType(alternative.SourceLoc(), "alternative pattern", *expected,
|
||||
choice_type);
|
||||
}
|
||||
const Value* parameter_types =
|
||||
std::optional<Ptr<const Value>> parameter_types =
|
||||
FindInVarValues(alternative.AlternativeName(),
|
||||
cast<ChoiceType>(*choice_type).Alternatives());
|
||||
if (parameter_types == nullptr) {
|
||||
if (parameter_types == std::nullopt) {
|
||||
FATAL_COMPILATION_ERROR(alternative.SourceLoc())
|
||||
<< "'" << alternative.AlternativeName()
|
||||
<< "' is not an alternative of " << choice_type;
|
||||
<< "' is not an alternative of " << *choice_type;
|
||||
}
|
||||
TCPattern arg_results = TypeCheckPattern(alternative.Arguments(), types,
|
||||
values, parameter_types);
|
||||
values, *parameter_types);
|
||||
// TODO: Think about a cleaner way to cast between Ptr types.
|
||||
// (multiple TODOs)
|
||||
auto arguments = Ptr<const TuplePattern>(
|
||||
cast<const TuplePattern>(arg_results.pattern.Get()));
|
||||
return {.pattern = global_arena->New<AlternativePattern>(
|
||||
@@ -648,9 +638,10 @@ auto TypeChecker::TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types,
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeCheckCase(const Value* expected, Ptr<const Pattern> pat,
|
||||
auto TypeChecker::TypeCheckCase(Ptr<const Value> expected,
|
||||
Ptr<const Pattern> pat,
|
||||
Ptr<const Statement> body, TypeEnv types,
|
||||
Env values, const Value*& ret_type,
|
||||
Env values, Ptr<const Value>& ret_type,
|
||||
bool is_omitted_ret_type)
|
||||
-> std::pair<Ptr<const Pattern>, Ptr<const Statement>> {
|
||||
auto pat_res = TypeCheckPattern(pat, types, values, expected);
|
||||
@@ -660,7 +651,7 @@ auto TypeChecker::TypeCheckCase(const Value* expected, Ptr<const Pattern> pat,
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
|
||||
Env values, const Value*& ret_type,
|
||||
Env values, Ptr<const Value>& ret_type,
|
||||
bool is_omitted_ret_type) -> TCStatement {
|
||||
switch (s->Tag()) {
|
||||
case Statement::Kind::Match: {
|
||||
@@ -682,7 +673,7 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
|
||||
const auto& while_stmt = cast<While>(*s);
|
||||
auto cnd_res = TypeCheckExp(while_stmt.Cond(), types, values);
|
||||
ExpectType(s->SourceLoc(), "condition of `while`",
|
||||
global_arena->RawNew<BoolType>(), cnd_res.type);
|
||||
global_arena->New<BoolType>(), cnd_res.type);
|
||||
auto body_res = TypeCheckStmt(while_stmt.Body(), types, values, ret_type,
|
||||
is_omitted_ret_type);
|
||||
auto new_s =
|
||||
@@ -706,7 +697,7 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
|
||||
case Statement::Kind::VariableDefinition: {
|
||||
const auto& var = cast<VariableDefinition>(*s);
|
||||
auto res = TypeCheckExp(var.Init(), types, values);
|
||||
const Value* rhs_ty = res.type;
|
||||
Ptr<const Value> rhs_ty = res.type;
|
||||
auto lhs_res = TypeCheckPattern(var.Pat(), types, values, rhs_ty);
|
||||
auto new_s = global_arena->New<VariableDefinition>(s->SourceLoc(),
|
||||
var.Pat(), res.exp);
|
||||
@@ -750,7 +741,7 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
|
||||
const auto& if_stmt = cast<If>(*s);
|
||||
auto cnd_res = TypeCheckExp(if_stmt.Cond(), types, values);
|
||||
ExpectType(s->SourceLoc(), "condition of `if`",
|
||||
global_arena->RawNew<BoolType>(), cnd_res.type);
|
||||
global_arena->New<BoolType>(), cnd_res.type);
|
||||
auto then_res = TypeCheckStmt(if_stmt.ThenStmt(), types, values, ret_type,
|
||||
is_omitted_ret_type);
|
||||
std::optional<Ptr<const Statement>> else_stmt;
|
||||
@@ -790,15 +781,14 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
|
||||
auto new_continuation = global_arena->New<Continuation>(
|
||||
s->SourceLoc(), cont.ContinuationVariable(), body_result.stmt);
|
||||
types.Set(cont.ContinuationVariable(),
|
||||
global_arena->RawNew<ContinuationType>());
|
||||
global_arena->New<ContinuationType>());
|
||||
return TCStatement(new_continuation, types);
|
||||
}
|
||||
case Statement::Kind::Run: {
|
||||
TCExpression argument_result =
|
||||
TypeCheckExp(cast<Run>(*s).Argument(), types, values);
|
||||
ExpectType(s->SourceLoc(), "argument of `run`",
|
||||
global_arena->RawNew<ContinuationType>(),
|
||||
argument_result.type);
|
||||
global_arena->New<ContinuationType>(), argument_result.type);
|
||||
auto new_run =
|
||||
global_arena->New<Run>(s->SourceLoc(), argument_result.exp);
|
||||
return TCStatement(new_run, types);
|
||||
@@ -894,17 +884,18 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
|
||||
// Bring the deduced parameters into scope
|
||||
for (const auto& deduced : f->deduced_parameters) {
|
||||
// auto t = interpreter.InterpExp(values, deduced.type);
|
||||
types.Set(deduced.name, global_arena->RawNew<VariableType>(deduced.name));
|
||||
types.Set(deduced.name, global_arena->New<VariableType>(deduced.name));
|
||||
Address a = interpreter.AllocateValue(*types.Get(deduced.name));
|
||||
values.Set(deduced.name, a);
|
||||
}
|
||||
// Type check the parameter pattern
|
||||
auto param_res = TypeCheckPattern(f->param_pattern, types, values, nullptr);
|
||||
auto param_res =
|
||||
TypeCheckPattern(f->param_pattern, types, values, std::nullopt);
|
||||
// Evaluate the return type expression
|
||||
auto return_type = interpreter.InterpPattern(values, f->return_type);
|
||||
if (f->name == "main") {
|
||||
ExpectType(f->source_location, "return type of `main`",
|
||||
global_arena->RawNew<IntType>(), return_type);
|
||||
global_arena->New<IntType>(), return_type);
|
||||
// TODO: Check that main doesn't have any parameters.
|
||||
}
|
||||
std::optional<Ptr<const Statement>> body_stmt;
|
||||
@@ -924,29 +915,29 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
|
||||
|
||||
auto TypeChecker::TypeOfFunDef(TypeEnv types, Env values,
|
||||
const FunctionDefinition* fun_def)
|
||||
-> const Value* {
|
||||
-> Ptr<const Value> {
|
||||
// Bring the deduced parameters into scope
|
||||
for (const auto& deduced : fun_def->deduced_parameters) {
|
||||
// auto t = interpreter.InterpExp(values, deduced.type);
|
||||
types.Set(deduced.name, global_arena->RawNew<VariableType>(deduced.name));
|
||||
types.Set(deduced.name, global_arena->New<VariableType>(deduced.name));
|
||||
Address a = interpreter.AllocateValue(*types.Get(deduced.name));
|
||||
values.Set(deduced.name, a);
|
||||
}
|
||||
// Type check the parameter pattern
|
||||
auto param_res =
|
||||
TypeCheckPattern(fun_def->param_pattern, types, values, nullptr);
|
||||
TypeCheckPattern(fun_def->param_pattern, types, values, std::nullopt);
|
||||
// Evaluate the return type expression
|
||||
auto ret = interpreter.InterpPattern(values, fun_def->return_type);
|
||||
if (ret->Tag() == Value::Kind::AutoType) {
|
||||
auto f = TypeCheckFunDef(fun_def, types, values);
|
||||
ret = interpreter.InterpPattern(values, f->return_type);
|
||||
}
|
||||
return global_arena->RawNew<FunctionType>(fun_def->deduced_parameters,
|
||||
param_res.type, ret);
|
||||
return global_arena->New<FunctionType>(fun_def->deduced_parameters,
|
||||
param_res.type, ret);
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/,
|
||||
Env ct_top) -> const Value* {
|
||||
Env ct_top) -> Ptr<const Value> {
|
||||
VarValues fields;
|
||||
VarValues methods;
|
||||
for (Ptr<const Member> m : sd->members) {
|
||||
@@ -969,8 +960,8 @@ auto TypeChecker::TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/,
|
||||
}
|
||||
}
|
||||
}
|
||||
return global_arena->RawNew<ClassType>(sd->name, std::move(fields),
|
||||
std::move(methods));
|
||||
return global_arena->New<ClassType>(sd->name, std::move(fields),
|
||||
std::move(methods));
|
||||
}
|
||||
|
||||
static auto GetName(const Declaration& d) -> const std::string& {
|
||||
@@ -1035,7 +1026,7 @@ auto TypeChecker::MakeTypeChecked(const Ptr<const Declaration> d,
|
||||
FATAL_COMPILATION_ERROR(var.SourceLoc())
|
||||
<< "Type of a top-level variable must be an expression.";
|
||||
}
|
||||
const Value* declared_type =
|
||||
Ptr<const Value> declared_type =
|
||||
interpreter.InterpExp(values, binding_type->Expression());
|
||||
ExpectType(var.SourceLoc(), "initializer of variable", declared_type,
|
||||
type_checked_initializer.type);
|
||||
@@ -1065,9 +1056,9 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
cast<ClassType>(*st).Fields()) {
|
||||
field_types.push_back({.name = field_name, .value = field_value});
|
||||
}
|
||||
auto fun_ty = global_arena->RawNew<FunctionType>(
|
||||
auto fun_ty = global_arena->New<FunctionType>(
|
||||
std::vector<GenericBinding>(),
|
||||
global_arena->RawNew<TupleValue>(std::move(field_types)), st);
|
||||
global_arena->New<TupleValue>(std::move(field_types)), st);
|
||||
tops->types.Set(class_def.name, fun_ty);
|
||||
break;
|
||||
}
|
||||
@@ -1079,8 +1070,7 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
auto t = interpreter.InterpExp(tops->values, signature);
|
||||
alts.push_back(std::make_pair(name, t));
|
||||
}
|
||||
auto ct =
|
||||
global_arena->RawNew<ChoiceType>(choice.Name(), std::move(alts));
|
||||
auto ct = global_arena->New<ChoiceType>(choice.Name(), std::move(alts));
|
||||
Address a = interpreter.AllocateValue(ct);
|
||||
tops->values.Set(choice.Name(), a); // Is this obsolete?
|
||||
tops->types.Set(choice.Name(), ct);
|
||||
@@ -1093,7 +1083,8 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
|
||||
// compile-time symbol table.
|
||||
Ptr<const Expression> type =
|
||||
cast<ExpressionPattern>(*var.Binding()->Type()).Expression();
|
||||
const Value* declared_type = interpreter.InterpExp(tops->values, type);
|
||||
Ptr<const Value> declared_type =
|
||||
interpreter.InterpExp(tops->values, type);
|
||||
tops->types.Set(*var.Binding()->Name(), declared_type);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
using TypeEnv = Dictionary<std::string, const Value*>;
|
||||
using TypeEnv = Dictionary<std::string, Ptr<const Value>>;
|
||||
|
||||
class TypeChecker {
|
||||
public:
|
||||
@@ -35,17 +35,17 @@ class TypeChecker {
|
||||
|
||||
private:
|
||||
struct TCExpression {
|
||||
TCExpression(Ptr<const Expression> e, const Value* t, TypeEnv types)
|
||||
TCExpression(Ptr<const Expression> e, Ptr<const Value> t, TypeEnv types)
|
||||
: exp(e), type(t), types(types) {}
|
||||
|
||||
Ptr<const Expression> exp;
|
||||
const Value* type;
|
||||
Ptr<const Value> type;
|
||||
TypeEnv types;
|
||||
};
|
||||
|
||||
struct TCPattern {
|
||||
Ptr<const Pattern> pattern;
|
||||
const Value* type;
|
||||
Ptr<const Value> type;
|
||||
TypeEnv types;
|
||||
};
|
||||
|
||||
@@ -71,8 +71,12 @@ class TypeChecker {
|
||||
auto TypeCheckExp(Ptr<const Expression> e, TypeEnv types, Env values)
|
||||
-> TCExpression;
|
||||
|
||||
// Equivalent to TypeCheckExp, but operates on Patterns instead of
|
||||
// Expressions. `expected` is the type that this pattern is expected to have,
|
||||
// if the surrounding context gives us that information. Otherwise, it is
|
||||
// nullopt.
|
||||
auto TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types, Env values,
|
||||
const Value* expected) -> TCPattern;
|
||||
std::optional<Ptr<const Value>> expected) -> TCPattern;
|
||||
|
||||
// TypeCheckStmt performs semantic analysis on a statement. It returns a new
|
||||
// version of the statement and a new type environment.
|
||||
@@ -82,21 +86,21 @@ class TypeChecker {
|
||||
// type is "auto", then the return type is inferred from the first return
|
||||
// statement.
|
||||
auto TypeCheckStmt(Ptr<const Statement> s, TypeEnv types, Env values,
|
||||
const Value*& ret_type, bool is_omitted_ret_type)
|
||||
Ptr<const Value>& ret_type, bool is_omitted_ret_type)
|
||||
-> TCStatement;
|
||||
|
||||
auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, Env values)
|
||||
-> Ptr<const FunctionDefinition>;
|
||||
|
||||
auto TypeCheckCase(const Value* expected, Ptr<const Pattern> pat,
|
||||
auto TypeCheckCase(Ptr<const Value> expected, Ptr<const Pattern> pat,
|
||||
Ptr<const Statement> body, TypeEnv types, Env values,
|
||||
const Value*& ret_type, bool is_omitted_ret_type)
|
||||
Ptr<const Value>& ret_type, bool is_omitted_ret_type)
|
||||
-> std::pair<Ptr<const Pattern>, Ptr<const Statement>>;
|
||||
|
||||
auto TypeOfFunDef(TypeEnv types, Env values,
|
||||
const FunctionDefinition* fun_def) -> const Value*;
|
||||
const FunctionDefinition* fun_def) -> Ptr<const Value>;
|
||||
auto TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/, Env ct_top)
|
||||
-> const Value*;
|
||||
-> Ptr<const Value>;
|
||||
|
||||
void TopLevel(const Declaration& d, TypeCheckContext* tops);
|
||||
|
||||
|
||||
@@ -17,23 +17,23 @@ namespace Carbon {
|
||||
using llvm::cast;
|
||||
|
||||
auto FindInVarValues(const std::string& field, const VarValues& inits)
|
||||
-> const Value* {
|
||||
-> std::optional<Ptr<const Value>> {
|
||||
for (auto& i : inits) {
|
||||
if (i.first == field) {
|
||||
return i.second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto FieldsEqual(const VarValues& ts1, const VarValues& ts2) -> bool {
|
||||
if (ts1.size() == ts2.size()) {
|
||||
for (auto& iter1 : ts1) {
|
||||
auto t2 = FindInVarValues(iter1.first, ts2);
|
||||
if (t2 == nullptr) {
|
||||
if (!t2) {
|
||||
return false;
|
||||
}
|
||||
if (!TypeEqual(iter1.second, t2)) {
|
||||
if (!TypeEqual(iter1.second, *t2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -43,42 +43,42 @@ auto FieldsEqual(const VarValues& ts1, const VarValues& ts2) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
auto TupleValue::FindField(const std::string& name) const -> const Value* {
|
||||
auto TupleValue::FindField(const std::string& name) const
|
||||
-> std::optional<Ptr<const Value>> {
|
||||
for (const TupleElement& element : elements) {
|
||||
if (element.name == name) {
|
||||
return element.value;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
auto GetMember(const Value* v, const std::string& f, SourceLocation loc)
|
||||
-> const Value* {
|
||||
auto GetMember(Ptr<const Value> v, const std::string& f, SourceLocation loc)
|
||||
-> Ptr<const Value> {
|
||||
switch (v->Tag()) {
|
||||
case Value::Kind::StructValue: {
|
||||
const Value* field =
|
||||
std::optional<Ptr<const Value>> field =
|
||||
cast<TupleValue>(*cast<StructValue>(*v).Inits()).FindField(f);
|
||||
if (field == nullptr) {
|
||||
if (field == std::nullopt) {
|
||||
FATAL_RUNTIME_ERROR(loc) << "member " << f << " not in " << *v;
|
||||
}
|
||||
return field;
|
||||
return *field;
|
||||
}
|
||||
case Value::Kind::TupleValue: {
|
||||
const Value* field = cast<TupleValue>(*v).FindField(f);
|
||||
if (field == nullptr) {
|
||||
std::optional<Ptr<const Value>> field = cast<TupleValue>(*v).FindField(f);
|
||||
if (!field) {
|
||||
FATAL_RUNTIME_ERROR(loc) << "field " << f << " not in " << *v;
|
||||
}
|
||||
return field;
|
||||
return *field;
|
||||
}
|
||||
case Value::Kind::ChoiceType: {
|
||||
const auto& choice = cast<ChoiceType>(*v);
|
||||
if (FindInVarValues(f, choice.Alternatives()) == nullptr) {
|
||||
if (!FindInVarValues(f, choice.Alternatives())) {
|
||||
FATAL_RUNTIME_ERROR(loc) << "alternative " << f << " not in " << *v;
|
||||
}
|
||||
return global_arena->RawNew<AlternativeConstructorValue>(f,
|
||||
choice.Name());
|
||||
return global_arena->New<AlternativeConstructorValue>(f, choice.Name());
|
||||
}
|
||||
default:
|
||||
FATAL() << "field access not allowed for value " << *v;
|
||||
@@ -88,8 +88,8 @@ auto GetMember(const Value* v, const std::string& f, SourceLocation loc)
|
||||
} // namespace
|
||||
|
||||
auto Value::GetField(const FieldPath& path, SourceLocation loc) const
|
||||
-> const Value* {
|
||||
const Value* value = this;
|
||||
-> Ptr<const Value> {
|
||||
Ptr<const Value> value(this);
|
||||
for (const std::string& field : path.components) {
|
||||
value = GetMember(value, field, loc);
|
||||
}
|
||||
@@ -98,11 +98,11 @@ auto Value::GetField(const FieldPath& path, SourceLocation loc) const
|
||||
|
||||
namespace {
|
||||
|
||||
auto SetFieldImpl(const Value* value,
|
||||
auto SetFieldImpl(Ptr<const Value> value,
|
||||
std::vector<std::string>::const_iterator path_begin,
|
||||
std::vector<std::string>::const_iterator path_end,
|
||||
const Value* field_value, SourceLocation loc)
|
||||
-> const Value* {
|
||||
Ptr<const Value> field_value, SourceLocation loc)
|
||||
-> Ptr<const Value> {
|
||||
if (path_begin == path_end) {
|
||||
return field_value;
|
||||
}
|
||||
@@ -123,7 +123,7 @@ auto SetFieldImpl(const Value* value,
|
||||
}
|
||||
it->value =
|
||||
SetFieldImpl(it->value, path_begin + 1, path_end, field_value, loc);
|
||||
return global_arena->RawNew<TupleValue>(elements);
|
||||
return global_arena->New<TupleValue>(elements);
|
||||
}
|
||||
default:
|
||||
FATAL() << "field access not allowed for value " << *value;
|
||||
@@ -132,10 +132,10 @@ auto SetFieldImpl(const Value* value,
|
||||
|
||||
} // namespace
|
||||
|
||||
auto Value::SetField(const FieldPath& path, const Value* field_value,
|
||||
SourceLocation loc) const -> const Value* {
|
||||
return SetFieldImpl(this, path.components.begin(), path.components.end(),
|
||||
field_value, loc);
|
||||
auto Value::SetField(const FieldPath& path, Ptr<const Value> field_value,
|
||||
SourceLocation loc) const -> Ptr<const Value> {
|
||||
return SetFieldImpl(Ptr<const Value>(this), path.components.begin(),
|
||||
path.components.end(), field_value, loc);
|
||||
}
|
||||
|
||||
void Value::Print(llvm::raw_ostream& out) const {
|
||||
@@ -248,7 +248,7 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
}
|
||||
}
|
||||
|
||||
auto CopyVal(const Value* val, SourceLocation loc) -> const Value* {
|
||||
auto CopyVal(Ptr<const Value> val, SourceLocation loc) -> Ptr<const Value> {
|
||||
switch (val->Tag()) {
|
||||
case Value::Kind::TupleValue: {
|
||||
std::vector<TupleElement> elements;
|
||||
@@ -256,56 +256,56 @@ auto CopyVal(const Value* val, SourceLocation loc) -> const Value* {
|
||||
elements.push_back(
|
||||
{.name = element.name, .value = CopyVal(element.value, loc)});
|
||||
}
|
||||
return global_arena->RawNew<TupleValue>(std::move(elements));
|
||||
return global_arena->New<TupleValue>(std::move(elements));
|
||||
}
|
||||
case Value::Kind::AlternativeValue: {
|
||||
const auto& alt = cast<AlternativeValue>(*val);
|
||||
const Value* arg = CopyVal(alt.Argument(), loc);
|
||||
return global_arena->RawNew<AlternativeValue>(alt.AltName(),
|
||||
alt.ChoiceName(), arg);
|
||||
Ptr<const Value> arg = CopyVal(alt.Argument(), loc);
|
||||
return global_arena->New<AlternativeValue>(alt.AltName(),
|
||||
alt.ChoiceName(), arg);
|
||||
}
|
||||
case Value::Kind::StructValue: {
|
||||
const auto& s = cast<StructValue>(*val);
|
||||
const Value* inits = CopyVal(s.Inits(), loc);
|
||||
return global_arena->RawNew<StructValue>(s.Type(), inits);
|
||||
Ptr<const Value> inits = CopyVal(s.Inits(), loc);
|
||||
return global_arena->New<StructValue>(s.Type(), inits);
|
||||
}
|
||||
case Value::Kind::IntValue:
|
||||
return global_arena->RawNew<IntValue>(cast<IntValue>(*val).Val());
|
||||
return global_arena->New<IntValue>(cast<IntValue>(*val).Val());
|
||||
case Value::Kind::BoolValue:
|
||||
return global_arena->RawNew<BoolValue>(cast<BoolValue>(*val).Val());
|
||||
return global_arena->New<BoolValue>(cast<BoolValue>(*val).Val());
|
||||
case Value::Kind::FunctionValue: {
|
||||
const auto& fn_value = cast<FunctionValue>(*val);
|
||||
return global_arena->RawNew<FunctionValue>(
|
||||
fn_value.Name(), fn_value.Param(), fn_value.Body());
|
||||
return global_arena->New<FunctionValue>(fn_value.Name(), fn_value.Param(),
|
||||
fn_value.Body());
|
||||
}
|
||||
case Value::Kind::PointerValue:
|
||||
return global_arena->RawNew<PointerValue>(cast<PointerValue>(*val).Val());
|
||||
return global_arena->New<PointerValue>(cast<PointerValue>(*val).Val());
|
||||
case Value::Kind::ContinuationValue:
|
||||
// Copying a continuation is "shallow".
|
||||
return val;
|
||||
case Value::Kind::FunctionType: {
|
||||
const auto& fn_type = cast<FunctionType>(*val);
|
||||
return global_arena->RawNew<FunctionType>(fn_type.Deduced(),
|
||||
CopyVal(fn_type.Param(), loc),
|
||||
CopyVal(fn_type.Ret(), loc));
|
||||
return global_arena->New<FunctionType>(fn_type.Deduced(),
|
||||
CopyVal(fn_type.Param(), loc),
|
||||
CopyVal(fn_type.Ret(), loc));
|
||||
}
|
||||
case Value::Kind::PointerType:
|
||||
return global_arena->RawNew<PointerType>(
|
||||
return global_arena->New<PointerType>(
|
||||
CopyVal(cast<PointerType>(*val).Type(), loc));
|
||||
case Value::Kind::IntType:
|
||||
return global_arena->RawNew<IntType>();
|
||||
return global_arena->New<IntType>();
|
||||
case Value::Kind::BoolType:
|
||||
return global_arena->RawNew<BoolType>();
|
||||
return global_arena->New<BoolType>();
|
||||
case Value::Kind::TypeType:
|
||||
return global_arena->RawNew<TypeType>();
|
||||
return global_arena->New<TypeType>();
|
||||
case Value::Kind::AutoType:
|
||||
return global_arena->RawNew<AutoType>();
|
||||
return global_arena->New<AutoType>();
|
||||
case Value::Kind::ContinuationType:
|
||||
return global_arena->RawNew<ContinuationType>();
|
||||
return global_arena->New<ContinuationType>();
|
||||
case Value::Kind::StringType:
|
||||
return global_arena->RawNew<StringType>();
|
||||
return global_arena->New<StringType>();
|
||||
case Value::Kind::StringValue:
|
||||
return global_arena->RawNew<StringValue>(cast<StringValue>(*val).Val());
|
||||
return global_arena->New<StringValue>(cast<StringValue>(*val).Val());
|
||||
case Value::Kind::VariableType:
|
||||
case Value::Kind::ClassType:
|
||||
case Value::Kind::ChoiceType:
|
||||
@@ -316,7 +316,7 @@ auto CopyVal(const Value* val, SourceLocation loc) -> const Value* {
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeEqual(const Value* t1, const Value* t2) -> bool {
|
||||
auto TypeEqual(Ptr<const Value> t1, Ptr<const Value> t2) -> bool {
|
||||
if (t1->Tag() != t2->Tag()) {
|
||||
return false;
|
||||
}
|
||||
@@ -388,7 +388,8 @@ static auto FieldsValueEqual(const std::vector<TupleElement>& ts1,
|
||||
// Returns true if the two values are equal and returns false otherwise.
|
||||
//
|
||||
// This function implements the `==` operator of Carbon.
|
||||
auto ValueEqual(const Value* v1, const Value* v2, SourceLocation loc) -> bool {
|
||||
auto ValueEqual(Ptr<const Value> v1, Ptr<const Value> v2, SourceLocation loc)
|
||||
-> bool {
|
||||
if (v1->Tag() != v2->Tag()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -70,12 +70,12 @@ class Value {
|
||||
// Returns the sub-Value specified by `path`, which must be a valid field
|
||||
// path for *this.
|
||||
auto GetField(const FieldPath& path, SourceLocation loc) const
|
||||
-> const Value*;
|
||||
-> Ptr<const Value>;
|
||||
|
||||
// Returns a copy of *this, but with the sub-Value specified by `path`
|
||||
// set to `field_value`. `path` must be a valid field path for *this.
|
||||
auto SetField(const FieldPath& path, const Value* field_value,
|
||||
SourceLocation loc) const -> const Value*;
|
||||
auto SetField(const FieldPath& path, Ptr<const Value> field_value,
|
||||
SourceLocation loc) const -> Ptr<const Value>;
|
||||
|
||||
protected:
|
||||
// Constructs a Value. `tag` must be the enumerator corresponding to the
|
||||
@@ -86,10 +86,10 @@ class Value {
|
||||
const Kind tag;
|
||||
};
|
||||
|
||||
using VarValues = std::list<std::pair<std::string, const Value*>>;
|
||||
using VarValues = std::list<std::pair<std::string, Ptr<const Value>>>;
|
||||
|
||||
auto FindInVarValues(const std::string& field, const VarValues& inits)
|
||||
-> const Value*;
|
||||
-> std::optional<Ptr<const Value>>;
|
||||
auto FieldsEqual(const VarValues& ts1, const VarValues& ts2) -> bool;
|
||||
|
||||
// A TupleElement represents the value of a single tuple field.
|
||||
@@ -98,7 +98,7 @@ struct TupleElement {
|
||||
std::string name;
|
||||
|
||||
// The field's value.
|
||||
const Value* value;
|
||||
Ptr<const Value> value;
|
||||
};
|
||||
|
||||
struct Frame; // Used by continuation.
|
||||
@@ -121,7 +121,7 @@ class IntValue : public Value {
|
||||
// A function value.
|
||||
class FunctionValue : public Value {
|
||||
public:
|
||||
FunctionValue(std::string name, const Value* param,
|
||||
FunctionValue(std::string name, Ptr<const Value> param,
|
||||
std::optional<Ptr<const Statement>> body)
|
||||
: Value(Kind::FunctionValue),
|
||||
name(std::move(name)),
|
||||
@@ -133,12 +133,12 @@ class FunctionValue : public Value {
|
||||
}
|
||||
|
||||
auto Name() const -> const std::string& { return name; }
|
||||
auto Param() const -> const Value* { return param; }
|
||||
auto Param() const -> Ptr<const Value> { return param; }
|
||||
auto Body() const -> std::optional<Ptr<const Statement>> { return body; }
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
const Value* param;
|
||||
Ptr<const Value> param;
|
||||
std::optional<Ptr<const Statement>> body;
|
||||
};
|
||||
|
||||
@@ -176,19 +176,19 @@ class BoolValue : public Value {
|
||||
// A function value.
|
||||
class StructValue : public Value {
|
||||
public:
|
||||
StructValue(const Value* type, const Value* inits)
|
||||
StructValue(Ptr<const Value> type, Ptr<const Value> inits)
|
||||
: Value(Kind::StructValue), type(type), inits(inits) {}
|
||||
|
||||
static auto classof(const Value* value) -> bool {
|
||||
return value->Tag() == Kind::StructValue;
|
||||
}
|
||||
|
||||
auto Type() const -> const Value* { return type; }
|
||||
auto Inits() const -> const Value* { return inits; }
|
||||
auto Type() const -> Ptr<const Value> { return type; }
|
||||
auto Inits() const -> Ptr<const Value> { return inits; }
|
||||
|
||||
private:
|
||||
const Value* type;
|
||||
const Value* inits;
|
||||
Ptr<const Value> type;
|
||||
Ptr<const Value> inits;
|
||||
};
|
||||
|
||||
// An alternative constructor value.
|
||||
@@ -215,7 +215,7 @@ class AlternativeConstructorValue : public Value {
|
||||
class AlternativeValue : public Value {
|
||||
public:
|
||||
AlternativeValue(std::string alt_name, std::string choice_name,
|
||||
const Value* argument)
|
||||
Ptr<const Value> argument)
|
||||
: Value(Kind::AlternativeValue),
|
||||
alt_name(std::move(alt_name)),
|
||||
choice_name(std::move(choice_name)),
|
||||
@@ -227,21 +227,21 @@ class AlternativeValue : public Value {
|
||||
|
||||
auto AltName() const -> const std::string& { return alt_name; }
|
||||
auto ChoiceName() const -> const std::string& { return choice_name; }
|
||||
auto Argument() const -> const Value* { return argument; }
|
||||
auto Argument() const -> Ptr<const Value> { return argument; }
|
||||
|
||||
private:
|
||||
std::string alt_name;
|
||||
std::string choice_name;
|
||||
const Value* argument;
|
||||
Ptr<const Value> argument;
|
||||
};
|
||||
|
||||
// A function value.
|
||||
class TupleValue : public Value {
|
||||
public:
|
||||
// An empty tuple, also known as the unit type.
|
||||
static const TupleValue& Empty() {
|
||||
static Ptr<const TupleValue> Empty() {
|
||||
static const TupleValue empty = TupleValue(std::vector<TupleElement>());
|
||||
return empty;
|
||||
return Ptr<const TupleValue>(&empty);
|
||||
}
|
||||
|
||||
explicit TupleValue(std::vector<TupleElement> elements)
|
||||
@@ -254,8 +254,9 @@ class TupleValue : public Value {
|
||||
auto Elements() const -> const std::vector<TupleElement>& { return elements; }
|
||||
|
||||
// Returns the value of the field named `name` in this tuple, or
|
||||
// null if there is no such field.
|
||||
auto FindField(const std::string& name) const -> const Value*;
|
||||
// nullopt if there is no such field.
|
||||
auto FindField(const std::string& name) const
|
||||
-> std::optional<Ptr<const Value>>;
|
||||
|
||||
private:
|
||||
std::vector<TupleElement> elements;
|
||||
@@ -265,7 +266,8 @@ class TupleValue : public Value {
|
||||
class BindingPlaceholderValue : public Value {
|
||||
public:
|
||||
// nullopt represents the `_` placeholder.
|
||||
BindingPlaceholderValue(std::optional<std::string> name, const Value* type)
|
||||
BindingPlaceholderValue(std::optional<std::string> name,
|
||||
Ptr<const Value> type)
|
||||
: Value(Kind::BindingPlaceholderValue),
|
||||
name(std::move(name)),
|
||||
type(type) {}
|
||||
@@ -275,11 +277,11 @@ class BindingPlaceholderValue : public Value {
|
||||
}
|
||||
|
||||
auto Name() const -> const std::optional<std::string>& { return name; }
|
||||
auto Type() const -> const Value* { return type; }
|
||||
auto Type() const -> Ptr<const Value> { return type; }
|
||||
|
||||
private:
|
||||
std::optional<std::string> name;
|
||||
const Value* type;
|
||||
Ptr<const Value> type;
|
||||
};
|
||||
|
||||
// The int type.
|
||||
@@ -315,8 +317,8 @@ class TypeType : public Value {
|
||||
// A function type.
|
||||
class FunctionType : public Value {
|
||||
public:
|
||||
FunctionType(std::vector<GenericBinding> deduced, const Value* param,
|
||||
const Value* ret)
|
||||
FunctionType(std::vector<GenericBinding> deduced, Ptr<const Value> param,
|
||||
Ptr<const Value> ret)
|
||||
: Value(Kind::FunctionType),
|
||||
deduced(std::move(deduced)),
|
||||
param(param),
|
||||
@@ -327,29 +329,29 @@ class FunctionType : public Value {
|
||||
}
|
||||
|
||||
auto Deduced() const -> const std::vector<GenericBinding>& { return deduced; }
|
||||
auto Param() const -> const Value* { return param; }
|
||||
auto Ret() const -> const Value* { return ret; }
|
||||
auto Param() const -> Ptr<const Value> { return param; }
|
||||
auto Ret() const -> Ptr<const Value> { return ret; }
|
||||
|
||||
private:
|
||||
std::vector<GenericBinding> deduced;
|
||||
const Value* param;
|
||||
const Value* ret;
|
||||
Ptr<const Value> param;
|
||||
Ptr<const Value> ret;
|
||||
};
|
||||
|
||||
// A pointer type.
|
||||
class PointerType : public Value {
|
||||
public:
|
||||
explicit PointerType(const Value* type)
|
||||
explicit PointerType(Ptr<const Value> type)
|
||||
: Value(Kind::PointerType), type(type) {}
|
||||
|
||||
static auto classof(const Value* value) -> bool {
|
||||
return value->Tag() == Kind::PointerType;
|
||||
}
|
||||
|
||||
auto Type() const -> const Value* { return type; }
|
||||
auto Type() const -> Ptr<const Value> { return type; }
|
||||
|
||||
private:
|
||||
const Value* type;
|
||||
Ptr<const Value> type;
|
||||
};
|
||||
|
||||
// The `auto` type.
|
||||
@@ -473,10 +475,11 @@ class StringValue : public Value {
|
||||
std::string val;
|
||||
};
|
||||
|
||||
auto CopyVal(const Value* val, SourceLocation loc) -> const Value*;
|
||||
auto CopyVal(Ptr<const Value> val, SourceLocation loc) -> Ptr<const Value>;
|
||||
|
||||
auto TypeEqual(const Value* t1, const Value* t2) -> bool;
|
||||
auto ValueEqual(const Value* v1, const Value* v2, SourceLocation loc) -> bool;
|
||||
auto TypeEqual(Ptr<const Value> t1, Ptr<const Value> t2) -> bool;
|
||||
auto ValueEqual(Ptr<const Value> v1, Ptr<const Value> v2, SourceLocation loc)
|
||||
-> bool;
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
|
||||
Reference in New Issue
Block a user