mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
This handles namespacing of functions. Parsing and semantics are changed significantly, while lowering works without changes. Variables can't be namespaced yet because they're dealing with patterns, and I didn't dig through that code. Most of the logic is done through the new name declaration stack, which is necessary because semantics isn't quite sure where the declaration name ends. It'd be complex for parsing to send a signal about this, probably involving node variants and rewrites of the tree, and this solution seems to work well. Unfortunately this means a new stack, but that may be inevitable due to the extra information needing to be tracked. Note this doesn't deal with scoped lookups of non-namespace things, which we'll need for generics. That'll probably involve pushing resolved scopes onto a stack (or maybe just setting a singleton value?) to affect contextual name lookup. But, I think the basics are there to make it work when we can test the behavior. This renames "designator expression" to "qualified expression" and adds "qualified declaration" in order to use terminology more consistent with C++. Namespaces will probably need to be considered for name mangling down the line, but this still uses the basic name.
98 lines
3.6 KiB
C++
98 lines
3.6 KiB
C++
// 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
|
|
|
|
#include "toolchain/semantics/semantics_context.h"
|
|
|
|
namespace Carbon {
|
|
|
|
auto SemanticsHandleFunctionDeclaration(SemanticsContext& context,
|
|
ParseTree::Node parse_node) -> bool {
|
|
return context.TODO(parse_node, "HandleFunctionDeclaration");
|
|
}
|
|
|
|
auto SemanticsHandleFunctionDefinition(SemanticsContext& context,
|
|
ParseTree::Node parse_node) -> bool {
|
|
auto function_id = context.node_stack().Pop<SemanticsFunctionId>(
|
|
ParseNodeKind::FunctionDefinitionStart);
|
|
|
|
// If the `}` of the function is reachable, reject if we need a return value
|
|
// and otherwise add an implicit `return;`.
|
|
if (context.is_current_position_reachable()) {
|
|
if (context.semantics_ir()
|
|
.GetFunction(function_id)
|
|
.return_type_id.is_valid()) {
|
|
CARBON_DIAGNOSTIC(
|
|
MissingReturnStatement, Error,
|
|
"Missing `return` at end of function with declared return type.");
|
|
context.emitter().Emit(parse_node, MissingReturnStatement);
|
|
} else {
|
|
context.AddNode(SemanticsNode::Return::Make(parse_node));
|
|
}
|
|
}
|
|
|
|
context.return_scope_stack().pop_back();
|
|
context.PopScope();
|
|
context.node_block_stack().Pop();
|
|
return true;
|
|
}
|
|
|
|
auto SemanticsHandleFunctionDefinitionStart(SemanticsContext& context,
|
|
ParseTree::Node parse_node)
|
|
-> bool {
|
|
SemanticsTypeId return_type_id = SemanticsTypeId::Invalid;
|
|
if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) ==
|
|
ParseNodeKind::ReturnType) {
|
|
return_type_id =
|
|
context.node_stack().Pop<SemanticsTypeId>(ParseNodeKind::ReturnType);
|
|
} else {
|
|
// Canonicalize the empty tuple for the implicit return.
|
|
context.CanonicalizeType(SemanticsNodeId::BuiltinEmptyTupleType);
|
|
}
|
|
auto param_refs_id = context.node_stack().Pop<SemanticsNodeBlockId>(
|
|
ParseNodeKind::ParameterList);
|
|
auto name_context = context.PopDeclarationName();
|
|
auto fn_node = context.node_stack().PopForSoloParseNode(
|
|
ParseNodeKind::FunctionIntroducer);
|
|
|
|
// Create the entry block.
|
|
auto outer_block = context.node_block_stack().PeekForAdd();
|
|
context.node_block_stack().Push();
|
|
|
|
// TODO: Support out-of-line definitions, which will have a resolved
|
|
// name_context. Right now, those become errors in AddNameToLookup.
|
|
|
|
// Add the callable.
|
|
auto function_id = context.semantics_ir().AddFunction(
|
|
{.name_id = name_context.unresolved_name_id,
|
|
.param_refs_id = param_refs_id,
|
|
.return_type_id = return_type_id,
|
|
.body_block_ids = {context.node_block_stack().PeekForAdd()}});
|
|
auto decl_id = context.AddNodeToBlock(
|
|
outer_block,
|
|
SemanticsNode::FunctionDeclaration::Make(fn_node, function_id));
|
|
context.AddNameToLookup(name_context, decl_id);
|
|
|
|
context.PushScope();
|
|
for (auto ref_id : context.semantics_ir().GetNodeBlock(param_refs_id)) {
|
|
auto ref = context.semantics_ir().GetNode(ref_id);
|
|
auto [name_id, target_id] = ref.GetAsBindName();
|
|
context.AddNameToLookup(ref.parse_node(), name_id, target_id);
|
|
}
|
|
context.return_scope_stack().push_back(decl_id);
|
|
context.node_stack().Push(parse_node, function_id);
|
|
|
|
return true;
|
|
}
|
|
|
|
auto SemanticsHandleFunctionIntroducer(SemanticsContext& context,
|
|
ParseTree::Node parse_node) -> bool {
|
|
// Push the bracketing node.
|
|
context.node_stack().Push(parse_node);
|
|
// A name should always follow.
|
|
context.PushDeclarationName();
|
|
return true;
|
|
}
|
|
|
|
} // namespace Carbon
|