diff --git a/executable_semantics/ast/declaration.h b/executable_semantics/ast/declaration.h index 8aeeaa156fae..63c2c996d29c 100644 --- a/executable_semantics/ast/declaration.h +++ b/executable_semantics/ast/declaration.h @@ -19,7 +19,7 @@ namespace Carbon { -struct Value; +class Value; using TypeEnv = Dictionary; using Env = Dictionary; diff --git a/executable_semantics/interpreter/field_path.h b/executable_semantics/interpreter/field_path.h index 4694dc95312a..0f49fc20dba0 100644 --- a/executable_semantics/interpreter/field_path.h +++ b/executable_semantics/interpreter/field_path.h @@ -57,7 +57,7 @@ class FieldPath { // The representation of FieldPath describes how to locate a Value within // another Value, so its implementation details are tied to the implementation // details of Value. - friend struct Value; + friend class Value; std::vector components; }; diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 764aea731b97..83d8dab897bc 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -75,28 +75,29 @@ auto EvalPrim(Operator op, const std::vector& args, int line_num) -> const Value* { switch (op) { case Operator::Neg: - return Value::MakeIntValue(-args[0]->GetIntValue()); + return global_arena->New(-cast(*args[0]).Val()); case Operator::Add: - return Value::MakeIntValue(args[0]->GetIntValue() + - args[1]->GetIntValue()); + return global_arena->New(cast(*args[0]).Val() + + cast(*args[1]).Val()); case Operator::Sub: - return Value::MakeIntValue(args[0]->GetIntValue() - - args[1]->GetIntValue()); + return global_arena->New(cast(*args[0]).Val() - + cast(*args[1]).Val()); case Operator::Mul: - return Value::MakeIntValue(args[0]->GetIntValue() * - args[1]->GetIntValue()); + return global_arena->New(cast(*args[0]).Val() * + cast(*args[1]).Val()); case Operator::Not: - return Value::MakeBoolValue(!args[0]->GetBoolValue()); + return global_arena->New(!cast(*args[0]).Val()); case Operator::And: - return Value::MakeBoolValue(args[0]->GetBoolValue() && - args[1]->GetBoolValue()); + return global_arena->New(cast(*args[0]).Val() && + cast(*args[1]).Val()); case Operator::Or: - return Value::MakeBoolValue(args[0]->GetBoolValue() || - args[1]->GetBoolValue()); + return global_arena->New(cast(*args[0]).Val() || + cast(*args[1]).Val()); case Operator::Eq: - return Value::MakeBoolValue(ValueEqual(args[0], args[1], line_num)); + return global_arena->New( + ValueEqual(args[0], args[1], line_num)); case Operator::Ptr: - return Value::MakePointerType(args[0]); + return global_arena->New(args[0]); case Operator::Deref: llvm::errs() << line_num << ": dereference not implemented yet\n"; exit(-1); @@ -114,12 +115,13 @@ void 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 = - state->heap.AllocateValue(Value::MakeVariableType(deduced.name)); + Address a = state->heap.AllocateValue( + global_arena->New(deduced.name)); new_env.Set(deduced.name, a); } auto pt = InterpPattern(new_env, func_def.param_pattern); - auto f = Value::MakeFunctionValue(func_def.name, pt, func_def.body); + auto f = + global_arena->New(func_def.name, pt, func_def.body); Address a = state->heap.AllocateValue(f); env->Set(func_def.name, a); break; @@ -141,8 +143,8 @@ void InitEnv(const Declaration& d, Env* env) { } } } - auto st = Value::MakeStructType(struct_def.name, std::move(fields), - std::move(methods)); + auto st = global_arena->New( + struct_def.name, std::move(fields), std::move(methods)); auto a = state->heap.AllocateValue(st); env->Set(struct_def.name, a); break; @@ -155,7 +157,7 @@ void InitEnv(const Declaration& d, Env* env) { auto t = InterpExp(Env(), signature); alts.push_back(make_pair(name, t)); } - auto ct = Value::MakeChoiceType(choice.name, std::move(alts)); + auto ct = global_arena->New(choice.name, std::move(alts)); auto a = state->heap.AllocateValue(ct); env->Set(choice.name, a); break; @@ -185,35 +187,34 @@ static void InitGlobals(std::list* fs) { // F is the function void CallFunction(int line_num, std::vector operas, State* state) { - switch (operas[0]->tag()) { - case ValKind::FunctionValue: { + switch (operas[0]->Tag()) { + case Value::Kind::FunctionValue: { + const auto& fn = cast(*operas[0]); // Bind arguments to parameters std::list params; std::optional matches = - PatternMatch(operas[0]->GetFunctionValue().param, operas[1], globals, - ¶ms, line_num); + PatternMatch(fn.Param(), operas[1], globals, ¶ms, line_num); CHECK(matches) << "internal error in call_function, pattern match failed"; // Create the new frame and push it on the stack auto* scope = global_arena->New(*matches, params); auto* frame = global_arena->New( - operas[0]->GetFunctionValue().name, Stack(scope), - Stack( - Action::MakeStatementAction(operas[0]->GetFunctionValue().body))); + fn.Name(), Stack(scope), + Stack(Action::MakeStatementAction(fn.Body()))); state->stack.Push(frame); break; } - case ValKind::StructType: { + case Value::Kind::StructType: { const Value* arg = CopyVal(operas[1], line_num); - const Value* sv = Value::MakeStructValue(operas[0], arg); + const Value* sv = global_arena->New(operas[0], arg); Frame* frame = state->stack.Top(); frame->todo.Push(Action::MakeValAction(sv)); break; } - case ValKind::AlternativeConstructorValue: { + case Value::Kind::AlternativeConstructorValue: { + const auto& alt = cast(*operas[0]); const Value* arg = CopyVal(operas[1], line_num); - const Value* av = Value::MakeAlternativeValue( - operas[0]->GetAlternativeConstructorValue().alt_name, - operas[0]->GetAlternativeConstructorValue().choice_name, arg); + const Value* av = global_arena->New( + alt.AltName(), alt.ChoiceName(), arg); Frame* frame = state->stack.Top(); frame->todo.Push(Action::MakeValAction(av)); break; @@ -248,7 +249,7 @@ void CreateTuple(Frame* frame, Action* act, const Expression* exp) { for (auto i = act->results.begin(); i != act->results.end(); ++i, ++f) { elements.push_back({.name = f->name, .value = *i}); } - const Value* tv = Value::MakeTupleValue(std::move(elements)); + const Value* tv = global_arena->New(std::move(elements)); frame->todo.Pop(1); frame->todo.Push(Action::MakeValAction(tv)); } @@ -261,29 +262,28 @@ void CreateTuple(Frame* frame, Action* act, const Expression* exp) { auto PatternMatch(const Value* p, const Value* v, Env values, std::list* vars, int line_num) -> std::optional { - switch (p->tag()) { - case ValKind::BindingPlaceholderValue: { - const BindingPlaceholderValue& placeholder = - p->GetBindingPlaceholderValue(); - if (placeholder.name.has_value()) { + switch (p->Tag()) { + case Value::Kind::BindingPlaceholderValue: { + const auto& placeholder = cast(*p); + if (placeholder.Name().has_value()) { Address a = state->heap.AllocateValue(CopyVal(v, line_num)); - vars->push_back(*placeholder.name); - values.Set(*placeholder.name, a); + vars->push_back(*placeholder.Name()); + values.Set(*placeholder.Name(), a); } return values; } - case ValKind::TupleValue: - switch (v->tag()) { - case ValKind::TupleValue: { - if (p->GetTupleValue().elements.size() != - v->GetTupleValue().elements.size()) { + case Value::Kind::TupleValue: + switch (v->Tag()) { + case Value::Kind::TupleValue: { + const auto& p_tup = cast(*p); + const auto& v_tup = cast(*v); + if (p_tup.Elements().size() != v_tup.Elements().size()) { FATAL_RUNTIME_ERROR(line_num) - << "arity mismatch in tuple pattern match"; + << "arity mismatch in tuple pattern match:\n pattern: " + << p_tup << "\n value: " << v_tup; } - for (const TupleElement& pattern_element : - p->GetTupleValue().elements) { - const Value* value_field = - v->GetTupleValue().FindField(pattern_element.name); + for (const TupleElement& pattern_element : p_tup.Elements()) { + const Value* value_field = v_tup.FindField(pattern_element.name); if (value_field == nullptr) { FATAL_RUNTIME_ERROR(line_num) << "field " << pattern_element.name << "not in " << *v; @@ -303,18 +303,17 @@ auto PatternMatch(const Value* p, const Value* v, Env values, << "\n"; exit(-1); } - case ValKind::AlternativeValue: - switch (v->tag()) { - case ValKind::AlternativeValue: { - if (p->GetAlternativeValue().choice_name != - v->GetAlternativeValue().choice_name || - p->GetAlternativeValue().alt_name != - v->GetAlternativeValue().alt_name) { + case Value::Kind::AlternativeValue: + switch (v->Tag()) { + case Value::Kind::AlternativeValue: { + const auto& p_alt = cast(*p); + const auto& v_alt = cast(*v); + if (p_alt.ChoiceName() != v_alt.ChoiceName() || + p_alt.AltName() != v_alt.AltName()) { return std::nullopt; } std::optional matches = PatternMatch( - p->GetAlternativeValue().argument, - v->GetAlternativeValue().argument, values, vars, line_num); + p_alt.Argument(), v_alt.Argument(), values, vars, line_num); if (!matches) { return std::nullopt; } @@ -327,18 +326,17 @@ auto PatternMatch(const Value* p, const Value* v, Env values, << *v << "\n"; exit(-1); } - case ValKind::FunctionType: - switch (v->tag()) { - case ValKind::FunctionType: { + case Value::Kind::FunctionType: + switch (v->Tag()) { + case Value::Kind::FunctionType: { + const auto& p_fn = cast(*p); + const auto& v_fn = cast(*v); std::optional matches = - PatternMatch(p->GetFunctionType().param, - v->GetFunctionType().param, values, vars, line_num); + PatternMatch(p_fn.Param(), v_fn.Param(), values, vars, line_num); if (!matches) { return std::nullopt; } - return PatternMatch(p->GetFunctionType().ret, - v->GetFunctionType().ret, *matches, vars, - line_num); + return PatternMatch(p_fn.Ret(), v_fn.Ret(), *matches, vars, line_num); } default: return std::nullopt; @@ -353,23 +351,23 @@ auto PatternMatch(const Value* p, const Value* v, Env values, } void PatternAssignment(const Value* pat, const Value* val, int line_num) { - switch (pat->tag()) { - case ValKind::PointerValue: - state->heap.Write(pat->GetPointerValue(), CopyVal(val, line_num), + switch (pat->Tag()) { + case Value::Kind::PointerValue: + state->heap.Write(cast(*pat).Val(), CopyVal(val, line_num), line_num); break; - case ValKind::TupleValue: { - switch (val->tag()) { - case ValKind::TupleValue: { - if (pat->GetTupleValue().elements.size() != - val->GetTupleValue().elements.size()) { + case Value::Kind::TupleValue: { + switch (val->Tag()) { + case Value::Kind::TupleValue: { + const auto& pat_tup = cast(*pat); + const auto& val_tup = cast(*val); + if (pat_tup.Elements().size() != val_tup.Elements().size()) { FATAL_RUNTIME_ERROR(line_num) - << "arity mismatch in tuple pattern match"; + << "arity mismatch in tuple pattern assignment:\n pattern: " + << pat_tup << "\n value: " << val_tup; } - for (const TupleElement& pattern_element : - pat->GetTupleValue().elements) { - const Value* value_field = - val->GetTupleValue().FindField(pattern_element.name); + for (const TupleElement& pattern_element : pat_tup.Elements()) { + const Value* value_field = val_tup.FindField(pattern_element.name); if (value_field == nullptr) { FATAL_RUNTIME_ERROR(line_num) << "field " << pattern_element.name << "not in " << *val; @@ -387,16 +385,15 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) { } break; } - case ValKind::AlternativeValue: { - switch (val->tag()) { - case ValKind::AlternativeValue: { - CHECK(pat->GetAlternativeValue().choice_name == - val->GetAlternativeValue().choice_name && - pat->GetAlternativeValue().alt_name == - val->GetAlternativeValue().alt_name) + case Value::Kind::AlternativeValue: { + switch (val->Tag()) { + case Value::Kind::AlternativeValue: { + const auto& pat_alt = cast(*pat); + const auto& val_alt = cast(*val); + CHECK(val_alt.ChoiceName() == pat_alt.ChoiceName() && + val_alt.AltName() == pat_alt.AltName()) << "internal error in pattern assignment"; - PatternAssignment(pat->GetAlternativeValue().argument, - val->GetAlternativeValue().argument, line_num); + PatternAssignment(pat_alt.Argument(), val_alt.Argument(), line_num); break; } default: @@ -434,7 +431,7 @@ void StepLvalue() { << ": could not find `" << exp->GetIdentifierExpression().name << "`"; } - const Value* v = Value::MakePointerValue(*pointer); + const Value* v = global_arena->New(*pointer); frame->todo.Pop(); frame->todo.Push(Action::MakeValAction(v)); break; @@ -449,11 +446,12 @@ void StepLvalue() { } else { // { v :: [].f :: C, E, F} :: S, H} // -> { { &v.f :: C, E, F} :: S, H } - Address aggregate = act->results[0]->GetPointerValue(); + Address aggregate = cast(*act->results[0]).Val(); Address field = aggregate.SubobjectAddress(exp->GetFieldAccessExpression().field); frame->todo.Pop(1); - frame->todo.Push(Action::MakeValAction(Value::MakePointerValue(field))); + frame->todo.Push( + Action::MakeValAction(global_arena->New(field))); } break; } @@ -471,11 +469,12 @@ void StepLvalue() { } else if (act->pos == 2) { // { v :: [][i] :: C, E, F} :: S, H} // -> { { &v[i] :: C, E, F} :: S, H } - Address aggregate = act->results[0]->GetPointerValue(); - std::string f = std::to_string(act->results[1]->GetIntValue()); + Address aggregate = cast(*act->results[0]).Val(); + std::string f = std::to_string(cast(*act->results[1]).Val()); Address field = aggregate.SubobjectAddress(f); frame->todo.Pop(1); - frame->todo.Push(Action::MakeValAction(Value::MakePointerValue(field))); + frame->todo.Push( + Action::MakeValAction(global_arena->New(field))); } break; } @@ -539,12 +538,13 @@ void StepExp() { act->pos++; } else if (act->pos == 2) { auto tuple = act->results[0]; - switch (tuple->tag()) { - case ValKind::TupleValue: { + switch (tuple->Tag()) { + case Value::Kind::TupleValue: { // { { v :: [][i] :: C, E, F} :: S, H} // -> { { v_i :: C, E, F} : S, H} - std::string f = std::to_string(act->results[1]->GetIntValue()); - const Value* field = tuple->GetTupleValue().FindField(f); + std::string f = + std::to_string(cast(*act->results[1]).Val()); + const Value* field = cast(*tuple).FindField(f); if (field == nullptr) { FATAL_RUNTIME_ERROR_NO_LINE() << "field " << f << " not in " << *tuple; @@ -622,15 +622,15 @@ void StepExp() { CHECK(act->pos == 0); // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} frame->todo.Pop(1); - frame->todo.Push( - Action::MakeValAction(Value::MakeIntValue(exp->GetIntLiteral()))); + frame->todo.Push(Action::MakeValAction( + global_arena->New(exp->GetIntLiteral()))); break; case ExpressionKind::BoolLiteral: CHECK(act->pos == 0); // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} frame->todo.Pop(1); - frame->todo.Push( - Action::MakeValAction(Value::MakeBoolValue(exp->GetBoolLiteral()))); + frame->todo.Push(Action::MakeValAction( + global_arena->New(exp->GetBoolLiteral()))); break; case ExpressionKind::PrimitiveOperatorExpression: if (act->pos != @@ -676,21 +676,21 @@ void StepExp() { break; case ExpressionKind::IntTypeLiteral: { CHECK(act->pos == 0); - const Value* v = Value::MakeIntType(); + const Value* v = global_arena->New(); frame->todo.Pop(1); frame->todo.Push(Action::MakeValAction(v)); break; } case ExpressionKind::BoolTypeLiteral: { CHECK(act->pos == 0); - const Value* v = Value::MakeBoolType(); + const Value* v = global_arena->New(); frame->todo.Pop(1); frame->todo.Push(Action::MakeValAction(v)); break; } case ExpressionKind::TypeTypeLiteral: { CHECK(act->pos == 0); - const Value* v = Value::MakeTypeType(); + const Value* v = global_arena->New(); frame->todo.Pop(1); frame->todo.Push(Action::MakeValAction(v)); break; @@ -709,8 +709,8 @@ void StepExp() { } else if (act->pos == 2) { // { { rt :: fn pt -> [] :: C, E, F} :: S, H} // -> { fn pt -> rt :: {C, E, F} :: S, H} - const Value* v = - Value::MakeFunctionType({}, act->results[0], act->results[1]); + const Value* v = global_arena->New( + std::vector(), act->results[0], act->results[1]); frame->todo.Pop(1); frame->todo.Push(Action::MakeValAction(v)); } @@ -718,7 +718,7 @@ void StepExp() { } case ExpressionKind::ContinuationTypeLiteral: { CHECK(act->pos == 0); - const Value* v = Value::MakeContinuationType(); + const Value* v = global_arena->New(); frame->todo.Pop(1); frame->todo.Push(Action::MakeValAction(v)); break; @@ -736,7 +736,7 @@ void StepPattern() { switch (pattern->Tag()) { case Pattern::Kind::AutoPattern: { CHECK(act->pos == 0); - const Value* v = Value::MakeAutoType(); + const Value* v = global_arena->New(); frame->todo.Pop(1); frame->todo.Push(Action::MakeValAction(v)); break; @@ -747,8 +747,8 @@ void StepPattern() { frame->todo.Push(Action::MakePatternAction(binding.Type())); act->pos++; } else { - auto v = - Value::MakeBindingPlaceholderValue(binding.Name(), act->results[0]); + auto v = global_arena->New(binding.Name(), + act->results[0]); frame->todo.Pop(1); frame->todo.Push(Action::MakeValAction(v)); } @@ -759,7 +759,8 @@ void StepPattern() { if (act->pos == 0) { if (tuple.Fields().empty()) { frame->todo.Pop(1); - frame->todo.Push(Action::MakeValAction(Value::MakeTupleValue({}))); + frame->todo.Push(Action::MakeValAction( + global_arena->New(std::vector()))); } else { const Pattern* p1 = tuple.Fields()[0].pattern; frame->todo.Push(Action::MakePatternAction(p1)); @@ -779,7 +780,8 @@ void StepPattern() { elements.push_back( {.name = tuple.Fields()[i].name, .value = act->results[i]}); } - const Value* tuple_value = Value::MakeTupleValue(std::move(elements)); + const Value* tuple_value = + global_arena->New(std::move(elements)); frame->todo.Pop(1); frame->todo.Push(Action::MakeValAction(tuple_value)); } @@ -796,10 +798,12 @@ void StepPattern() { act->pos++; } else { CHECK(act->pos == 2); - const auto& choice_type = act->results[0]->GetChoiceType(); + const auto& choice_type = cast(*act->results[0]); frame->todo.Pop(1); - frame->todo.Push(Action::MakeValAction(Value::MakeAlternativeValue( - alternative.AlternativeName(), choice_type.name, act->results[1]))); + frame->todo.Push( + Action::MakeValAction(global_arena->New( + alternative.AlternativeName(), choice_type.Name(), + act->results[1]))); } break; } @@ -917,7 +921,7 @@ void StepStmt() { // -> { { e :: (while ([]) s) :: C, E, F} :: S, H} frame->todo.Push(Action::MakeExpressionAction(stmt->GetWhile().cond)); act->pos++; - } else if (act->results[0]->GetBoolValue()) { + } else if (cast(*act->results[0]).Val()) { // { {true :: (while ([]) s) :: C, E, F} :: S, H} // -> { { s :: (while (e) s) :: C, E, F } :: S, H} frame->todo.Top()->pos = 0; @@ -1042,7 +1046,7 @@ void StepStmt() { // -> { { e :: (if ([]) then_stmt else else_stmt) :: C, E, F} :: S, H} frame->todo.Push(Action::MakeExpressionAction(stmt->GetIf().cond)); act->pos++; - } else if (act->results[0]->GetBoolValue()) { + } else if (cast(*act->results[0]).Val()) { // { {true :: if ([]) then_stmt else else_stmt :: C, E, F} :: // S, H} // -> { { then_stmt :: C, E, F } :: S, H} @@ -1099,8 +1103,9 @@ void StepStmt() { todo.Push(Action::MakeStatementAction(stmt->GetContinuation().body)); Frame* continuation_frame = global_arena->New("__continuation", scopes, todo); - Address continuation_address = state->heap.AllocateValue( - Value::MakeContinuationValue({continuation_frame})); + Address continuation_address = + state->heap.AllocateValue(global_arena->New( + std::vector({continuation_frame}))); // Store the continuation's address in the frame. continuation_frame->continuation = continuation_address; // Bind the continuation object to the continuation variable @@ -1127,7 +1132,7 @@ void StepStmt() { frame->todo.Push(ignore_result); // Push the continuation onto the current stack. const std::vector& continuation_vector = - act->results[0]->GetContinuationValue().stack; + cast(*act->results[0]).Stack(); for (auto frame_iter = continuation_vector.rbegin(); frame_iter != continuation_vector.rend(); ++frame_iter) { state->stack.Push(*frame_iter); @@ -1144,7 +1149,8 @@ void StepStmt() { } while (paused.back()->continuation == std::nullopt); // Update the continuation with the paused stack. state->heap.Write(*paused.back()->continuation, - Value::MakeContinuationValue(paused), stmt->line_num); + global_arena->New(paused), + stmt->line_num); break; } } @@ -1209,7 +1215,7 @@ auto InterpProgram(std::list* fs) -> int { } } const Value* v = state->stack.Top()->todo.Top()->GetValAction().val; - return v->GetIntValue(); + return cast(*v).Val(); } // Interpret an expression at compile-time. diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index 12499ba487ef..88866d39bcff 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/executable_semantics/interpreter/typecheck.cpp @@ -35,7 +35,7 @@ void ExpectType(int line_num, const std::string& context, const Value* expected, void ExpectPointerType(int line_num, const std::string& context, const Value* actual) { - if (actual->tag() != ValKind::PointerType) { + if (actual->Tag() != Value::Kind::PointerType) { FATAL_COMPILATION_ERROR(line_num) << "type error in " << context << "\n" << "expected a pointer type\n" << "actual: " << *actual; @@ -44,37 +44,43 @@ void ExpectPointerType(int line_num, const std::string& context, // Reify type to type expression. auto ReifyType(const Value* t, int line_num) -> const Expression* { - switch (t->tag()) { - case ValKind::IntType: + switch (t->Tag()) { + case Value::Kind::IntType: return Expression::MakeIntTypeLiteral(0); - case ValKind::BoolType: + case Value::Kind::BoolType: return Expression::MakeBoolTypeLiteral(0); - case ValKind::TypeType: + case Value::Kind::TypeType: return Expression::MakeTypeTypeLiteral(0); - case ValKind::ContinuationType: + case Value::Kind::ContinuationType: return Expression::MakeContinuationTypeLiteral(0); - case ValKind::FunctionType: + case Value::Kind::FunctionType: { + const auto& fn_type = cast(*t); return Expression::MakeFunctionTypeLiteral( - 0, ReifyType(t->GetFunctionType().param, line_num), - ReifyType(t->GetFunctionType().ret, line_num), + 0, ReifyType(fn_type.Param(), line_num), + ReifyType(fn_type.Ret(), line_num), /*is_omitted_return_type=*/false); - case ValKind::TupleValue: { + } + case Value::Kind::TupleValue: { std::vector args; - for (const TupleElement& field : t->GetTupleValue().elements) { + for (const TupleElement& field : cast(*t).Elements()) { args.push_back( FieldInitializer(field.name, ReifyType(field.value, line_num))); } return Expression::MakeTupleLiteral(0, args); } - case ValKind::StructType: - return Expression::MakeIdentifierExpression(0, t->GetStructType().name); - case ValKind::ChoiceType: - return Expression::MakeIdentifierExpression(0, t->GetChoiceType().name); - case ValKind::PointerType: + case Value::Kind::StructType: + return Expression::MakeIdentifierExpression(0, + cast(*t).Name()); + case Value::Kind::ChoiceType: + return Expression::MakeIdentifierExpression(0, + cast(*t).Name()); + case Value::Kind::PointerType: return Expression::MakePrimitiveOperatorExpression( - 0, Operator::Ptr, {ReifyType(t->GetPointerType().type, line_num)}); - case ValKind::VariableType: - return Expression::MakeIdentifierExpression(0, t->GetVariableType().name); + 0, Operator::Ptr, + {ReifyType(cast(*t).Type(), line_num)}); + case Value::Kind::VariableType: + return Expression::MakeIdentifierExpression( + 0, cast(*t).Name()); default: llvm::errs() << line_num << ": expected a type, not " << *t << "\n"; exit(-1); @@ -89,84 +95,84 @@ auto ReifyType(const Value* t, int line_num) -> const Expression* { // results so-far. auto ArgumentDeduction(int line_num, TypeEnv deduced, const Value* param, const Value* arg) -> TypeEnv { - switch (param->tag()) { - case ValKind::VariableType: { - std::optional d = - deduced.Get(param->GetVariableType().name); + switch (param->Tag()) { + case Value::Kind::VariableType: { + const auto& var_type = cast(*param); + std::optional d = deduced.Get(var_type.Name()); if (!d) { - deduced.Set(param->GetVariableType().name, arg); + deduced.Set(var_type.Name(), arg); } else { ExpectType(line_num, "argument deduction", *d, arg); } return deduced; } - case ValKind::TupleValue: { - if (arg->tag() != ValKind::TupleValue) { + case Value::Kind::TupleValue: { + if (arg->Tag() != Value::Kind::TupleValue) { ExpectType(line_num, "argument deduction", param, arg); } - if (param->GetTupleValue().elements.size() != - arg->GetTupleValue().elements.size()) { + const auto& param_tup = cast(*param); + const auto& arg_tup = cast(*arg); + if (param_tup.Elements().size() != arg_tup.Elements().size()) { ExpectType(line_num, "argument deduction", param, arg); } - for (size_t i = 0; i < param->GetTupleValue().elements.size(); ++i) { - if (param->GetTupleValue().elements[i].name != - arg->GetTupleValue().elements[i].name) { + for (size_t i = 0; i < param_tup.Elements().size(); ++i) { + if (param_tup.Elements()[i].name != arg_tup.Elements()[i].name) { std::cerr << line_num << ": mismatch in tuple names, " - << param->GetTupleValue().elements[i].name - << " != " << arg->GetTupleValue().elements[i].name - << std::endl; + << param_tup.Elements()[i].name + << " != " << arg_tup.Elements()[i].name << std::endl; exit(-1); } - deduced = ArgumentDeduction(line_num, deduced, - param->GetTupleValue().elements[i].value, - arg->GetTupleValue().elements[i].value); + deduced = + ArgumentDeduction(line_num, deduced, param_tup.Elements()[i].value, + arg_tup.Elements()[i].value); } return deduced; } - case ValKind::FunctionType: { - if (arg->tag() != ValKind::FunctionType) { + case Value::Kind::FunctionType: { + if (arg->Tag() != Value::Kind::FunctionType) { ExpectType(line_num, "argument deduction", param, arg); } + const auto& param_fn = cast(*param); + const auto& arg_fn = cast(*arg); // TODO: handle situation when arg has deduced parameters. + deduced = ArgumentDeduction(line_num, deduced, param_fn.Param(), + arg_fn.Param()); deduced = - ArgumentDeduction(line_num, deduced, param->GetFunctionType().param, - arg->GetFunctionType().param); - deduced = - ArgumentDeduction(line_num, deduced, param->GetFunctionType().ret, - arg->GetFunctionType().ret); + ArgumentDeduction(line_num, deduced, param_fn.Ret(), arg_fn.Ret()); return deduced; } - case ValKind::PointerType: { - if (arg->tag() != ValKind::PointerType) { + case Value::Kind::PointerType: { + if (arg->Tag() != Value::Kind::PointerType) { ExpectType(line_num, "argument deduction", param, arg); } - return ArgumentDeduction(line_num, deduced, param->GetPointerType().type, - arg->GetPointerType().type); + return ArgumentDeduction(line_num, deduced, + cast(*param).Type(), + cast(*arg).Type()); } // Nothing to do in the case for `auto`. - case ValKind::AutoType: { + case Value::Kind::AutoType: { return deduced; } // For the following cases, we check for type equality. - case ValKind::ContinuationType: - case ValKind::StructType: - case ValKind::ChoiceType: - case ValKind::IntType: - case ValKind::BoolType: - case ValKind::TypeType: { + case Value::Kind::ContinuationType: + case Value::Kind::StructType: + case Value::Kind::ChoiceType: + case Value::Kind::IntType: + case Value::Kind::BoolType: + case Value::Kind::TypeType: { ExpectType(line_num, "argument deduction", param, arg); return deduced; } // The rest of these cases should never happen. - case ValKind::IntValue: - case ValKind::BoolValue: - case ValKind::FunctionValue: - case ValKind::PointerValue: - case ValKind::StructValue: - case ValKind::AlternativeValue: - case ValKind::BindingPlaceholderValue: - case ValKind::AlternativeConstructorValue: - case ValKind::ContinuationValue: + case Value::Kind::IntValue: + case Value::Kind::BoolValue: + case Value::Kind::FunctionValue: + case Value::Kind::PointerValue: + case Value::Kind::StructValue: + case Value::Kind::AlternativeValue: + case Value::Kind::BindingPlaceholderValue: + case Value::Kind::AlternativeConstructorValue: + case Value::Kind::ContinuationValue: llvm::errs() << line_num << ": internal error in ArgumentDeduction: expected type, " << "not value " << *param << "\n"; @@ -175,50 +181,53 @@ auto ArgumentDeduction(int line_num, TypeEnv deduced, const Value* param, } auto Substitute(TypeEnv dict, const Value* type) -> const Value* { - switch (type->tag()) { - case ValKind::VariableType: { - std::optional t = dict.Get(type->GetVariableType().name); + switch (type->Tag()) { + case Value::Kind::VariableType: { + std::optional t = + dict.Get(cast(*type).Name()); if (!t) { return type; } else { return *t; } } - case ValKind::TupleValue: { + case Value::Kind::TupleValue: { std::vector elts; - for (const auto& elt : type->GetTupleValue().elements) { + for (const auto& elt : cast(*type).Elements()) { auto t = Substitute(dict, elt.value); elts.push_back({.name = elt.name, .value = t}); } - return Value::MakeTupleValue(elts); + return global_arena->New(elts); } - case ValKind::FunctionType: { - auto param = Substitute(dict, type->GetFunctionType().param); - auto ret = Substitute(dict, type->GetFunctionType().ret); - return Value::MakeFunctionType({}, param, ret); + 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->New(std::vector(), + param, ret); } - case ValKind::PointerType: { - return Value::MakePointerType( - Substitute(dict, type->GetPointerType().type)); + case Value::Kind::PointerType: { + return global_arena->New( + Substitute(dict, cast(*type).Type())); } - case ValKind::AutoType: - case ValKind::IntType: - case ValKind::BoolType: - case ValKind::TypeType: - case ValKind::StructType: - case ValKind::ChoiceType: - case ValKind::ContinuationType: + case Value::Kind::AutoType: + case Value::Kind::IntType: + case Value::Kind::BoolType: + case Value::Kind::TypeType: + case Value::Kind::StructType: + case Value::Kind::ChoiceType: + case Value::Kind::ContinuationType: return type; // The rest of these cases should never happen. - case ValKind::IntValue: - case ValKind::BoolValue: - case ValKind::FunctionValue: - case ValKind::PointerValue: - case ValKind::StructValue: - case ValKind::AlternativeValue: - case ValKind::BindingPlaceholderValue: - case ValKind::AlternativeConstructorValue: - case ValKind::ContinuationValue: + case Value::Kind::IntValue: + case Value::Kind::BoolValue: + case Value::Kind::FunctionValue: + case Value::Kind::PointerValue: + case Value::Kind::StructValue: + case Value::Kind::AlternativeValue: + case Value::Kind::BindingPlaceholderValue: + case Value::Kind::AlternativeConstructorValue: + case Value::Kind::ContinuationValue: llvm::errs() << "internal error in Substitute: expected type, " << "not value " << *type << "\n"; exit(-1); @@ -247,12 +256,13 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) case ExpressionKind::IndexExpression: { auto res = TypeCheckExp(e->GetIndexExpression().aggregate, types, values); auto t = res.type; - switch (t->tag()) { - case ValKind::TupleValue: { + switch (t->Tag()) { + case Value::Kind::TupleValue: { auto i = - InterpExp(values, e->GetIndexExpression().offset)->GetIntValue(); + cast(*InterpExp(values, e->GetIndexExpression().offset)) + .Val(); std::string f = std::to_string(i); - const Value* field_t = t->GetTupleValue().FindField(f); + const Value* field_t = cast(*t).FindField(f); if (field_t == nullptr) { FATAL_COMPILATION_ERROR(e->line_num) << "field " << f << " is not in the tuple " << *t; @@ -278,17 +288,18 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) arg_types.push_back({.name = arg->name, .value = arg_res.type}); } auto tuple_e = Expression::MakeTupleLiteral(e->line_num, new_args); - auto tuple_t = Value::MakeTupleValue(std::move(arg_types)); + auto tuple_t = global_arena->New(std::move(arg_types)); return TCExpression(tuple_e, tuple_t, new_types); } case ExpressionKind::FieldAccessExpression: { auto res = TypeCheckExp(e->GetFieldAccessExpression().aggregate, types, values); auto t = res.type; - switch (t->tag()) { - case ValKind::StructType: + switch (t->Tag()) { + case Value::Kind::StructType: { + const auto& t_struct = cast(*t); // Search for a field - for (auto& field : t->GetStructType().fields) { + for (auto& field : t_struct.Fields()) { if (e->GetFieldAccessExpression().field == field.first) { const Expression* new_e = Expression::MakeFieldAccessExpression( e->line_num, res.exp, e->GetFieldAccessExpression().field); @@ -296,7 +307,7 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) } } // Search for a method - for (auto& method : t->GetStructType().methods) { + for (auto& method : t_struct.Methods()) { if (e->GetFieldAccessExpression().field == method.first) { const Expression* new_e = Expression::MakeFieldAccessExpression( e->line_num, res.exp, e->GetFieldAccessExpression().field); @@ -304,11 +315,12 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) } } FATAL_COMPILATION_ERROR(e->line_num) - << "struct " << t->GetStructType().name - << " does not have a field named " + << "struct " << t_struct.Name() << " does not have a field named " << e->GetFieldAccessExpression().field; - case ValKind::TupleValue: - for (const TupleElement& field : t->GetTupleValue().elements) { + } + case Value::Kind::TupleValue: { + const auto& tup = cast(*t); + for (const TupleElement& field : tup.Elements()) { if (e->GetFieldAccessExpression().field == field.name) { auto new_e = Expression::MakeFieldAccessExpression( e->line_num, res.exp, e->GetFieldAccessExpression().field); @@ -316,24 +328,24 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) } } FATAL_COMPILATION_ERROR(e->line_num) - << "struct " << t->GetStructType().name - << " does not have a field named " + << "tuple " << tup << " does not have a field named " << e->GetFieldAccessExpression().field; - case ValKind::ChoiceType: - for (auto vt = t->GetChoiceType().alternatives.begin(); - vt != t->GetChoiceType().alternatives.end(); ++vt) { - if (e->GetFieldAccessExpression().field == vt->first) { + } + case Value::Kind::ChoiceType: { + const auto& choice = cast(*t); + for (const auto& vt : choice.Alternatives()) { + if (e->GetFieldAccessExpression().field == vt.first) { const Expression* new_e = Expression::MakeFieldAccessExpression( e->line_num, res.exp, e->GetFieldAccessExpression().field); - auto fun_ty = Value::MakeFunctionType({}, vt->second, t); + auto fun_ty = global_arena->New( + std::vector(), vt.second, t); return TCExpression(new_e, fun_ty, res.types); } } FATAL_COMPILATION_ERROR(e->line_num) - << "struct " << t->GetStructType().name - << " does not have a field named " + << "choice " << choice.Name() << " does not have a field named " << e->GetFieldAccessExpression().field; - + } default: FATAL_COMPILATION_ERROR(e->line_num) << "field access, expected a struct\n" @@ -351,9 +363,9 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) } } case ExpressionKind::IntLiteral: - return TCExpression(e, Value::MakeIntType(), types); + return TCExpression(e, global_arena->New(), types); case ExpressionKind::BoolLiteral: - return TCExpression(e, Value::MakeBoolType(), types); + return TCExpression(e, global_arena->New(), types); case ExpressionKind::PrimitiveOperatorExpression: { std::vector es; std::vector ts; @@ -369,61 +381,69 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) e->line_num, e->GetPrimitiveOperatorExpression().op, es); switch (e->GetPrimitiveOperatorExpression().op) { case Operator::Neg: - ExpectType(e->line_num, "negation", Value::MakeIntType(), ts[0]); - return TCExpression(new_e, Value::MakeIntType(), new_types); + ExpectType(e->line_num, "negation", global_arena->New(), + ts[0]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Add: - ExpectType(e->line_num, "addition(1)", Value::MakeIntType(), ts[0]); - ExpectType(e->line_num, "addition(2)", Value::MakeIntType(), ts[1]); - return TCExpression(new_e, Value::MakeIntType(), new_types); + ExpectType(e->line_num, "addition(1)", global_arena->New(), + ts[0]); + ExpectType(e->line_num, "addition(2)", global_arena->New(), + ts[1]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Sub: - ExpectType(e->line_num, "subtraction(1)", Value::MakeIntType(), - ts[0]); - ExpectType(e->line_num, "subtraction(2)", Value::MakeIntType(), - ts[1]); - return TCExpression(new_e, Value::MakeIntType(), new_types); + ExpectType(e->line_num, "subtraction(1)", + global_arena->New(), ts[0]); + ExpectType(e->line_num, "subtraction(2)", + global_arena->New(), ts[1]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Mul: - ExpectType(e->line_num, "multiplication(1)", Value::MakeIntType(), - ts[0]); - ExpectType(e->line_num, "multiplication(2)", Value::MakeIntType(), - ts[1]); - return TCExpression(new_e, Value::MakeIntType(), new_types); + ExpectType(e->line_num, "multiplication(1)", + global_arena->New(), ts[0]); + ExpectType(e->line_num, "multiplication(2)", + global_arena->New(), ts[1]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::And: - ExpectType(e->line_num, "&&(1)", Value::MakeBoolType(), ts[0]); - ExpectType(e->line_num, "&&(2)", Value::MakeBoolType(), ts[1]); - return TCExpression(new_e, Value::MakeBoolType(), new_types); + ExpectType(e->line_num, "&&(1)", global_arena->New(), + ts[0]); + ExpectType(e->line_num, "&&(2)", global_arena->New(), + ts[1]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Or: - ExpectType(e->line_num, "||(1)", Value::MakeBoolType(), ts[0]); - ExpectType(e->line_num, "||(2)", Value::MakeBoolType(), ts[1]); - return TCExpression(new_e, Value::MakeBoolType(), new_types); + ExpectType(e->line_num, "||(1)", global_arena->New(), + ts[0]); + ExpectType(e->line_num, "||(2)", global_arena->New(), + ts[1]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Not: - ExpectType(e->line_num, "!", Value::MakeBoolType(), ts[0]); - return TCExpression(new_e, Value::MakeBoolType(), new_types); + ExpectType(e->line_num, "!", global_arena->New(), ts[0]); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Eq: ExpectType(e->line_num, "==", ts[0], ts[1]); - return TCExpression(new_e, Value::MakeBoolType(), new_types); + return TCExpression(new_e, global_arena->New(), new_types); case Operator::Deref: ExpectPointerType(e->line_num, "*", ts[0]); - return TCExpression(new_e, ts[0]->GetPointerType().type, new_types); + return TCExpression(new_e, cast(*ts[0]).Type(), + new_types); case Operator::Ptr: - ExpectType(e->line_num, "*", Value::MakeTypeType(), ts[0]); - return TCExpression(new_e, Value::MakeTypeType(), new_types); + ExpectType(e->line_num, "*", global_arena->New(), ts[0]); + return TCExpression(new_e, global_arena->New(), new_types); } break; } case ExpressionKind::CallExpression: { auto fun_res = TypeCheckExp(e->GetCallExpression().function, types, values); - switch (fun_res.type->tag()) { - case ValKind::FunctionType: { - auto fun_t = fun_res.type; + switch (fun_res.type->Tag()) { + case Value::Kind::FunctionType: { + const auto& fun_t = cast(*fun_res.type); auto arg_res = TypeCheckExp(e->GetCallExpression().argument, fun_res.types, values); - auto parameter_type = fun_t->GetFunctionType().param; - auto return_type = fun_t->GetFunctionType().ret; - if (fun_t->GetFunctionType().deduced.size() > 0) { + auto parameter_type = fun_t.Param(); + auto return_type = fun_t.Ret(); + if (!fun_t.Deduced().empty()) { auto deduced_args = ArgumentDeduction(e->line_num, TypeEnv(), parameter_type, arg_res.type); - for (auto& deduced_param : fun_t->GetFunctionType().deduced) { + for (auto& deduced_param : fun_t.Deduced()) { // TODO: change the following to a CHECK once the real checking // has been added to the type checking of function signatures. if (!deduced_args.Get(deduced_param.name)) { @@ -457,16 +477,16 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) auto new_e = Expression::MakeFunctionTypeLiteral( e->line_num, ReifyType(pt, e->line_num), ReifyType(rt, e->line_num), /*is_omitted_return_type=*/false); - return TCExpression(new_e, Value::MakeTypeType(), types); + return TCExpression(new_e, global_arena->New(), types); } case ExpressionKind::IntTypeLiteral: - return TCExpression(e, Value::MakeTypeType(), types); + return TCExpression(e, global_arena->New(), types); case ExpressionKind::BoolTypeLiteral: - return TCExpression(e, Value::MakeTypeType(), types); + return TCExpression(e, global_arena->New(), types); case ExpressionKind::TypeTypeLiteral: - return TCExpression(e, Value::MakeTypeType(), types); + return TCExpression(e, global_arena->New(), types); case ExpressionKind::ContinuationTypeLiteral: - return TCExpression(e, Value::MakeTypeType(), types); + return TCExpression(e, global_arena->New(), types); } } @@ -484,7 +504,8 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, } switch (p->Tag()) { case Pattern::Kind::AutoPattern: { - return {.pattern = p, .type = Value::MakeTypeType(), .types = types}; + return { + .pattern = p, .type = global_arena->New(), .types = types}; } case Pattern::Kind::BindingPattern: { const auto& binding = cast(*p); @@ -502,7 +523,7 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, case Pattern::Kind::ExpressionPattern: { type = InterpExp( values, cast(binding.Type())->Expression()); - CHECK(type->tag() != ValKind::AutoType); + CHECK(type->Tag() != Value::Kind::AutoType); if (expected != nullptr) { ExpectType(binding.LineNumber(), "pattern variable", type, expected); @@ -529,11 +550,11 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, std::vector new_fields; std::vector field_types; auto new_types = types; - if (expected && expected->tag() != ValKind::TupleValue) { + if (expected && expected->Tag() != Value::Kind::TupleValue) { FATAL_COMPILATION_ERROR(p->LineNumber()) << "didn't expect a tuple"; } - if (expected && - tuple.Fields().size() != expected->GetTupleValue().elements.size()) { + if (expected && tuple.Fields().size() != + cast(*expected).Elements().size()) { FATAL_COMPILATION_ERROR(tuple.LineNumber()) << "tuples of different length"; } @@ -542,7 +563,7 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, const Value* expected_field_type = nullptr; if (expected != nullptr) { const TupleElement& expected_element = - expected->GetTupleValue().elements[i]; + cast(*expected).Elements()[i]; if (expected_element.name != field.name) { FATAL_COMPILATION_ERROR(tuple.LineNumber()) << "field names do not match, expected " @@ -559,13 +580,13 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, } auto new_tuple = global_arena->New(tuple.LineNumber(), new_fields); - auto tuple_t = Value::MakeTupleValue(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 = InterpExp(values, alternative.ChoiceType()); - if (choice_type->tag() != ValKind::ChoiceType) { + if (choice_type->Tag() != Value::Kind::ChoiceType) { FATAL_COMPILATION_ERROR(alternative.LineNumber()) << "alternative pattern does not name a choice type."; } @@ -575,7 +596,7 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, } const Value* parameter_types = FindInVarValues(alternative.AlternativeName(), - choice_type->GetChoiceType().alternatives); + cast(*choice_type).Alternatives()); if (parameter_types == nullptr) { FATAL_COMPILATION_ERROR(alternative.LineNumber()) << "'" << alternative.AlternativeName() @@ -639,8 +660,8 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, } case StatementKind::While: { auto cnd_res = TypeCheckExp(s->GetWhile().cond, types, values); - ExpectType(s->line_num, "condition of `while`", Value::MakeBoolType(), - cnd_res.type); + ExpectType(s->line_num, "condition of `while`", + global_arena->New(), cnd_res.type); auto body_res = TypeCheckStmt(s->GetWhile().body, types, values, ret_type); auto new_s = @@ -692,8 +713,8 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, } case StatementKind::If: { auto cnd_res = TypeCheckExp(s->GetIf().cond, types, values); - ExpectType(s->line_num, "condition of `if`", Value::MakeBoolType(), - cnd_res.type); + ExpectType(s->line_num, "condition of `if`", + global_arena->New(), cnd_res.type); auto thn_res = TypeCheckStmt(s->GetIf().then_stmt, types, values, ret_type); auto els_res = @@ -704,7 +725,7 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, } case StatementKind::Return: { auto res = TypeCheckExp(s->GetReturn().exp, types, values); - if (ret_type->tag() == ValKind::AutoType) { + if (ret_type->Tag() == Value::Kind::AutoType) { // The following infers the return type from the first 'return' // statement. This will get more difficult with subtyping, when we // should infer the least-upper bound of all the 'return' statements. @@ -723,14 +744,14 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, s->line_num, s->GetContinuation().continuation_variable, body_result.stmt); types.Set(s->GetContinuation().continuation_variable, - Value::MakeContinuationType()); + global_arena->New()); return TCStatement(new_continuation, types); } case StatementKind::Run: { TCExpression argument_result = TypeCheckExp(s->GetRun().argument, types, values); ExpectType(s->line_num, "argument of `run`", - Value::MakeContinuationType(), argument_result.type); + global_arena->New(), argument_result.type); const Statement* new_run = Statement::MakeRun(s->line_num, argument_result.exp); return TCStatement(new_run, types); @@ -820,8 +841,8 @@ auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, Env values) // Bring the deduced parameters into scope for (const auto& deduced : f->deduced_parameters) { // auto t = InterpExp(values, deduced.type); - Address a = - state->heap.AllocateValue(Value::MakeVariableType(deduced.name)); + Address a = state->heap.AllocateValue( + global_arena->New(deduced.name)); values.Set(deduced.name, a); } // Type check the parameter pattern @@ -829,12 +850,13 @@ auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, Env values) // Evaluate the return type expression auto return_type = InterpPattern(values, f->return_type); if (f->name == "main") { - ExpectType(f->line_num, "return type of `main`", Value::MakeIntType(), - return_type); + ExpectType(f->line_num, "return type of `main`", + global_arena->New(), return_type); // TODO: Check that main doesn't have any parameters. } auto res = TypeCheckStmt(f->body, param_res.types, values, return_type); - bool void_return = TypeEqual(return_type, Value::MakeUnitTypeVal()); + bool void_return = TypeEqual( + return_type, global_arena->New(std::vector())); auto body = CheckOrEnsureReturn(res.stmt, void_return, f->line_num); return global_arena->New( f->line_num, f->name, f->deduced_parameters, f->param_pattern, @@ -847,8 +869,8 @@ auto TypeOfFunDef(TypeEnv types, Env values, const FunctionDefinition* fun_def) // Bring the deduced parameters into scope for (const auto& deduced : fun_def->deduced_parameters) { // auto t = InterpExp(values, deduced.type); - Address a = - state->heap.AllocateValue(Value::MakeVariableType(deduced.name)); + Address a = state->heap.AllocateValue( + global_arena->New(deduced.name)); values.Set(deduced.name, a); } // Type check the parameter pattern @@ -856,12 +878,12 @@ auto TypeOfFunDef(TypeEnv types, Env values, const FunctionDefinition* fun_def) TypeCheckPattern(fun_def->param_pattern, types, values, nullptr); // Evaluate the return type expression auto ret = InterpPattern(values, fun_def->return_type); - if (ret->tag() == ValKind::AutoType) { + if (ret->Tag() == Value::Kind::AutoType) { auto f = TypeCheckFunDef(fun_def, types, values); ret = InterpPattern(values, f->return_type); } - return Value::MakeFunctionType(fun_def->deduced_parameters, param_res.type, - ret); + return global_arena->New(fun_def->deduced_parameters, + param_res.type, ret); } auto TypeOfStructDef(const StructDefinition* sd, TypeEnv /*types*/, Env ct_top) @@ -888,7 +910,8 @@ auto TypeOfStructDef(const StructDefinition* sd, TypeEnv /*types*/, Env ct_top) } } } - return Value::MakeStructType(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& { @@ -975,11 +998,13 @@ static void TopLevel(const Declaration& d, TypeCheckContext* tops) { Address a = state->heap.AllocateValue(st); tops->values.Set(struct_def.name, a); // Is this obsolete? std::vector field_types; - for (const auto& [field_name, field_value] : st->GetStructType().fields) { + for (const auto& [field_name, field_value] : + cast(*st).Fields()) { field_types.push_back({.name = field_name, .value = field_value}); } - auto fun_ty = Value::MakeFunctionType( - {}, Value::MakeTupleValue(std::move(field_types)), st); + auto fun_ty = global_arena->New( + std::vector(), + global_arena->New(std::move(field_types)), st); tops->types.Set(struct_def.name, fun_ty); break; } @@ -991,7 +1016,7 @@ static void TopLevel(const Declaration& d, TypeCheckContext* tops) { auto t = InterpExp(tops->values, signature); alts.push_back(std::make_pair(name, t)); } - auto ct = Value::MakeChoiceType(choice.name, std::move(alts)); + auto ct = global_arena->New(choice.name, std::move(alts)); Address a = state->heap.AllocateValue(ct); tops->values.Set(choice.name, a); // Is this obsolete? tops->types.Set(choice.name, ct); diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index 86bbc8022235..8afd86b1944d 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -10,70 +10,11 @@ #include "executable_semantics/common/arena.h" #include "executable_semantics/common/error.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Casting.h" namespace Carbon { -auto Value::GetIntValue() const -> int { - return std::get(value).value; -} - -auto Value::GetBoolValue() const -> bool { - return std::get(value).value; -} - -auto Value::GetFunctionValue() const -> const FunctionValue& { - return std::get(value); -} - -auto Value::GetStructValue() const -> const StructValue& { - return std::get(value); -} - -auto Value::GetAlternativeConstructorValue() const - -> const AlternativeConstructorValue& { - return std::get(value); -} - -auto Value::GetAlternativeValue() const -> const AlternativeValue& { - return std::get(value); -} - -auto Value::GetTupleValue() const -> const TupleValue& { - return std::get(value); -} - -auto Value::GetPointerValue() const -> Address { - return std::get(value).value; -} - -auto Value::GetBindingPlaceholderValue() const - -> const BindingPlaceholderValue& { - return std::get(value); -} - -auto Value::GetFunctionType() const -> const FunctionType& { - return std::get(value); -} - -auto Value::GetPointerType() const -> const PointerType& { - return std::get(value); -} - -auto Value::GetStructType() const -> const StructType& { - return std::get(value); -} - -auto Value::GetChoiceType() const -> const ChoiceType& { - return std::get(value); -} - -auto Value::GetVariableType() const -> const VariableType& { - return std::get(value); -} - -auto Value::GetContinuationValue() const -> const ContinuationValue& { - return std::get(value); -} +using llvm::cast; auto FindInVarValues(const std::string& field, const VarValues& inits) -> const Value* { @@ -111,178 +52,33 @@ auto TupleValue::FindField(const std::string& name) const -> const Value* { return nullptr; } -auto Value::MakeIntValue(int i) -> const Value* { - auto* v = global_arena->New(); - v->value = IntValue({.value = i}); - return v; -} - -auto Value::MakeBoolValue(bool b) -> const Value* { - auto* v = global_arena->New(); - v->value = BoolValue({.value = b}); - return v; -} - -auto Value::MakeFunctionValue(std::string name, const Value* param, - const Statement* body) -> const Value* { - auto* v = global_arena->New(); - v->value = - FunctionValue({.name = std::move(name), .param = param, .body = body}); - return v; -} - -auto Value::MakePointerValue(Address addr) -> const Value* { - auto* v = global_arena->New(); - v->value = PointerValue({.value = addr}); - return v; -} - -auto Value::MakeStructValue(const Value* type, const Value* inits) - -> const Value* { - auto* v = global_arena->New(); - v->value = StructValue({.type = type, .inits = inits}); - return v; -} - -auto Value::MakeTupleValue(std::vector elements) -> const Value* { - auto* v = global_arena->New(); - v->value = TupleValue({.elements = std::move(elements)}); - return v; -} - -auto Value::MakeAlternativeValue(std::string alt_name, std::string choice_name, - const Value* argument) -> const Value* { - auto* v = global_arena->New(); - v->value = AlternativeValue({.alt_name = std::move(alt_name), - .choice_name = std::move(choice_name), - .argument = argument}); - return v; -} - -auto Value::MakeAlternativeConstructorValue(std::string alt_name, - std::string choice_name) - -> const Value* { - auto* v = global_arena->New(); - v->value = AlternativeConstructorValue( - {.alt_name = std::move(alt_name), .choice_name = std::move(choice_name)}); - return v; -} - -// Return a first-class continuation represented a fragment -// of the stack. -auto Value::MakeContinuationValue(std::vector stack) -> Value* { - auto* v = global_arena->New(); - v->value = ContinuationValue({.stack = std::move(stack)}); - return v; -} - -auto Value::MakeBindingPlaceholderValue(std::optional name, - const Value* type) -> const Value* { - auto* v = global_arena->New(); - v->value = BindingPlaceholderValue({.name = std::move(name), .type = type}); - return v; -} - -auto Value::MakeIntType() -> const Value* { - auto* v = global_arena->New(); - v->value = IntType(); - return v; -} - -auto Value::MakeBoolType() -> const Value* { - auto* v = global_arena->New(); - v->value = BoolType(); - return v; -} - -auto Value::MakeTypeType() -> const Value* { - auto* v = global_arena->New(); - v->value = TypeType(); - return v; -} - -// Return a Continuation type. -auto Value::MakeContinuationType() -> const Value* { - auto* v = global_arena->New(); - v->value = ContinuationType(); - return v; -} - -auto Value::MakeAutoType() -> const Value* { - auto* v = global_arena->New(); - v->value = AutoType(); - return v; -} - -auto Value::MakeFunctionType(std::vector deduced_params, - const Value* param, const Value* ret) - -> const Value* { - auto* v = global_arena->New(); - v->value = FunctionType( - {.deduced = std::move(deduced_params), .param = param, .ret = ret}); - return v; -} - -auto Value::MakePointerType(const Value* type) -> const Value* { - auto* v = global_arena->New(); - v->value = PointerType({.type = type}); - return v; -} - -auto Value::MakeStructType(std::string name, VarValues fields, - VarValues methods) -> const Value* { - auto* v = global_arena->New(); - v->value = StructType({.name = std::move(name), - .fields = std::move(fields), - .methods = std::move(methods)}); - return v; -} - -auto Value::MakeUnitTypeVal() -> const Value* { - auto* v = global_arena->New(); - v->value = TupleValue({.elements = {}}); - return v; -} - -auto Value::MakeChoiceType(std::string name, VarValues alts) -> const Value* { - auto* v = global_arena->New(); - v->value = - ChoiceType({.name = std::move(name), .alternatives = std::move(alts)}); - return v; -} - -auto Value::MakeVariableType(std::string name) -> const Value* { - auto* v = global_arena->New(); - v->value = VariableType({.name = std::move(name)}); - return v; -} - namespace { auto GetMember(const Value* v, const std::string& f, int line_num) -> const Value* { - switch (v->tag()) { - case ValKind::StructValue: { + switch (v->Tag()) { + case Value::Kind::StructValue: { const Value* field = - v->GetStructValue().inits->GetTupleValue().FindField(f); + cast(*cast(*v).Inits()).FindField(f); if (field == nullptr) { FATAL_RUNTIME_ERROR(line_num) << "member " << f << " not in " << *v; } return field; } - case ValKind::TupleValue: { - const Value* field = v->GetTupleValue().FindField(f); + case Value::Kind::TupleValue: { + const Value* field = cast(*v).FindField(f); if (field == nullptr) { FATAL_RUNTIME_ERROR(line_num) << "field " << f << " not in " << *v; } return field; } - case ValKind::ChoiceType: { - if (FindInVarValues(f, v->GetChoiceType().alternatives) == nullptr) { + case Value::Kind::ChoiceType: { + const auto& choice = cast(*v); + if (FindInVarValues(f, choice.Alternatives()) == nullptr) { FATAL_RUNTIME_ERROR(line_num) << "alternative " << f << " not in " << *v; } - return Value::MakeAlternativeConstructorValue(f, v->GetChoiceType().name); + return global_arena->New(f, choice.Name()); } default: llvm::errs() << "field access not allowed for value " << *v << "\n"; @@ -310,13 +106,13 @@ auto SetFieldImpl(const Value* value, if (path_begin == path_end) { return field_value; } - switch (value->tag()) { - case ValKind::StructValue: { - return SetFieldImpl(value->GetStructValue().inits, path_begin, path_end, - field_value, line_num); + switch (value->Tag()) { + case Value::Kind::StructValue: { + return SetFieldImpl(cast(*value).Inits(), path_begin, + path_end, field_value, line_num); } - case ValKind::TupleValue: { - std::vector elements = value->GetTupleValue().elements; + case Value::Kind::TupleValue: { + std::vector elements = cast(*value).Elements(); auto it = std::find_if(elements.begin(), elements.end(), [path_begin](const TupleElement& element) { return element.name == *path_begin; @@ -327,7 +123,7 @@ auto SetFieldImpl(const Value* value, } it->value = SetFieldImpl(it->value, path_begin + 1, path_end, field_value, line_num); - return Value::MakeTupleValue(elements); + return global_arena->New(elements); } default: llvm::errs() << "field access not allowed for value " << *value << "\n"; @@ -344,78 +140,79 @@ auto Value::SetField(const FieldPath& path, const Value* field_value, } void Value::Print(llvm::raw_ostream& out) const { - switch (tag()) { - case ValKind::AlternativeConstructorValue: { - out << GetAlternativeConstructorValue().choice_name << "." - << GetAlternativeConstructorValue().alt_name; + switch (Tag()) { + case Value::Kind::AlternativeConstructorValue: { + const auto& alt = cast(*this); + out << alt.ChoiceName() << "." << alt.AltName(); break; } - case ValKind::BindingPlaceholderValue: { - const BindingPlaceholderValue& placeholder = GetBindingPlaceholderValue(); - if (placeholder.name.has_value()) { - out << *placeholder.name; + case Value::Kind::BindingPlaceholderValue: { + const auto& placeholder = cast(*this); + if (placeholder.Name().has_value()) { + out << *placeholder.Name(); } else { out << "_"; } - out << ": " << *placeholder.type; + out << ": " << *placeholder.Type(); break; } - case ValKind::AlternativeValue: { - out << "alt " << GetAlternativeValue().choice_name << "." - << GetAlternativeValue().alt_name << " " - << *GetAlternativeValue().argument; + case Value::Kind::AlternativeValue: { + const auto& alt = cast(*this); + out << "alt " << alt.ChoiceName() << "." << alt.AltName() << " " + << *alt.Argument(); break; } - case ValKind::StructValue: { - out << GetStructValue().type->GetStructType().name - << *GetStructValue().inits; + case Value::Kind::StructValue: { + const auto& s = cast(*this); + out << cast(*s.Type()).Name() << *s.Inits(); break; } - case ValKind::TupleValue: { + case Value::Kind::TupleValue: { out << "("; llvm::ListSeparator sep; - for (const TupleElement& element : GetTupleValue().elements) { + for (const TupleElement& element : cast(*this).Elements()) { out << sep << element.name << " = " << *element.value; } out << ")"; break; } - case ValKind::IntValue: - out << GetIntValue(); + case Value::Kind::IntValue: + out << cast(*this).Val(); break; - case ValKind::BoolValue: - out << (GetBoolValue() ? "true" : "false"); + case Value::Kind::BoolValue: + out << (cast(*this).Val() ? "true" : "false"); break; - case ValKind::FunctionValue: - out << "fun<" << GetFunctionValue().name << ">"; + case Value::Kind::FunctionValue: + out << "fun<" << cast(*this).Name() << ">"; break; - case ValKind::PointerValue: - out << "ptr<" << GetPointerValue() << ">"; + case Value::Kind::PointerValue: + out << "ptr<" << cast(*this).Val() << ">"; break; - case ValKind::BoolType: + case Value::Kind::BoolType: out << "Bool"; break; - case ValKind::IntType: + case Value::Kind::IntType: out << "Int"; break; - case ValKind::TypeType: + case Value::Kind::TypeType: out << "Type"; break; - case ValKind::AutoType: + case Value::Kind::AutoType: out << "auto"; break; - case ValKind::ContinuationType: + case Value::Kind::ContinuationType: out << "Continuation"; break; - case ValKind::PointerType: - out << *GetPointerType().type << "*"; + case Value::Kind::PointerType: + out << *cast(*this).Type() << "*"; break; - case ValKind::FunctionType: + case Value::Kind::FunctionType: { + const auto& fn_type = cast(*this); out << "fn "; - if (GetFunctionType().deduced.size() > 0) { + if (fn_type.Deduced().size() > 0) { out << "["; unsigned int i = 0; - for (const auto& deduced : GetFunctionType().deduced) { + for (const auto& deduced : fn_type.Deduced()) { if (i != 0) { out << ", "; } @@ -424,18 +221,19 @@ void Value::Print(llvm::raw_ostream& out) const { } out << "]"; } - out << *GetFunctionType().param << " -> " << *GetFunctionType().ret; + out << *fn_type.Param() << " -> " << *fn_type.Ret(); break; - case ValKind::StructType: - out << "struct " << GetStructType().name; + } + case Value::Kind::StructType: + out << "struct " << cast(*this).Name(); break; - case ValKind::ChoiceType: - out << "choice " << GetChoiceType().name; + case Value::Kind::ChoiceType: + out << "choice " << cast(*this).Name(); break; - case ValKind::VariableType: - out << GetVariableType().name; + case Value::Kind::VariableType: + out << cast(*this).Name(); break; - case ValKind::ContinuationValue: + case Value::Kind::ContinuationValue: out << "continuation"; // TODO: Find a way to print useful information about the continuation // without creating a dependency cycle. @@ -444,106 +242,108 @@ void Value::Print(llvm::raw_ostream& out) const { } auto CopyVal(const Value* val, int line_num) -> const Value* { - switch (val->tag()) { - case ValKind::TupleValue: { + switch (val->Tag()) { + case Value::Kind::TupleValue: { std::vector elements; - for (const TupleElement& element : val->GetTupleValue().elements) { + for (const TupleElement& element : cast(*val).Elements()) { elements.push_back( {.name = element.name, .value = CopyVal(element.value, line_num)}); } - return Value::MakeTupleValue(std::move(elements)); + return global_arena->New(std::move(elements)); } - case ValKind::AlternativeValue: { - const Value* arg = CopyVal(val->GetAlternativeValue().argument, line_num); - return Value::MakeAlternativeValue(val->GetAlternativeValue().alt_name, - val->GetAlternativeValue().choice_name, - arg); + case Value::Kind::AlternativeValue: { + const auto& alt = cast(*val); + const Value* arg = CopyVal(alt.Argument(), line_num); + return global_arena->New(alt.AltName(), + alt.ChoiceName(), arg); } - case ValKind::StructValue: { - const Value* inits = CopyVal(val->GetStructValue().inits, line_num); - return Value::MakeStructValue(val->GetStructValue().type, inits); + case Value::Kind::StructValue: { + const auto& s = cast(*val); + const Value* inits = CopyVal(s.Inits(), line_num); + return global_arena->New(s.Type(), inits); } - case ValKind::IntValue: - return Value::MakeIntValue(val->GetIntValue()); - case ValKind::BoolValue: - return Value::MakeBoolValue(val->GetBoolValue()); - case ValKind::FunctionValue: - return Value::MakeFunctionValue(val->GetFunctionValue().name, - val->GetFunctionValue().param, - val->GetFunctionValue().body); - case ValKind::PointerValue: - return Value::MakePointerValue(val->GetPointerValue()); - case ValKind::ContinuationValue: + case Value::Kind::IntValue: + return global_arena->New(cast(*val).Val()); + case Value::Kind::BoolValue: + return global_arena->New(cast(*val).Val()); + case Value::Kind::FunctionValue: { + const auto& fn_value = cast(*val); + return global_arena->New(fn_value.Name(), fn_value.Param(), + fn_value.Body()); + } + case Value::Kind::PointerValue: + return global_arena->New(cast(*val).Val()); + case Value::Kind::ContinuationValue: // Copying a continuation is "shallow". return val; - case ValKind::FunctionType: - return Value::MakeFunctionType( - val->GetFunctionType().deduced, - CopyVal(val->GetFunctionType().param, line_num), - CopyVal(val->GetFunctionType().ret, line_num)); - - case ValKind::PointerType: - return Value::MakePointerType( - CopyVal(val->GetPointerType().type, line_num)); - case ValKind::IntType: - return Value::MakeIntType(); - case ValKind::BoolType: - return Value::MakeBoolType(); - case ValKind::TypeType: - return Value::MakeTypeType(); - case ValKind::AutoType: - return Value::MakeAutoType(); - case ValKind::ContinuationType: - return Value::MakeContinuationType(); - case ValKind::VariableType: - case ValKind::StructType: - case ValKind::ChoiceType: - case ValKind::BindingPlaceholderValue: - case ValKind::AlternativeConstructorValue: + case Value::Kind::FunctionType: { + const auto& fn_type = cast(*val); + return global_arena->New(fn_type.Deduced(), + CopyVal(fn_type.Param(), line_num), + CopyVal(fn_type.Ret(), line_num)); + } + case Value::Kind::PointerType: + return global_arena->New( + CopyVal(cast(*val).Type(), line_num)); + case Value::Kind::IntType: + return global_arena->New(); + case Value::Kind::BoolType: + return global_arena->New(); + case Value::Kind::TypeType: + return global_arena->New(); + case Value::Kind::AutoType: + return global_arena->New(); + case Value::Kind::ContinuationType: + return global_arena->New(); + case Value::Kind::VariableType: + case Value::Kind::StructType: + case Value::Kind::ChoiceType: + case Value::Kind::BindingPlaceholderValue: + case Value::Kind::AlternativeConstructorValue: // TODO: These should be copied so that they don't get destructed. return val; } } auto TypeEqual(const Value* t1, const Value* t2) -> bool { - if (t1->tag() != t2->tag()) { + if (t1->Tag() != t2->Tag()) { return false; } - switch (t1->tag()) { - case ValKind::PointerType: - return TypeEqual(t1->GetPointerType().type, t2->GetPointerType().type); - case ValKind::FunctionType: - return TypeEqual(t1->GetFunctionType().param, - t2->GetFunctionType().param) && - TypeEqual(t1->GetFunctionType().ret, t2->GetFunctionType().ret); - case ValKind::StructType: - return t1->GetStructType().name == t2->GetStructType().name; - case ValKind::ChoiceType: - return t1->GetChoiceType().name == t2->GetChoiceType().name; - case ValKind::TupleValue: { - if (t1->GetTupleValue().elements.size() != - t2->GetTupleValue().elements.size()) { + switch (t1->Tag()) { + case Value::Kind::PointerType: + return TypeEqual(cast(*t1).Type(), + cast(*t2).Type()); + case Value::Kind::FunctionType: { + const auto& fn1 = cast(*t1); + const auto& fn2 = cast(*t2); + return TypeEqual(fn1.Param(), fn2.Param()) && + TypeEqual(fn1.Ret(), fn2.Ret()); + } + case Value::Kind::StructType: + return cast(*t1).Name() == cast(*t2).Name(); + case Value::Kind::ChoiceType: + return cast(*t1).Name() == cast(*t2).Name(); + case Value::Kind::TupleValue: { + const auto& tup1 = cast(*t1); + const auto& tup2 = cast(*t2); + if (tup1.Elements().size() != tup2.Elements().size()) { return false; } - for (size_t i = 0; i < t1->GetTupleValue().elements.size(); ++i) { - if (t1->GetTupleValue().elements[i].name != - t2->GetTupleValue().elements[i].name) { - return false; - } - if (!TypeEqual(t1->GetTupleValue().elements[i].value, - t2->GetTupleValue().elements[i].value)) { + for (size_t i = 0; i < tup1.Elements().size(); ++i) { + if (tup1.Elements()[i].name != tup2.Elements()[i].name || + !TypeEqual(tup1.Elements()[i].value, tup2.Elements()[i].value)) { return false; } } return true; } - case ValKind::IntType: - case ValKind::BoolType: - case ValKind::ContinuationType: - case ValKind::TypeType: + case Value::Kind::IntType: + case Value::Kind::BoolType: + case Value::Kind::ContinuationType: + case Value::Kind::TypeType: return true; - case ValKind::VariableType: - return t1->GetVariableType().name == t2->GetVariableType().name; + case Value::Kind::VariableType: + return cast(*t1).Name() == cast(*t2).Name(); default: llvm::errs() << "TypeEqual used to compare non-type values\n" << *t1 << "\n" @@ -578,37 +378,37 @@ static auto FieldsValueEqual(const std::vector& ts1, // // This function implements the `==` operator of Carbon. auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool { - if (v1->tag() != v2->tag()) { + if (v1->Tag() != v2->Tag()) { return false; } - switch (v1->tag()) { - case ValKind::IntValue: - return v1->GetIntValue() == v2->GetIntValue(); - case ValKind::BoolValue: - return v1->GetBoolValue() == v2->GetBoolValue(); - case ValKind::PointerValue: - return v1->GetPointerValue() == v2->GetPointerValue(); - case ValKind::FunctionValue: - return v1->GetFunctionValue().body == v2->GetFunctionValue().body; - case ValKind::TupleValue: - return FieldsValueEqual(v1->GetTupleValue().elements, - v2->GetTupleValue().elements, line_num); + switch (v1->Tag()) { + case Value::Kind::IntValue: + return cast(*v1).Val() == cast(*v2).Val(); + case Value::Kind::BoolValue: + return cast(*v1).Val() == cast(*v2).Val(); + case Value::Kind::PointerValue: + return cast(*v1).Val() == cast(*v2).Val(); + case Value::Kind::FunctionValue: + return cast(*v1).Body() == cast(*v2).Body(); + case Value::Kind::TupleValue: + return FieldsValueEqual(cast(*v1).Elements(), + cast(*v2).Elements(), line_num); default: - case ValKind::IntType: - case ValKind::BoolType: - case ValKind::TypeType: - case ValKind::FunctionType: - case ValKind::PointerType: - case ValKind::AutoType: - case ValKind::StructType: - case ValKind::ChoiceType: - case ValKind::ContinuationType: + case Value::Kind::IntType: + case Value::Kind::BoolType: + case Value::Kind::TypeType: + case Value::Kind::FunctionType: + case Value::Kind::PointerType: + case Value::Kind::AutoType: + case Value::Kind::StructType: + case Value::Kind::ChoiceType: + case Value::Kind::ContinuationType: return TypeEqual(v1, v2); - case ValKind::StructValue: - case ValKind::AlternativeValue: - case ValKind::BindingPlaceholderValue: - case ValKind::AlternativeConstructorValue: - case ValKind::ContinuationValue: + case Value::Kind::StructValue: + case Value::Kind::AlternativeValue: + case Value::Kind::BindingPlaceholderValue: + case Value::Kind::AlternativeConstructorValue: + case Value::Kind::ContinuationValue: llvm::errs() << "ValueEqual does not support this kind of value.\n"; exit(-1); } diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h index d545cbdf6c6b..b4a755986f29 100644 --- a/executable_semantics/interpreter/value.h +++ b/executable_semantics/interpreter/value.h @@ -21,7 +21,67 @@ namespace Carbon { -struct Value; +// Abstract base class of all AST nodes representing values. +// +// Value and its derived classes support LLVM-style RTTI, including +// llvm::isa, llvm::cast, and llvm::dyn_cast. To support this, every +// class derived from Value must provide a `classof` operation, and +// every concrete derived class must have a corresponding enumerator +// in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for +// details. +class Value { + public: + enum class Kind { + IntValue, + FunctionValue, + PointerValue, + BoolValue, + StructValue, + AlternativeValue, + TupleValue, + IntType, + BoolType, + TypeType, + FunctionType, + PointerType, + AutoType, + StructType, + ChoiceType, + ContinuationType, // The type of a continuation. + VariableType, // e.g. generic type parameters + BindingPlaceholderValue, + AlternativeConstructorValue, + ContinuationValue // A first-class continuation value. + }; + + Value(const Value&) = delete; + Value& operator=(const Value&) = delete; + + // Returns the enumerator corresponding to the most-derived type of this + // object. + auto Tag() const -> Kind { return tag; } + + void Print(llvm::raw_ostream& out) const; + LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); } + + // Returns the sub-Value specified by `path`, which must be a valid field + // path for *this. + auto GetField(const FieldPath& path, int line_num) const -> 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, + int line_num) const -> const Value*; + + protected: + // Constructs a Value. `tag` must be the enumerator corresponding to the + // most-derived type being constructed. + explicit Value(Kind tag) : tag(tag) {} + + private: + const Kind tag; +}; + using VarValues = std::list>; auto FindInVarValues(const std::string& field, const VarValues& inits) @@ -37,221 +97,343 @@ struct TupleElement { const Value* value; }; -enum class ValKind { - IntValue, - FunctionValue, - PointerValue, - BoolValue, - StructValue, - AlternativeValue, - TupleValue, - IntType, - BoolType, - TypeType, - FunctionType, - PointerType, - AutoType, - StructType, - ChoiceType, - ContinuationType, // The type of a continuation. - VariableType, // e.g. generic type parameters - BindingPlaceholderValue, - AlternativeConstructorValue, - ContinuationValue // A first-class continuation value. +struct Frame; // Used by continuation. + +// An integer value. +class IntValue : public Value { + public: + explicit IntValue(int val) : Value(Kind::IntValue), val(val) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::IntValue; + } + + auto Val() const -> int { return val; } + + private: + int val; }; -struct Frame; // used by continuation +// A function value. +class FunctionValue : public Value { + public: + FunctionValue(std::string name, const Value* param, const Statement* body) + : Value(Kind::FunctionValue), + name(std::move(name)), + param(param), + body(body) {} -struct IntValue { - static constexpr ValKind Kind = ValKind::IntValue; - int value; -}; + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::FunctionValue; + } -struct FunctionValue { - static constexpr ValKind Kind = ValKind::FunctionValue; + auto Name() const -> const std::string& { return name; } + auto Param() const -> const Value* { return param; } + auto Body() const -> const Statement* { return body; } + + private: std::string name; const Value* param; const Statement* body; }; -struct PointerValue { - static constexpr ValKind Kind = ValKind::PointerValue; - Address value; +// A pointer value. +class PointerValue : public Value { + public: + explicit PointerValue(Address val) + : Value(Kind::PointerValue), val(std::move(val)) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::PointerValue; + } + + auto Val() const -> const Address& { return val; } + + private: + Address val; }; -struct BoolValue { - static constexpr ValKind Kind = ValKind::BoolValue; - bool value; +// A bool value. +class BoolValue : public Value { + public: + explicit BoolValue(bool val) : Value(Kind::BoolValue), val(val) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::BoolValue; + } + + auto Val() const -> bool { return val; } + + private: + bool val; }; -struct StructValue { - static constexpr ValKind Kind = ValKind::StructValue; +// A function value. +class StructValue : public Value { + public: + StructValue(const Value* type, 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; } + + private: const Value* type; const Value* inits; }; -struct AlternativeConstructorValue { - static constexpr ValKind Kind = ValKind::AlternativeConstructorValue; +// An alternative constructor value. +class AlternativeConstructorValue : public Value { + public: + AlternativeConstructorValue(std::string alt_name, std::string choice_name) + : Value(Kind::AlternativeConstructorValue), + alt_name(std::move(alt_name)), + choice_name(std::move(choice_name)) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::AlternativeConstructorValue; + } + + auto AltName() const -> const std::string& { return alt_name; } + auto ChoiceName() const -> const std::string& { return choice_name; } + + private: std::string alt_name; std::string choice_name; }; -struct AlternativeValue { - static constexpr ValKind Kind = ValKind::AlternativeValue; +// An alternative value. +class AlternativeValue : public Value { + public: + AlternativeValue(std::string alt_name, std::string choice_name, + const Value* argument) + : Value(Kind::AlternativeValue), + alt_name(std::move(alt_name)), + choice_name(std::move(choice_name)), + argument(argument) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::AlternativeValue; + } + + 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; } + + private: std::string alt_name; std::string choice_name; const Value* argument; }; -struct TupleValue { - static constexpr ValKind Kind = ValKind::TupleValue; - std::vector elements; +// A function value. +class TupleValue : public Value { + public: + explicit TupleValue(std::vector elements) + : Value(Kind::TupleValue), elements(std::move(elements)) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::TupleValue; + } + + 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*; + + private: + std::vector elements; }; -struct BindingPlaceholderValue { - static constexpr ValKind Kind = ValKind::BindingPlaceholderValue; - // nullopt represents the `_` placeholder +// A binding placeholder value. +class BindingPlaceholderValue : public Value { + public: + // nullopt represents the `_` placeholder. + BindingPlaceholderValue(std::optional name, const Value* type) + : Value(Kind::BindingPlaceholderValue), + name(std::move(name)), + type(type) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::BindingPlaceholderValue; + } + + auto Name() const -> const std::optional& { return name; } + auto Type() const -> const Value* { return type; } + + private: std::optional name; const Value* type; }; -struct IntType { - static constexpr ValKind Kind = ValKind::IntType; +// The int type. +class IntType : public Value { + public: + IntType() : Value(Kind::IntType) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::IntType; + } }; -struct BoolType { - static constexpr ValKind Kind = ValKind::BoolType; +// The bool type. +class BoolType : public Value { + public: + BoolType() : Value(Kind::BoolType) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::BoolType; + } }; -struct TypeType { - static constexpr ValKind Kind = ValKind::TypeType; +// A type type. +class TypeType : public Value { + public: + TypeType() : Value(Kind::TypeType) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::TypeType; + } }; -struct FunctionType { - static constexpr ValKind Kind = ValKind::FunctionType; +// A function type. +class FunctionType : public Value { + public: + FunctionType(std::vector deduced, const Value* param, + const Value* ret) + : Value(Kind::FunctionType), + deduced(std::move(deduced)), + param(param), + ret(ret) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::FunctionType; + } + + auto Deduced() const -> const std::vector& { return deduced; } + auto Param() const -> const Value* { return param; } + auto Ret() const -> const Value* { return ret; } + + private: std::vector deduced; const Value* param; const Value* ret; }; -struct PointerType { - static constexpr ValKind Kind = ValKind::PointerType; +// A pointer type. +class PointerType : public Value { + public: + explicit PointerType(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; } + + private: const Value* type; }; -struct AutoType { - static constexpr ValKind Kind = ValKind::AutoType; +// The `auto` type. +class AutoType : public Value { + public: + AutoType() : Value(Kind::AutoType) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::AutoType; + } }; -struct StructType { - static constexpr ValKind Kind = ValKind::StructType; +// A struct type. +class StructType : public Value { + public: + StructType(std::string name, VarValues fields, VarValues methods) + : Value(Kind::StructType), + name(std::move(name)), + fields(std::move(fields)), + methods(std::move(methods)) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::StructType; + } + + auto Name() const -> const std::string& { return name; } + auto Fields() const -> const VarValues& { return fields; } + auto Methods() const -> const VarValues& { return methods; } + + private: std::string name; VarValues fields; VarValues methods; }; -struct ChoiceType { - static constexpr ValKind Kind = ValKind::ChoiceType; +// A choice type. +class ChoiceType : public Value { + public: + ChoiceType(std::string name, VarValues alternatives) + : Value(Kind::ChoiceType), + name(std::move(name)), + alternatives(std::move(alternatives)) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::ChoiceType; + } + + auto Name() const -> const std::string& { return name; } + auto Alternatives() const -> const VarValues& { return alternatives; } + + private: std::string name; VarValues alternatives; }; -struct ContinuationType { - static constexpr ValKind Kind = ValKind::ContinuationType; +// A continuation type. +class ContinuationType : public Value { + public: + ContinuationType() : Value(Kind::ContinuationType) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::ContinuationType; + } }; -struct VariableType { - static constexpr ValKind Kind = ValKind::VariableType; +// A variable type. +class VariableType : public Value { + public: + explicit VariableType(std::string name) + : Value(Kind::VariableType), name(std::move(name)) {} + + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::VariableType; + } + + auto Name() const -> const std::string& { return name; } + + private: std::string name; }; -struct ContinuationValue { - static constexpr ValKind Kind = ValKind::ContinuationValue; - std::vector stack; -}; +// A first-class continuation representation of a fragment of the stack. +class ContinuationValue : public Value { + public: + explicit ContinuationValue(std::vector stack) + : Value(Kind::ContinuationValue), stack(std::move(stack)) {} -struct Value { - // Constructors - - // Return a first-class continuation represented by the - // given stack, down to the nearest enclosing `__continuation`. - static auto MakeContinuationValue(std::vector stack) -> Value*; - static auto MakeIntValue(int i) -> const Value*; - static auto MakeBoolValue(bool b) -> const Value*; - static auto MakeFunctionValue(std::string name, const Value* param, - const Statement* body) -> const Value*; - static auto MakePointerValue(Address addr) -> const Value*; - static auto MakeStructValue(const Value* type, const Value* inits) - -> const Value*; - static auto MakeTupleValue(std::vector elts) -> const Value*; - static auto MakeAlternativeValue(std::string alt_name, - std::string choice_name, - const Value* argument) -> const Value*; - static auto MakeAlternativeConstructorValue(std::string alt_name, - std::string choice_name) - -> const Value*; - static auto MakeBindingPlaceholderValue(std::optional name, - const Value* type) -> const Value*; - static auto MakeIntType() -> const Value*; - static auto MakeContinuationType() -> const Value*; - static auto MakeAutoType() -> const Value*; - static auto MakeBoolType() -> const Value*; - static auto MakeTypeType() -> const Value*; - static auto MakeFunctionType(std::vector deduced_params, - const Value* param, const Value* ret) - -> const Value*; - static auto MakePointerType(const Value* type) -> const Value*; - static auto MakeStructType(std::string name, VarValues fields, - VarValues methods) -> const Value*; - static auto MakeUnitTypeVal() -> const Value*; - static auto MakeChoiceType(std::string name, VarValues alts) -> const Value*; - static auto MakeVariableType(std::string name) -> const Value*; - - // Access to alternatives - auto GetIntValue() const -> int; - auto GetBoolValue() const -> bool; - auto GetFunctionValue() const -> const FunctionValue&; - auto GetStructValue() const -> const StructValue&; - auto GetAlternativeConstructorValue() const - -> const AlternativeConstructorValue&; - auto GetAlternativeValue() const -> const AlternativeValue&; - auto GetTupleValue() const -> const TupleValue&; - auto GetPointerValue() const -> Address; - auto GetBindingPlaceholderValue() const -> const BindingPlaceholderValue&; - auto GetFunctionType() const -> const FunctionType&; - auto GetPointerType() const -> const PointerType&; - auto GetStructType() const -> const StructType&; - auto GetChoiceType() const -> const ChoiceType&; - auto GetVariableType() const -> const VariableType&; - auto GetContinuationValue() const -> const ContinuationValue&; - - inline auto tag() const -> ValKind { - return std::visit([](const auto& t) { return t.Kind; }, value); + static auto classof(const Value* value) -> bool { + return value->Tag() == Kind::ContinuationValue; } - // Returns the sub-Value specified by `path`, which must be a valid field - // path for *this. - auto GetField(const FieldPath& path, int line_num) const -> 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, - int line_num) const -> const Value*; - - void Print(llvm::raw_ostream& out) const; - LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); } + auto Stack() const -> const std::vector& { return stack; } private: - std::variant - value; + std::vector stack; }; auto CopyVal(const Value* val, int line_num) -> const Value*;