diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 83d8dab897bc..67b96009d48d 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -759,8 +759,7 @@ void StepPattern() { if (act->pos == 0) { if (tuple.Fields().empty()) { frame->todo.Pop(1); - frame->todo.Push(Action::MakeValAction( - global_arena->New(std::vector()))); + frame->todo.Push(Action::MakeValAction(&TupleValue::Empty())); } else { const Pattern* p1 = tuple.Fields()[0].pattern; frame->todo.Push(Action::MakePatternAction(p1)); diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index 88866d39bcff..632d31899fa6 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/executable_semantics/interpreter/typecheck.cpp @@ -855,8 +855,7 @@ auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, Env values) // 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, global_arena->New(std::vector())); + bool void_return = TypeEqual(return_type, &TupleValue::Empty()); 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, diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h index b4a755986f29..8598e4c5da00 100644 --- a/executable_semantics/interpreter/value.h +++ b/executable_semantics/interpreter/value.h @@ -233,6 +233,12 @@ class AlternativeValue : public Value { // A function value. class TupleValue : public Value { public: + // An empty tuple, also known as the unit type. + static const TupleValue& Empty() { + static const TupleValue empty = TupleValue(std::vector()); + return empty; + } + explicit TupleValue(std::vector elements) : Value(Kind::TupleValue), elements(std::move(elements)) {}