From 0601f5620b47e6338811d93dbc6faedb57a6b117 Mon Sep 17 00:00:00 2001 From: Jon Meow <46229924+jonmeow@users.noreply.github.com> Date: Wed, 1 Sep 2021 15:59:56 -0700 Subject: [PATCH] Switch Value to Ptr (#799) Co-authored-by: Geoff Romer --- executable_semantics/interpreter/action.cpp | 5 +- executable_semantics/interpreter/action.h | 8 +- executable_semantics/interpreter/heap.cpp | 8 +- executable_semantics/interpreter/heap.h | 8 +- .../interpreter/interpreter.cpp | 147 ++++++------ .../interpreter/interpreter.h | 22 +- .../interpreter/type_checker.cpp | 213 +++++++++--------- .../interpreter/type_checker.h | 24 +- executable_semantics/interpreter/value.cpp | 105 ++++----- executable_semantics/interpreter/value.h | 75 +++--- 10 files changed, 307 insertions(+), 308 deletions(-) diff --git a/executable_semantics/interpreter/action.cpp b/executable_semantics/interpreter/action.cpp index 16e10d743102..3370088e5798 100644 --- a/executable_semantics/interpreter/action.cpp +++ b/executable_semantics/interpreter/action.cpp @@ -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 << ")"; } diff --git a/executable_semantics/interpreter/action.h b/executable_semantics/interpreter/action.h index d8a849dd4bfb..e40ad05c91d5 100644 --- a/executable_semantics/interpreter/action.h +++ b/executable_semantics/interpreter/action.h @@ -38,11 +38,13 @@ class Action { auto Pos() const -> int { return pos; } // Results from a subexpression. - auto Results() const -> const std::vector& { return results; } + auto Results() const -> const std::vector>& { + return results; + } void SetPos(int pos) { this->pos = pos; } - void AddResult(const Value* result) { results.push_back(result); } + void AddResult(Ptr result) { results.push_back(result); } void Clear() { pos = 0; @@ -65,7 +67,7 @@ class Action { private: int pos = 0; - std::vector results; + std::vector> results; const Kind tag; }; diff --git a/executable_semantics/interpreter/heap.cpp b/executable_semantics/interpreter/heap.cpp index 7ad5e6f43497..a0a02399b80b 100644 --- a/executable_semantics/interpreter/heap.cpp +++ b/executable_semantics/interpreter/heap.cpp @@ -9,25 +9,23 @@ namespace Carbon { -auto Heap::AllocateValue(const Value* v) -> Address { +auto Heap::AllocateValue(Ptr 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 { 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 v, SourceLocation loc) { this->CheckAlive(a, loc); values_[a.index] = values_[a.index]->SetField(a.field_path, v, loc); } diff --git a/executable_semantics/interpreter/heap.h b/executable_semantics/interpreter/heap.h index 9ff2d9b915ff..3e8c523af220 100644 --- a/executable_semantics/interpreter/heap.h +++ b/executable_semantics/interpreter/heap.h @@ -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; // 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 v, SourceLocation loc); // Put the given value on the heap and mark it as alive. - auto AllocateValue(const Value* v) -> Address; + auto AllocateValue(Ptr 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 values_; + std::vector> values_; std::vector alive_; }; diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index fa9550f70b0d..6a0e26b1b4b6 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -75,32 +75,32 @@ void Interpreter::PrintState(llvm::raw_ostream& out) { out << "\n}\n"; } -static auto EvalPrim(Operator op, const std::vector& args, - SourceLocation loc) -> const Value* { +static auto EvalPrim(Operator op, const std::vector>& args, + SourceLocation loc) -> Ptr { switch (op) { case Operator::Neg: - return global_arena->RawNew(-cast(*args[0]).Val()); + return global_arena->New(-cast(*args[0]).Val()); case Operator::Add: - return global_arena->RawNew(cast(*args[0]).Val() + - cast(*args[1]).Val()); + return global_arena->New(cast(*args[0]).Val() + + cast(*args[1]).Val()); case Operator::Sub: - return global_arena->RawNew(cast(*args[0]).Val() - - cast(*args[1]).Val()); + return global_arena->New(cast(*args[0]).Val() - + cast(*args[1]).Val()); case Operator::Mul: - return global_arena->RawNew(cast(*args[0]).Val() * - cast(*args[1]).Val()); + return global_arena->New(cast(*args[0]).Val() * + cast(*args[1]).Val()); case Operator::Not: - return global_arena->RawNew(!cast(*args[0]).Val()); + return global_arena->New(!cast(*args[0]).Val()); case Operator::And: - return global_arena->RawNew(cast(*args[0]).Val() && - cast(*args[1]).Val()); + return global_arena->New(cast(*args[0]).Val() && + cast(*args[1]).Val()); case Operator::Or: - return global_arena->RawNew(cast(*args[0]).Val() || - cast(*args[1]).Val()); + return global_arena->New(cast(*args[0]).Val() || + cast(*args[1]).Val()); case Operator::Eq: - return global_arena->RawNew(ValueEqual(args[0], args[1], loc)); + return global_arena->New(ValueEqual(args[0], args[1], loc)); case Operator::Ptr: - return global_arena->RawNew(args[0]); + return global_arena->New(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(deduced.name)); + Address a = + heap.AllocateValue(global_arena->New(deduced.name)); new_env.Set(deduced.name, a); } auto pt = InterpPattern(new_env, func_def.param_pattern); auto f = - global_arena->RawNew(func_def.name, pt, func_def.body); + global_arena->New(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( - class_def.name, std::move(fields), std::move(methods)); + auto st = global_arena->New(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(choice.Name(), std::move(alts)); + auto ct = global_arena->New(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) { } } -static const Value* CreateTuple(Ptr act, Ptr exp) { +static Ptr CreateTuple(Ptr act, + Ptr exp) { // { { (v1,...,vn) :: C, E, F} :: S, H} // -> { { `(v1,...,vn) :: C, E, F} :: S, H} const auto& tup_lit = cast(*exp); @@ -207,10 +207,10 @@ static const Value* CreateTuple(Ptr act, Ptr exp) { {.name = tup_lit.Fields()[i].name, .value = act->Results()[i]}); } - return global_arena->RawNew(std::move(elements)); + return global_arena->New(std::move(elements)); } -auto Interpreter::PatternMatch(const Value* p, const Value* v, +auto Interpreter::PatternMatch(Ptr p, Ptr v, SourceLocation loc) -> std::optional { 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 pat, Ptr 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> 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(*exp).Name()); - const Value* v = global_arena->RawNew(pointer); + Ptr v = global_arena->New(pointer); return Done{v}; } case Expression::Kind::FieldAccessExpression: { @@ -385,7 +386,7 @@ auto Interpreter::StepLvalue() -> Transition { Address aggregate = cast(*act->Results()[0]).Val(); Address field = aggregate.SubobjectAddress( cast(*exp).Field()); - return Done{global_arena->RawNew(field)}; + return Done{global_arena->New(field)}; } } case Expression::Kind::IndexExpression: { @@ -405,7 +406,7 @@ auto Interpreter::StepLvalue() -> Transition { std::string f = std::to_string(cast(*act->Results()[1]).Val()); Address field = aggregate.SubobjectAddress(f); - return Done{global_arena->RawNew(field)}; + return Done{global_arena->New(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(act->Results()[0]); + auto* tuple = dyn_cast(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(*act->Results()[1]).Val()); - const Value* field = tuple->FindField(f); - if (field == nullptr) { + std::optional> 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(cast(*exp).Val())}; + return Done{global_arena->New(cast(*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(cast(*exp).Val())}; + return Done{global_arena->New(cast(*exp).Val())}; case Expression::Kind::PrimitiveOperatorExpression: { const auto& op = cast(*exp); if (act->Pos() != static_cast(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(act->Results()[0], arg)}; + Ptr arg = CopyVal(act->Results()[1], exp->SourceLoc()); + return Done{global_arena->New(act->Results()[0], arg)}; } case Value::Kind::AlternativeConstructorValue: { const auto& alt = cast(*act->Results()[0]); - const Value* arg = CopyVal(act->Results()[1], exp->SourceLoc()); - return Done{global_arena->RawNew( + Ptr arg = CopyVal(act->Results()[1], exp->SourceLoc()); + return Done{global_arena->New( alt.AltName(), alt.ChoiceName(), arg)}; } case Value::Kind::FunctionValue: return CallFunction{ - .function = cast(act->Results()[0]), + // TODO: Think about a cleaner way to cast between Ptr types. + // (multiple TODOs) + .function = Ptr( + cast(act->Results()[0].Get())), .args = act->Results()[1], .loc = exp->SourceLoc()}; default: @@ -590,24 +592,24 @@ auto Interpreter::StepExp() -> Transition { switch (cast(*exp).Intrinsic()) { case IntrinsicExpression::IntrinsicKind::Print: Address pointer = GetFromEnv(exp->SourceLoc(), "format_str"); - const Value* pointee = heap.Read(pointer, exp->SourceLoc()); + Ptr pointee = heap.Read(pointer, exp->SourceLoc()); CHECK(pointee->Tag() == Value::Kind::StringValue); // TODO: This could eventually use something like llvm::formatv. llvm::outs() << cast(*pointee).Val(); - return Done{&TupleValue::Empty()}; + return Done{TupleValue::Empty()}; } case Expression::Kind::IntTypeLiteral: { CHECK(act->Pos() == 0); - return Done{global_arena->RawNew()}; + return Done{global_arena->New()}; } case Expression::Kind::BoolTypeLiteral: { CHECK(act->Pos() == 0); - return Done{global_arena->RawNew()}; + return Done{global_arena->New()}; } case Expression::Kind::TypeTypeLiteral: { CHECK(act->Pos() == 0); - return Done{global_arena->RawNew()}; + return Done{global_arena->New()}; } 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( + return Done{global_arena->New( std::vector(), act->Results()[0], act->Results()[1])}; } } case Expression::Kind::ContinuationTypeLiteral: { CHECK(act->Pos() == 0); - return Done{global_arena->RawNew()}; + return Done{global_arena->New()}; } 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(cast(*exp).Val())}; + global_arena->New(cast(*exp).Val())}; case Expression::Kind::StringTypeLiteral: { CHECK(act->Pos() == 0); - return Done{global_arena->RawNew()}; + return Done{global_arena->New()}; } } // 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()}; + return Done{global_arena->New()}; } case Pattern::Kind::BindingPattern: { const auto& binding = cast(*pattern); if (act->Pos() == 0) { return Spawn{global_arena->New(binding.Type())}; } else { - return Done{global_arena->RawNew( + return Done{global_arena->New( binding.Name(), act->Results()[0])}; } } @@ -666,7 +668,7 @@ auto Interpreter::StepPattern() -> Transition { const auto& tuple = cast(*pattern); if (act->Pos() == 0) { if (tuple.Fields().empty()) { - return Done{&TupleValue::Empty()}; + return Done{TupleValue::Empty()}; } else { Ptr p1 = tuple.Fields()[0].pattern; return Spawn{(global_arena->New(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(std::move(elements))}; + return Done{global_arena->New(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(*act->Results()[0]); - return Done{global_arena->RawNew( + return Done{global_arena->New( 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 v = act->Results()[0]; + Ptr p = act->Results()[1]; std::optional 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 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("__continuation", scopes, todo); Address continuation_address = - heap.AllocateValue(global_arena->RawNew( + heap.AllocateValue(global_arena->New( std::vector>({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(paused), + global_arena->New(paused), stmt->SourceLoc()); return ManualTransition{}; } @@ -1027,15 +1030,15 @@ class Interpreter::DoTransition { void operator()(const Done& done) { Ptr 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>& fs) } auto Interpreter::InterpExp(Env values, Ptr e) - -> const Value* { + -> Ptr { 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 e) } auto Interpreter::InterpPattern(Env values, Ptr p) - -> const Value* { + -> Ptr { CHECK(program_value == std::nullopt); auto program_value_guard = llvm::make_scope_exit([&] { program_value = std::nullopt; }); diff --git a/executable_semantics/interpreter/interpreter.h b/executable_semantics/interpreter/interpreter.h index a979e6a585cc..a38cc7c4c5b5 100644 --- a/executable_semantics/interpreter/interpreter.h +++ b/executable_semantics/interpreter/interpreter.h @@ -29,18 +29,18 @@ class Interpreter { auto InterpProgram(const std::list>& fs) -> int; // Interpret an expression at compile-time. - auto InterpExp(Env values, Ptr e) -> const Value*; + auto InterpExp(Env values, Ptr e) -> Ptr; // Interpret a pattern at compile-time. - auto InterpPattern(Env values, Ptr p) -> const Value*; + auto InterpPattern(Env values, Ptr p) -> Ptr; // 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 p, Ptr v, SourceLocation loc) -> std::optional; // Support TypeChecker allocating values on the heap. - auto AllocateValue(const Value* v) -> Address { + auto AllocateValue(Ptr 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> 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 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 function; + Ptr args; SourceLocation loc; }; @@ -131,7 +131,7 @@ class Interpreter { void DeallocateScope(Ptr scope); void DeallocateLocals(Ptr frame); - void PatternAssignment(const Value* pat, const Value* val, + void PatternAssignment(Ptr pat, Ptr val, SourceLocation loc); void PrintState(llvm::raw_ostream& out); @@ -141,7 +141,7 @@ class Interpreter { Stack> stack; Heap heap; - std::optional program_value; + std::optional> program_value; }; } // namespace Carbon diff --git a/executable_semantics/interpreter/type_checker.cpp b/executable_semantics/interpreter/type_checker.cpp index 02580ee2c252..be4416d2861d 100644 --- a/executable_semantics/interpreter/type_checker.cpp +++ b/executable_semantics/interpreter/type_checker.cpp @@ -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 expected, Ptr 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 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 t, SourceLocation loc) -> Ptr { 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 param, Ptr arg) + -> TypeEnv { switch (param->Tag()) { case Value::Kind::VariableType: { const auto& var_type = cast(*param); - std::optional d = deduced.Get(var_type.Name()); + std::optional> 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 type) + -> Ptr { switch (type->Tag()) { case Value::Kind::VariableType: { - std::optional t = + std::optional> t = dict.Get(cast(*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(elts); + return global_arena->New(elts); } case Value::Kind::FunctionType: { const auto& fn_type = cast(*type); auto param = Substitute(dict, fn_type.Param()); auto ret = Substitute(dict, fn_type.Ret()); - return global_arena->RawNew(std::vector(), - param, ret); + return global_arena->New(std::vector(), + param, ret); } case Value::Kind::PointerType: { - return global_arena->RawNew( + return global_arena->New( Substitute(dict, cast(*type).Type())); } case Value::Kind::AutoType: @@ -273,15 +275,16 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, cast(*interpreter.InterpExp(values, index.Offset())) .Val(); std::string f = std::to_string(i); - const Value* field_t = cast(*t).FindField(f); - if (field_t == nullptr) { + std::optional> field_t = + cast(*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( e->SourceLoc(), res.exp, global_arena->New(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 e, TypeEnv types, arg_types.push_back({.name = arg.name, .value = arg_res.type}); } auto tuple_e = global_arena->New(e->SourceLoc(), new_args); - auto tuple_t = global_arena->RawNew(std::move(arg_types)); + auto tuple_t = global_arena->New(std::move(arg_types)); return TCExpression(tuple_e, tuple_t, new_types); } case Expression::Kind::FieldAccessExpression: { @@ -350,7 +353,7 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, Ptr new_e = global_arena->New( e->SourceLoc(), res.exp, access.Field()); - auto fun_ty = global_arena->RawNew( + auto fun_ty = global_arena->New( std::vector(), vt.second, t); return TCExpression(new_e, fun_ty, res.types); } @@ -367,7 +370,7 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, } case Expression::Kind::IdentifierExpression: { const auto& ident = cast(*e); - std::optional type = types.Get(ident.Name()); + std::optional> type = types.Get(ident.Name()); if (type) { return TCExpression(e, *type, types); } else { @@ -376,13 +379,13 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, } } case Expression::Kind::IntLiteral: - return TCExpression(e, global_arena->RawNew(), types); + return TCExpression(e, global_arena->New(), types); case Expression::Kind::BoolLiteral: - return TCExpression(e, global_arena->RawNew(), types); + return TCExpression(e, global_arena->New(), types); case Expression::Kind::PrimitiveOperatorExpression: { const auto& op = cast(*e); std::vector> es; - std::vector ts; + std::vector> ts; auto new_types = types; for (Ptr argument : op.Arguments()) { auto res = TypeCheckExp(argument, types, values); @@ -394,63 +397,52 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, e->SourceLoc(), op.Op(), es); switch (op.Op()) { case Operator::Neg: - ExpectType(e->SourceLoc(), "negation", - global_arena->RawNew(), ts[0]); - return TCExpression(new_e, global_arena->RawNew(), - new_types); + ExpectType(e->SourceLoc(), "negation", global_arena->New(), + ts[0]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Add: ExpectType(e->SourceLoc(), "addition(1)", - global_arena->RawNew(), ts[0]); + global_arena->New(), ts[0]); ExpectType(e->SourceLoc(), "addition(2)", - global_arena->RawNew(), ts[1]); - return TCExpression(new_e, global_arena->RawNew(), - new_types); + global_arena->New(), ts[1]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Sub: ExpectType(e->SourceLoc(), "subtraction(1)", - global_arena->RawNew(), ts[0]); + global_arena->New(), ts[0]); ExpectType(e->SourceLoc(), "subtraction(2)", - global_arena->RawNew(), ts[1]); - return TCExpression(new_e, global_arena->RawNew(), - new_types); + global_arena->New(), ts[1]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Mul: ExpectType(e->SourceLoc(), "multiplication(1)", - global_arena->RawNew(), ts[0]); + global_arena->New(), ts[0]); ExpectType(e->SourceLoc(), "multiplication(2)", - global_arena->RawNew(), ts[1]); - return TCExpression(new_e, global_arena->RawNew(), - new_types); + global_arena->New(), ts[1]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::And: - ExpectType(e->SourceLoc(), "&&(1)", global_arena->RawNew(), + ExpectType(e->SourceLoc(), "&&(1)", global_arena->New(), ts[0]); - ExpectType(e->SourceLoc(), "&&(2)", global_arena->RawNew(), + ExpectType(e->SourceLoc(), "&&(2)", global_arena->New(), ts[1]); - return TCExpression(new_e, global_arena->RawNew(), - new_types); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Or: - ExpectType(e->SourceLoc(), "||(1)", global_arena->RawNew(), + ExpectType(e->SourceLoc(), "||(1)", global_arena->New(), ts[0]); - ExpectType(e->SourceLoc(), "||(2)", global_arena->RawNew(), + ExpectType(e->SourceLoc(), "||(2)", global_arena->New(), ts[1]); - return TCExpression(new_e, global_arena->RawNew(), - new_types); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Not: - ExpectType(e->SourceLoc(), "!", global_arena->RawNew(), - ts[0]); - return TCExpression(new_e, global_arena->RawNew(), - new_types); + ExpectType(e->SourceLoc(), "!", global_arena->New(), ts[0]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Eq: ExpectType(e->SourceLoc(), "==", ts[0], ts[1]); - return TCExpression(new_e, global_arena->RawNew(), - new_types); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Deref: ExpectPointerType(e->SourceLoc(), "*", ts[0]); return TCExpression(new_e, cast(*ts[0]).Type(), new_types); case Operator::Ptr: - ExpectType(e->SourceLoc(), "*", global_arena->RawNew(), - ts[0]); - return TCExpression(new_e, global_arena->RawNew(), - new_types); + ExpectType(e->SourceLoc(), "*", global_arena->New(), ts[0]); + return TCExpression(new_e, global_arena->New(), new_types); } break; } @@ -500,34 +492,32 @@ auto TypeChecker::TypeCheckExp(Ptr 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(), types); + return TCExpression(new_e, global_arena->New(), types); } case Expression::Kind::StringLiteral: - return TCExpression(e, global_arena->RawNew(), types); + return TCExpression(e, global_arena->New(), types); case Expression::Kind::IntrinsicExpression: switch (cast(*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(), types); + return TCExpression(e, global_arena->New(), 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 p, TypeEnv types, - Env values, const Value* expected) + Env values, + std::optional> 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 p, TypeEnv types, } switch (p->Tag()) { case Pattern::Kind::AutoPattern: { - return {.pattern = p, - .type = global_arena->RawNew(), - .types = types}; + return { + .pattern = p, .type = global_arena->New(), .types = types}; } case Pattern::Kind::BindingPattern: { const auto& binding = cast(*p); TCPattern binding_type_result = - TypeCheckPattern(binding.Type(), types, values, nullptr); - const Value* type = + TypeCheckPattern(binding.Type(), types, values, std::nullopt); + Ptr type = interpreter.InterpPattern(values, binding_type_result.pattern); - if (expected != nullptr) { + if (expected) { std::optional 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( binding.SourceLoc(), binding.Name(), @@ -573,20 +562,20 @@ auto TypeChecker::TypeCheckPattern(Ptr p, TypeEnv types, std::vector new_fields; std::vector 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(*expected).Elements().size()) { + cast(**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> expected_field_type; + if (expected) { const TupleElement& expected_element = - cast(*expected).Elements()[i]; + cast(**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 p, TypeEnv types, } auto new_tuple = global_arena->New(tuple.SourceLoc(), new_fields); - auto tuple_t = global_arena->RawNew(std::move(field_types)); + auto tuple_t = global_arena->New(std::move(field_types)); return {.pattern = new_tuple, .type = tuple_t, .types = new_types}; } case Pattern::Kind::AlternativePattern: { const auto& alternative = cast(*p); - const Value* choice_type = + Ptr 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> parameter_types = FindInVarValues(alternative.AlternativeName(), cast(*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( cast(arg_results.pattern.Get())); return {.pattern = global_arena->New( @@ -648,9 +638,10 @@ auto TypeChecker::TypeCheckPattern(Ptr p, TypeEnv types, } } -auto TypeChecker::TypeCheckCase(const Value* expected, Ptr pat, +auto TypeChecker::TypeCheckCase(Ptr expected, + Ptr pat, Ptr body, TypeEnv types, - Env values, const Value*& ret_type, + Env values, Ptr& ret_type, bool is_omitted_ret_type) -> std::pair, Ptr> { auto pat_res = TypeCheckPattern(pat, types, values, expected); @@ -660,7 +651,7 @@ auto TypeChecker::TypeCheckCase(const Value* expected, Ptr pat, } auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, - Env values, const Value*& ret_type, + Env values, Ptr& ret_type, bool is_omitted_ret_type) -> TCStatement { switch (s->Tag()) { case Statement::Kind::Match: { @@ -682,7 +673,7 @@ auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, const auto& while_stmt = cast(*s); auto cnd_res = TypeCheckExp(while_stmt.Cond(), types, values); ExpectType(s->SourceLoc(), "condition of `while`", - global_arena->RawNew(), cnd_res.type); + global_arena->New(), 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 s, TypeEnv types, case Statement::Kind::VariableDefinition: { const auto& var = cast(*s); auto res = TypeCheckExp(var.Init(), types, values); - const Value* rhs_ty = res.type; + Ptr rhs_ty = res.type; auto lhs_res = TypeCheckPattern(var.Pat(), types, values, rhs_ty); auto new_s = global_arena->New(s->SourceLoc(), var.Pat(), res.exp); @@ -750,7 +741,7 @@ auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, const auto& if_stmt = cast(*s); auto cnd_res = TypeCheckExp(if_stmt.Cond(), types, values); ExpectType(s->SourceLoc(), "condition of `if`", - global_arena->RawNew(), cnd_res.type); + global_arena->New(), cnd_res.type); auto then_res = TypeCheckStmt(if_stmt.ThenStmt(), types, values, ret_type, is_omitted_ret_type); std::optional> else_stmt; @@ -790,15 +781,14 @@ auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, auto new_continuation = global_arena->New( s->SourceLoc(), cont.ContinuationVariable(), body_result.stmt); types.Set(cont.ContinuationVariable(), - global_arena->RawNew()); + global_arena->New()); return TCStatement(new_continuation, types); } case Statement::Kind::Run: { TCExpression argument_result = TypeCheckExp(cast(*s).Argument(), types, values); ExpectType(s->SourceLoc(), "argument of `run`", - global_arena->RawNew(), - argument_result.type); + global_arena->New(), argument_result.type); auto new_run = global_arena->New(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(deduced.name)); + types.Set(deduced.name, global_arena->New(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(), return_type); + global_arena->New(), return_type); // TODO: Check that main doesn't have any parameters. } std::optional> 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 { // 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(deduced.name)); + types.Set(deduced.name, global_arena->New(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(fun_def->deduced_parameters, - param_res.type, ret); + return global_arena->New(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 { VarValues fields; VarValues methods; for (Ptr m : sd->members) { @@ -969,8 +960,8 @@ auto TypeChecker::TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/, } } } - return global_arena->RawNew(sd->name, std::move(fields), - std::move(methods)); + return global_arena->New(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 d, FATAL_COMPILATION_ERROR(var.SourceLoc()) << "Type of a top-level variable must be an expression."; } - const Value* declared_type = + Ptr 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(*st).Fields()) { field_types.push_back({.name = field_name, .value = field_value}); } - auto fun_ty = global_arena->RawNew( + auto fun_ty = global_arena->New( std::vector(), - global_arena->RawNew(std::move(field_types)), st); + global_arena->New(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(choice.Name(), std::move(alts)); + auto ct = global_arena->New(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 type = cast(*var.Binding()->Type()).Expression(); - const Value* declared_type = interpreter.InterpExp(tops->values, type); + Ptr declared_type = + interpreter.InterpExp(tops->values, type); tops->types.Set(*var.Binding()->Name(), declared_type); break; } diff --git a/executable_semantics/interpreter/type_checker.h b/executable_semantics/interpreter/type_checker.h index 72da7ba1f560..f1dff7d9c473 100644 --- a/executable_semantics/interpreter/type_checker.h +++ b/executable_semantics/interpreter/type_checker.h @@ -16,7 +16,7 @@ namespace Carbon { -using TypeEnv = Dictionary; +using TypeEnv = Dictionary>; class TypeChecker { public: @@ -35,17 +35,17 @@ class TypeChecker { private: struct TCExpression { - TCExpression(Ptr e, const Value* t, TypeEnv types) + TCExpression(Ptr e, Ptr t, TypeEnv types) : exp(e), type(t), types(types) {} Ptr exp; - const Value* type; + Ptr type; TypeEnv types; }; struct TCPattern { Ptr pattern; - const Value* type; + Ptr type; TypeEnv types; }; @@ -71,8 +71,12 @@ class TypeChecker { auto TypeCheckExp(Ptr 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 p, TypeEnv types, Env values, - const Value* expected) -> TCPattern; + std::optional> 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 s, TypeEnv types, Env values, - const Value*& ret_type, bool is_omitted_ret_type) + Ptr& ret_type, bool is_omitted_ret_type) -> TCStatement; auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, Env values) -> Ptr; - auto TypeCheckCase(const Value* expected, Ptr pat, + auto TypeCheckCase(Ptr expected, Ptr pat, Ptr body, TypeEnv types, Env values, - const Value*& ret_type, bool is_omitted_ret_type) + Ptr& ret_type, bool is_omitted_ret_type) -> std::pair, Ptr>; auto TypeOfFunDef(TypeEnv types, Env values, - const FunctionDefinition* fun_def) -> const Value*; + const FunctionDefinition* fun_def) -> Ptr; auto TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/, Env ct_top) - -> const Value*; + -> Ptr; void TopLevel(const Declaration& d, TypeCheckContext* tops); diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index a0944107f62d..452a58427e6f 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -17,23 +17,23 @@ namespace Carbon { using llvm::cast; auto FindInVarValues(const std::string& field, const VarValues& inits) - -> const Value* { + -> std::optional> { 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> { 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 v, const std::string& f, SourceLocation loc) + -> Ptr { switch (v->Tag()) { case Value::Kind::StructValue: { - const Value* field = + std::optional> field = cast(*cast(*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(*v).FindField(f); - if (field == nullptr) { + std::optional> field = cast(*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(*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(f, - choice.Name()); + return global_arena->New(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 { + Ptr 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 value, std::vector::const_iterator path_begin, std::vector::const_iterator path_end, - const Value* field_value, SourceLocation loc) - -> const Value* { + Ptr field_value, SourceLocation loc) + -> Ptr { 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(elements); + return global_arena->New(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 field_value, + SourceLocation loc) const -> Ptr { + return SetFieldImpl(Ptr(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 val, SourceLocation loc) -> Ptr { switch (val->Tag()) { case Value::Kind::TupleValue: { std::vector 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(std::move(elements)); + return global_arena->New(std::move(elements)); } case Value::Kind::AlternativeValue: { const auto& alt = cast(*val); - const Value* arg = CopyVal(alt.Argument(), loc); - return global_arena->RawNew(alt.AltName(), - alt.ChoiceName(), arg); + Ptr arg = CopyVal(alt.Argument(), loc); + return global_arena->New(alt.AltName(), + alt.ChoiceName(), arg); } case Value::Kind::StructValue: { const auto& s = cast(*val); - const Value* inits = CopyVal(s.Inits(), loc); - return global_arena->RawNew(s.Type(), inits); + Ptr inits = CopyVal(s.Inits(), loc); + return global_arena->New(s.Type(), inits); } case Value::Kind::IntValue: - return global_arena->RawNew(cast(*val).Val()); + return global_arena->New(cast(*val).Val()); case Value::Kind::BoolValue: - return global_arena->RawNew(cast(*val).Val()); + return global_arena->New(cast(*val).Val()); case Value::Kind::FunctionValue: { const auto& fn_value = cast(*val); - return global_arena->RawNew( - fn_value.Name(), fn_value.Param(), fn_value.Body()); + return global_arena->New(fn_value.Name(), fn_value.Param(), + fn_value.Body()); } case Value::Kind::PointerValue: - return global_arena->RawNew(cast(*val).Val()); + return global_arena->New(cast(*val).Val()); case Value::Kind::ContinuationValue: // Copying a continuation is "shallow". return val; case Value::Kind::FunctionType: { const auto& fn_type = cast(*val); - return global_arena->RawNew(fn_type.Deduced(), - CopyVal(fn_type.Param(), loc), - CopyVal(fn_type.Ret(), loc)); + return global_arena->New(fn_type.Deduced(), + CopyVal(fn_type.Param(), loc), + CopyVal(fn_type.Ret(), loc)); } case Value::Kind::PointerType: - return global_arena->RawNew( + return global_arena->New( CopyVal(cast(*val).Type(), loc)); case Value::Kind::IntType: - return global_arena->RawNew(); + return global_arena->New(); case Value::Kind::BoolType: - return global_arena->RawNew(); + return global_arena->New(); case Value::Kind::TypeType: - return global_arena->RawNew(); + return global_arena->New(); case Value::Kind::AutoType: - return global_arena->RawNew(); + return global_arena->New(); case Value::Kind::ContinuationType: - return global_arena->RawNew(); + return global_arena->New(); case Value::Kind::StringType: - return global_arena->RawNew(); + return global_arena->New(); case Value::Kind::StringValue: - return global_arena->RawNew(cast(*val).Val()); + return global_arena->New(cast(*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 t1, Ptr t2) -> bool { if (t1->Tag() != t2->Tag()) { return false; } @@ -388,7 +388,8 @@ static auto FieldsValueEqual(const std::vector& 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 v1, Ptr v2, SourceLocation loc) + -> bool { if (v1->Tag() != v2->Tag()) { return false; } diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h index e1198b799334..22de1039d2f9 100644 --- a/executable_semantics/interpreter/value.h +++ b/executable_semantics/interpreter/value.h @@ -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; // 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 field_value, + SourceLocation loc) const -> Ptr; 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>; +using VarValues = std::list>>; auto FindInVarValues(const std::string& field, const VarValues& inits) - -> const Value*; + -> std::optional>; 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 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 param, std::optional> 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 { return param; } auto Body() const -> std::optional> { return body; } private: std::string name; - const Value* param; + Ptr param; std::optional> 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 type, Ptr 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 { return type; } + auto Inits() const -> Ptr { return inits; } private: - const Value* type; - const Value* inits; + Ptr type; + Ptr 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 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 { return argument; } private: std::string alt_name; std::string choice_name; - const Value* argument; + Ptr argument; }; // A function value. class TupleValue : public Value { public: // An empty tuple, also known as the unit type. - static const TupleValue& Empty() { + static Ptr Empty() { static const TupleValue empty = TupleValue(std::vector()); - return empty; + return Ptr(&empty); } explicit TupleValue(std::vector elements) @@ -254,8 +254,9 @@ class TupleValue : public Value { auto Elements() const -> const std::vector& { 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>; private: std::vector elements; @@ -265,7 +266,8 @@ class TupleValue : public Value { class BindingPlaceholderValue : public Value { public: // nullopt represents the `_` placeholder. - BindingPlaceholderValue(std::optional name, const Value* type) + BindingPlaceholderValue(std::optional name, + Ptr type) : Value(Kind::BindingPlaceholderValue), name(std::move(name)), type(type) {} @@ -275,11 +277,11 @@ class BindingPlaceholderValue : public Value { } auto Name() const -> const std::optional& { return name; } - auto Type() const -> const Value* { return type; } + auto Type() const -> Ptr { return type; } private: std::optional name; - const Value* type; + Ptr type; }; // The int type. @@ -315,8 +317,8 @@ class TypeType : public Value { // A function type. class FunctionType : public Value { public: - FunctionType(std::vector deduced, const Value* param, - const Value* ret) + FunctionType(std::vector deduced, Ptr param, + Ptr ret) : Value(Kind::FunctionType), deduced(std::move(deduced)), param(param), @@ -327,29 +329,29 @@ class FunctionType : public Value { } auto Deduced() const -> const std::vector& { return deduced; } - auto Param() const -> const Value* { return param; } - auto Ret() const -> const Value* { return ret; } + auto Param() const -> Ptr { return param; } + auto Ret() const -> Ptr { return ret; } private: std::vector deduced; - const Value* param; - const Value* ret; + Ptr param; + Ptr ret; }; // A pointer type. class PointerType : public Value { public: - explicit PointerType(const Value* type) + explicit PointerType(Ptr 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 { return type; } private: - const Value* type; + Ptr 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 val, SourceLocation loc) -> Ptr; -auto TypeEqual(const Value* t1, const Value* t2) -> bool; -auto ValueEqual(const Value* v1, const Value* v2, SourceLocation loc) -> bool; +auto TypeEqual(Ptr t1, Ptr t2) -> bool; +auto ValueEqual(Ptr v1, Ptr v2, SourceLocation loc) + -> bool; } // namespace Carbon