Skip to content

Commit

Permalink
Use As and ImplicitAs interfaces for conversions. (carbon-languag…
Browse files Browse the repository at this point in the history
…e#4209)

Add these interfaces to the core library. For now, they're two separate
interfaces because we don't yet support one interface extending another.

This collapses a lot of the layering in check: for example, the call
building logic depends on implicit conversions, conversions now depend
on the overloaded operator machinery, and that machinery depends on
building calls.

In passing, improve the diagnostics for failing to find a name required
from the prelude. Also convert all the transitively-called code from
`NodeId` to `LocId` given the latter is what the conversion machinery
has available.

---------

Co-authored-by: Jon Ross-Perkins <[email protected]>
  • Loading branch information
zygoloid and jonmeow authored Sep 5, 2024
1 parent 2d650f7 commit 187a360
Show file tree
Hide file tree
Showing 466 changed files with 6,527 additions and 880 deletions.
2 changes: 2 additions & 0 deletions common/check_internal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ ExitingStream::~ExitingStream() {

auto ExitingStream::Done() -> void {
buffer_ << "\n";
buffer_.flush();

// Register another signal handler to print the buffered message. This is
// because we want it at the bottom of output, after LLVM's builtin stack
// output, rather than the top.
Expand Down
1 change: 1 addition & 0 deletions core/prelude/operators.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
package Core library "prelude/operators";

export import library "prelude/operators/arithmetic";
export import library "prelude/operators/as";
export import library "prelude/operators/bitwise";
export import library "prelude/operators/comparison";
14 changes: 14 additions & 0 deletions core/prelude/operators/as.carbon
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

package Core library "prelude/operators/as";

interface As(Dest:! type) {
fn Convert[self: Self]() -> Dest;
}

interface ImplicitAs(Dest:! type) {
// TODO: extend As(Dest);
fn Convert[self: Self]() -> Dest;
}
58 changes: 6 additions & 52 deletions toolchain/check/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ filegroup(
cc_library(
name = "context",
srcs = [
"call.cpp",
"context.cpp",
"convert.cpp",
"decl_name_stack.cpp",
Expand All @@ -26,13 +27,16 @@ cc_library(
"import.cpp",
"import_ref.cpp",
"inst_block_stack.cpp",
"member_access.cpp",
"merge.cpp",
"modifiers.cpp",
"name_component.cpp",
"operator.cpp",
"return.cpp",
"subst.cpp",
],
hdrs = [
"call.h",
"context.h",
"convert.h",
"decl_introducer_state.h",
Expand All @@ -47,9 +51,11 @@ cc_library(
"import_ref.h",
"inst_block_stack.h",
"keyword_modifier_set.h",
"member_access.h",
"merge.h",
"modifiers.h",
"name_component.h",
"operator.h",
"param_and_arg_refs_stack.h",
"pending_block.h",
"return.h",
Expand Down Expand Up @@ -93,12 +99,9 @@ cc_library(
]),
hdrs = ["check.h"],
deps = [
":call",
":context",
":impl",
":interface",
":member_access",
":operator",
":pointer_dereference",
":sem_ir_diagnostic_converter",
"//common:check",
Expand Down Expand Up @@ -139,21 +142,6 @@ cc_fuzz_test(
],
)

cc_library(
name = "call",
srcs = ["call.cpp"],
hdrs = ["call.h"],
deps = [
":context",
"//common:check",
"//toolchain/base:kind_switch",
"//toolchain/sem_ir:file",
"//toolchain/sem_ir:ids",
"//toolchain/sem_ir:inst",
"//toolchain/sem_ir:inst_kind",
],
)

cc_library(
name = "generic_region_stack",
srcs = ["generic_region_stack.cpp"],
Expand Down Expand Up @@ -200,23 +188,6 @@ cc_library(
],
)

cc_library(
name = "member_access",
srcs = ["member_access.cpp"],
hdrs = ["member_access.h"],
deps = [
":context",
"//common:check",
"//toolchain/base:kind_switch",
"//toolchain/diagnostics:diagnostic_emitter",
"//toolchain/sem_ir:file",
"//toolchain/sem_ir:ids",
"//toolchain/sem_ir:inst",
"//toolchain/sem_ir:inst_kind",
"@llvm-project//llvm:Support",
],
)

cc_library(
name = "node_stack",
srcs = ["node_stack.cpp"],
Expand All @@ -233,23 +204,6 @@ cc_library(
],
)

cc_library(
name = "operator",
srcs = ["operator.cpp"],
hdrs = ["operator.h"],
deps = [
":call",
":context",
":member_access",
"//common:check",
"//toolchain/parse:node_kind",
"//toolchain/sem_ir:file",
"//toolchain/sem_ir:ids",
"//toolchain/sem_ir:inst",
"//toolchain/sem_ir:inst_kind",
],
)

cc_library(
name = "pointer_dereference",
srcs = ["pointer_dereference.cpp"],
Expand Down
37 changes: 17 additions & 20 deletions toolchain/check/call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include "toolchain/check/convert.h"
#include "toolchain/check/deduce.h"
#include "toolchain/check/function.h"
#include "toolchain/check/generic.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/inst.h"
#include "toolchain/sem_ir/typed_insts.h"
Expand All @@ -18,7 +17,7 @@ namespace Carbon::Check {

// Performs a call where the callee is the name of a generic class, such as
// `Vector(i32)`.
static auto PerformCallToGenericClass(Context& context, Parse::NodeId node_id,
static auto PerformCallToGenericClass(Context& context, SemIR::LocId loc_id,
SemIR::InstId callee_id,
SemIR::ClassId class_id,
llvm::ArrayRef<SemIR::InstId> arg_ids)
Expand All @@ -32,9 +31,9 @@ static auto PerformCallToGenericClass(Context& context, Parse::NodeId node_id,

// Convert the arguments to match the parameters.
auto converted_args_id = ConvertCallArgs(
context, node_id, /*self_id=*/SemIR::InstId::Invalid, arg_ids,
context, loc_id, /*self_id=*/SemIR::InstId::Invalid, arg_ids,
/*return_storage_id=*/SemIR::InstId::Invalid, class_info, specific_id);
return context.AddInst<SemIR::Call>(node_id,
return context.AddInst<SemIR::Call>(loc_id,
{.type_id = SemIR::TypeId::TypeType,
.callee_id = callee_id,
.args_id = converted_args_id});
Expand All @@ -43,8 +42,7 @@ static auto PerformCallToGenericClass(Context& context, Parse::NodeId node_id,
// Performs a call where the callee is the name of a generic interface, such as
// `AddWith(i32)`.
// TODO: Refactor with PerformCallToGenericClass.
static auto PerformCallToGenericInterface(Context& context,
Parse::NodeId node_id,
static auto PerformCallToGenericInterface(Context& context, SemIR::LocId loc_id,
SemIR::InstId callee_id,
SemIR::InterfaceId interface_id,
llvm::ArrayRef<SemIR::InstId> arg_ids)
Expand All @@ -58,30 +56,29 @@ static auto PerformCallToGenericInterface(Context& context,

// Convert the arguments to match the parameters.
auto converted_args_id = ConvertCallArgs(
context, node_id, /*self_id=*/SemIR::InstId::Invalid, arg_ids,
context, loc_id, /*self_id=*/SemIR::InstId::Invalid, arg_ids,
/*return_storage_id=*/SemIR::InstId::Invalid, interface_info,
specific_id);
return context.AddInst<SemIR::Call>(node_id,
return context.AddInst<SemIR::Call>(loc_id,
{.type_id = SemIR::TypeId::TypeType,
.callee_id = callee_id,
.args_id = converted_args_id});
}

auto PerformCall(Context& context, Parse::NodeId node_id,
SemIR::InstId callee_id, llvm::ArrayRef<SemIR::InstId> arg_ids)
-> SemIR::InstId {
auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id,
llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::InstId {
// Identify the function we're calling.
auto callee_function = GetCalleeFunction(context.sem_ir(), callee_id);
if (!callee_function.function_id.is_valid()) {
auto type_inst =
context.types().GetAsInst(context.insts().Get(callee_id).type_id());
CARBON_KIND_SWITCH(type_inst) {
case CARBON_KIND(SemIR::GenericClassType generic_class): {
return PerformCallToGenericClass(context, node_id, callee_id,
return PerformCallToGenericClass(context, loc_id, callee_id,
generic_class.class_id, arg_ids);
}
case CARBON_KIND(SemIR::GenericInterfaceType generic_interface): {
return PerformCallToGenericInterface(context, node_id, callee_id,
return PerformCallToGenericInterface(context, loc_id, callee_id,
generic_interface.interface_id,
arg_ids);
}
Expand All @@ -90,7 +87,7 @@ auto PerformCall(Context& context, Parse::NodeId node_id,
CARBON_DIAGNOSTIC(CallToNonCallable, Error,
"Value of type `{0}` is not callable.",
SemIR::TypeId);
context.emitter().Emit(node_id, CallToNonCallable,
context.emitter().Emit(loc_id, CallToNonCallable,
context.insts().Get(callee_id).type_id());
}
return SemIR::InstId::BuiltinError;
Expand All @@ -104,7 +101,7 @@ auto PerformCall(Context& context, Parse::NodeId node_id,
auto specific_id = SemIR::SpecificId::Invalid;
if (callable.generic_id.is_valid()) {
specific_id = DeduceGenericCallArguments(
context, node_id, callable.generic_id, callee_function.specific_id,
context, loc_id, callable.generic_id, callee_function.specific_id,
callable.implicit_param_refs_id, callable.param_refs_id,
callee_function.self_id, arg_ids);
if (!specific_id.is_valid()) {
Expand All @@ -128,7 +125,7 @@ auto PerformCall(Context& context, Parse::NodeId node_id,
// Tentatively put storage for a temporary in the function's return slot.
// This will be replaced if necessary when we perform initialization.
return_storage_id = context.AddInst<SemIR::TemporaryStorage>(
node_id, {.type_id = return_info.type_id});
loc_id, {.type_id = return_info.type_id});
break;
case SemIR::InitRepr::None:
// For functions with an implicit return type, the return type is the
Expand All @@ -148,12 +145,12 @@ auto PerformCall(Context& context, Parse::NodeId node_id,

// Convert the arguments to match the parameters.
auto converted_args_id = ConvertCallArgs(
context, node_id, callee_function.self_id, arg_ids, return_storage_id,
context, loc_id, callee_function.self_id, arg_ids, return_storage_id,
CalleeParamsInfo(callable), specific_id);
auto call_inst_id =
context.AddInst<SemIR::Call>(node_id, {.type_id = return_info.type_id,
.callee_id = callee_id,
.args_id = converted_args_id});
context.AddInst<SemIR::Call>(loc_id, {.type_id = return_info.type_id,
.callee_id = callee_id,
.args_id = converted_args_id});

return call_inst_id;
}
Expand Down
5 changes: 2 additions & 3 deletions toolchain/check/call.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
namespace Carbon::Check {

// Checks and builds SemIR for a call to `callee_id` with arguments `args_id`.
auto PerformCall(Context& context, Parse::NodeId node_id,
SemIR::InstId callee_id, llvm::ArrayRef<SemIR::InstId> arg_ids)
-> SemIR::InstId;
auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id,
llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::InstId;

} // namespace Carbon::Check

Expand Down
27 changes: 11 additions & 16 deletions toolchain/check/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ auto Context::LookupNameInExactScope(SemIRLoc loc, SemIR::NameId name_id,
return SemIR::InstId::Invalid;
}

auto Context::LookupQualifiedName(Parse::NodeId node_id, SemIR::NameId name_id,
auto Context::LookupQualifiedName(SemIRLoc loc, SemIR::NameId name_id,
LookupScope scope, bool required)
-> LookupResult {
llvm::SmallVector<LookupScope> scopes = {scope};
Expand All @@ -362,7 +362,7 @@ auto Context::LookupQualifiedName(Parse::NodeId node_id, SemIR::NameId name_id,
has_error |= name_scope.has_error;

auto scope_result_id =
LookupNameInExactScope(node_id, name_id, scope_id, name_scope);
LookupNameInExactScope(loc, name_id, scope_id, name_scope);
if (!scope_result_id.is_valid()) {
// Nothing found in this scope: also look in its extended scopes.
auto extended = name_scope.extended_scopes;
Expand All @@ -385,7 +385,7 @@ auto Context::LookupQualifiedName(Parse::NodeId node_id, SemIR::NameId name_id,
NameAmbiguousDueToExtend, Error,
"Ambiguous use of name `{0}` found in multiple extended scopes.",
SemIR::NameId);
emitter_->Emit(node_id, NameAmbiguousDueToExtend, name_id);
emitter_->Emit(loc, NameAmbiguousDueToExtend, name_id);
// TODO: Add notes pointing to the scopes.
return {.specific_id = SemIR::SpecificId::Invalid,
.inst_id = SemIR::InstId::BuiltinError};
Expand All @@ -397,7 +397,7 @@ auto Context::LookupQualifiedName(Parse::NodeId node_id, SemIR::NameId name_id,

if (required && !result.inst_id.is_valid()) {
if (!has_error) {
DiagnoseNameNotFound(node_id, name_id);
DiagnoseNameNotFound(loc, name_id);
}
return {.specific_id = SemIR::SpecificId::Invalid,
.inst_id = SemIR::InstId::BuiltinError};
Expand Down Expand Up @@ -633,10 +633,8 @@ namespace {
// complete.
class TypeCompleter {
public:
TypeCompleter(
Context& context,
std::optional<llvm::function_ref<auto()->Context::DiagnosticBuilder>>
diagnoser)
TypeCompleter(Context& context,
std::optional<Context::BuildDiagnosticFn> diagnoser)
: context_(context), diagnoser_(diagnoser) {}

// Attempts to complete the given type. Returns true if it is now complete,
Expand Down Expand Up @@ -1019,21 +1017,18 @@ class TypeCompleter {

Context& context_;
llvm::SmallVector<WorkItem> work_list_;
std::optional<llvm::function_ref<auto()->Context::DiagnosticBuilder>>
diagnoser_;
std::optional<Context::BuildDiagnosticFn> diagnoser_;
};
} // namespace

auto Context::TryToCompleteType(
SemIR::TypeId type_id,
std::optional<llvm::function_ref<auto()->DiagnosticBuilder>> diagnoser)
auto Context::TryToCompleteType(SemIR::TypeId type_id,
std::optional<BuildDiagnosticFn> diagnoser)
-> bool {
return TypeCompleter(*this, diagnoser).Complete(type_id);
}

auto Context::TryToDefineType(
SemIR::TypeId type_id,
std::optional<llvm::function_ref<auto()->DiagnosticBuilder>> diagnoser)
auto Context::TryToDefineType(SemIR::TypeId type_id,
std::optional<BuildDiagnosticFn> diagnoser)
-> bool {
if (!TryToCompleteType(type_id, diagnoser)) {
return false;
Expand Down
Loading

0 comments on commit 187a360

Please sign in to comment.