mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
Allow more signatures for Main.Run. (#6751)
Allow an argc parameter and an argv parameter to be passed. For now we check that argc is an i32 and argv is a pointer. The rules here are not yet decided -- see #6735 -- but we should at least allow C-style access to argv for now in order to unblock experimentation.
This commit is contained in:
@@ -291,6 +291,97 @@ static auto MaybeAddToNameLookup(
|
||||
modifier_set.GetAccessKind());
|
||||
}
|
||||
|
||||
// Returns whether the given type is `i32`.
|
||||
static auto IsI32(Context& context, Parse::NodeId node_id,
|
||||
SemIR::TypeId type_id) -> bool {
|
||||
return type_id == MakeIntType(context, node_id, SemIR::IntKind::Signed,
|
||||
context.ints().Add(32));
|
||||
}
|
||||
|
||||
// Returns whether the given parameter list is valid for the entry point
|
||||
// function `Main.Run`.
|
||||
static auto IsValidEntryPointParamList(Context& context, Parse::NodeId node_id,
|
||||
SemIR::InstBlockId param_patterns_id)
|
||||
-> bool {
|
||||
if (!param_patterns_id.has_value()) {
|
||||
// Positional parameters for are not supported.
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto [index, param_pattern_id] :
|
||||
llvm::enumerate(context.inst_blocks().Get(param_patterns_id))) {
|
||||
if (param_pattern_id == SemIR::ErrorInst::InstId) {
|
||||
// Ignore erroneous parameters.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto param =
|
||||
context.insts().TryGetAs<SemIR::ValueParamPattern>(param_pattern_id);
|
||||
if (!param) {
|
||||
// Only value parameters are supported for now.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param->type_id == SemIR::ErrorInst::TypeId) {
|
||||
// Ignore parameters with erroneous types.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto param_type_inst_id = context.types()
|
||||
.GetAs<SemIR::PatternType>(param->type_id)
|
||||
.scrutinee_type_inst_id;
|
||||
switch (index) {
|
||||
case 0: {
|
||||
// `argc` should be a 32-bit integer.
|
||||
if (!IsI32(
|
||||
context, node_id,
|
||||
context.types().GetTypeIdForTypeInstId(param_type_inst_id))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// `argv` should be a pointer.
|
||||
// TODO: Consider checking the pointee type also.
|
||||
if (!context.insts().Is<SemIR::PointerType>(param_type_inst_id)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// TODO: Decide whether to allow a third `envp` parameter.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns whether the given return type is valid for the entry point
|
||||
// function `Main.Run`.
|
||||
static auto IsValidEntryPointReturnType(Context& context, Parse::NodeId node_id,
|
||||
SemIR::TypeId return_type_id) -> bool {
|
||||
// An implicit or explicit return type of `()` is OK.
|
||||
// TODO: Translate this to returning an `i32` with value `0` in lowering.
|
||||
if (!return_type_id.has_value()) {
|
||||
return true;
|
||||
}
|
||||
if (return_type_id == GetTupleType(context, {})) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsI32(context, node_id, return_type_id)) {
|
||||
// Explicit return type of `i32` or an adapter for it is OK.
|
||||
return true;
|
||||
}
|
||||
|
||||
// For now, disallow anything else.
|
||||
// TODO: Decide on valid return types for `Main.Run`. Perhaps we should
|
||||
// have an interface for this.
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the function is the entry point, do corresponding validation.
|
||||
static auto ValidateForEntryPoint(Context& context,
|
||||
Parse::AnyFunctionDeclId node_id,
|
||||
@@ -301,21 +392,22 @@ static auto ValidateForEntryPoint(Context& context,
|
||||
return;
|
||||
}
|
||||
|
||||
auto return_type_id = function_info.GetDeclaredReturnType(context.sem_ir());
|
||||
// TODO: Update this once valid signatures for the entry point are decided.
|
||||
// See https://github.com/carbon-language/carbon-lang/issues/6735
|
||||
if (function_info.implicit_param_patterns_id.has_value() ||
|
||||
!function_info.param_patterns_id.has_value() ||
|
||||
!context.inst_blocks().Get(function_info.param_patterns_id).empty() ||
|
||||
(return_type_id.has_value() &&
|
||||
return_type_id != GetTupleType(context, {}) &&
|
||||
// TODO: Decide on valid return types for `Main.Run`. Perhaps we should
|
||||
// have an interface for this.
|
||||
return_type_id != MakeIntType(context, node_id, SemIR::IntKind::Signed,
|
||||
context.ints().Add(32)))) {
|
||||
CARBON_DIAGNOSTIC(InvalidMainRunSignature, Error,
|
||||
"invalid signature for `Main.Run` function; expected "
|
||||
"`fn ()` or `fn () -> i32`");
|
||||
context.emitter().Emit(node_id, InvalidMainRunSignature);
|
||||
!IsValidEntryPointParamList(context, node_id,
|
||||
function_info.param_patterns_id)) {
|
||||
CARBON_DIAGNOSTIC(InvalidMainRunParameters, Error,
|
||||
"invalid parameters for `Main.Run` function; expected "
|
||||
"`()` or `(argc: i32, argv: Core.Optional(char*)*)`");
|
||||
context.emitter().Emit(node_id, InvalidMainRunParameters);
|
||||
} else if (!IsValidEntryPointReturnType(
|
||||
context, node_id,
|
||||
function_info.GetDeclaredReturnType(context.sem_ir()))) {
|
||||
CARBON_DIAGNOSTIC(InvalidMainRunReturnType, Error,
|
||||
"invalid return type for `Main.Run` function; expected "
|
||||
"`fn (...)` or `fn (...) -> i32`");
|
||||
context.emitter().Emit(node_id, InvalidMainRunReturnType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user