Switch Value to Ptr (#799)

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