handle_let_and_var.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/check/context.h"
  5. #include "toolchain/check/convert.h"
  6. #include "toolchain/check/decl_introducer_state.h"
  7. #include "toolchain/check/handle.h"
  8. #include "toolchain/check/interface.h"
  9. #include "toolchain/check/modifiers.h"
  10. #include "toolchain/check/pattern_match.h"
  11. #include "toolchain/check/return.h"
  12. #include "toolchain/diagnostics/diagnostic_emitter.h"
  13. #include "toolchain/lex/token_kind.h"
  14. #include "toolchain/sem_ir/inst.h"
  15. #include "toolchain/sem_ir/name_scope.h"
  16. #include "toolchain/sem_ir/typed_insts.h"
  17. namespace Carbon::Check {
  18. template <Lex::TokenKind::RawEnumType Kind>
  19. static auto HandleIntroducer(Context& context, Parse::NodeId node_id) -> bool {
  20. context.decl_introducer_state_stack().Push<Kind>();
  21. // Push a bracketing node and pattern block to establish the pattern context.
  22. context.node_stack().Push(node_id);
  23. context.pattern_block_stack().Push();
  24. context.full_pattern_stack().PushFullPattern();
  25. context.BeginSubpattern();
  26. return true;
  27. }
  28. auto HandleParseNode(Context& context, Parse::LetIntroducerId node_id) -> bool {
  29. return HandleIntroducer<Lex::TokenKind::Let>(context, node_id);
  30. }
  31. auto HandleParseNode(Context& context, Parse::VariableIntroducerId node_id)
  32. -> bool {
  33. return HandleIntroducer<Lex::TokenKind::Var>(context, node_id);
  34. }
  35. // Returns a VarStorage inst for the given pattern. If the pattern
  36. // is the body of a returned var, this reuses the return slot, and otherwise it
  37. // adds a new inst.
  38. static auto GetOrAddStorage(Context& context, SemIR::InstId pattern_id)
  39. -> SemIR::InstId {
  40. if (context.decl_introducer_state_stack().innermost().modifier_set.HasAnyOf(
  41. KeywordModifierSet::Returned)) {
  42. auto& function = GetCurrentFunctionForReturn(context);
  43. auto return_info =
  44. SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(), function);
  45. if (return_info.has_return_slot()) {
  46. return GetCurrentReturnSlot(context);
  47. }
  48. }
  49. auto pattern = context.insts().GetWithLocId(pattern_id);
  50. auto subpattern =
  51. context.insts().Get(pattern.inst.As<SemIR::VarPattern>().subpattern_id);
  52. // Try to populate name_id on a best-effort basis.
  53. auto name_id = SemIR::NameId::None;
  54. if (auto binding_pattern = subpattern.TryAs<SemIR::BindingPattern>()) {
  55. name_id =
  56. context.entity_names().Get(binding_pattern->entity_name_id).name_id;
  57. }
  58. return context.AddInst(SemIR::LocIdAndInst::UncheckedLoc(
  59. pattern.loc_id, SemIR::VarStorage{.type_id = subpattern.type_id(),
  60. .pretty_name_id = name_id}));
  61. }
  62. auto HandleParseNode(Context& context, Parse::VariablePatternId node_id)
  63. -> bool {
  64. auto subpattern_id = SemIR::InstId::None;
  65. if (context.node_stack().PeekIs(Parse::NodeKind::TuplePattern)) {
  66. context.node_stack().PopAndIgnore();
  67. CARBON_CHECK(
  68. context.node_stack().PeekIs(Parse::NodeKind::TuplePatternStart));
  69. context.node_stack().PopAndIgnore();
  70. context.inst_block_stack().PopAndDiscard();
  71. context.TODO(node_id, "tuple pattern in let/var");
  72. subpattern_id = SemIR::ErrorInst::SingletonInstId;
  73. } else {
  74. subpattern_id = context.node_stack().PopPattern();
  75. }
  76. auto type_id = context.insts().Get(subpattern_id).type_id();
  77. auto pattern_id = context.AddPatternInst<SemIR::VarPattern>(
  78. node_id, {.type_id = type_id, .subpattern_id = subpattern_id});
  79. context.node_stack().Push(node_id, pattern_id);
  80. return true;
  81. }
  82. // Handle the end of the full-pattern of a let/var declaration (before the
  83. // start of the initializer, if any).
  84. static auto EndFullPattern(Context& context) -> void {
  85. if (context.GetCurrentScopeAs<SemIR::InterfaceDecl>()) {
  86. // Don't emit NameBindingDecl for an associated constant, because it will
  87. // always be empty.
  88. context.pattern_block_stack().PopAndDiscard();
  89. return;
  90. }
  91. auto pattern_block_id = context.pattern_block_stack().Pop();
  92. context.AddInst<SemIR::NameBindingDecl>(
  93. context.node_stack().PeekNodeId(),
  94. {.pattern_block_id = pattern_block_id});
  95. // We need to emit the VarStorage insts early, because they may be output
  96. // arguments for the initializer. However, we can't emit them when we emit
  97. // the corresponding `VarPattern`s because they're part of the pattern match,
  98. // not part of the pattern.
  99. // TODO: find a way to do this without walking the whole pattern block.
  100. for (auto inst_id : context.inst_blocks().Get(pattern_block_id)) {
  101. if (context.insts().Is<SemIR::VarPattern>(inst_id)) {
  102. context.var_storage_map().Insert(inst_id,
  103. GetOrAddStorage(context, inst_id));
  104. }
  105. }
  106. }
  107. static auto HandleInitializer(Context& context, Parse::NodeId node_id) -> bool {
  108. EndFullPattern(context);
  109. if (context.scope_stack().PeekIndex() == ScopeIndex::Package) {
  110. context.global_init().Resume();
  111. }
  112. context.node_stack().Push(node_id);
  113. context.full_pattern_stack().StartPatternInitializer();
  114. return true;
  115. }
  116. auto HandleParseNode(Context& context, Parse::LetInitializerId node_id)
  117. -> bool {
  118. return HandleInitializer(context, node_id);
  119. }
  120. auto HandleParseNode(Context& context, Parse::VariableInitializerId node_id)
  121. -> bool {
  122. return HandleInitializer(context, node_id);
  123. }
  124. namespace {
  125. // State from HandleDecl, returned for type-specific handling.
  126. struct DeclInfo {
  127. // The optional initializer.
  128. std::optional<SemIR::InstId> init_id = std::nullopt;
  129. SemIR::InstId pattern_id = SemIR::InstId::None;
  130. std::optional<SemIR::Inst> parent_scope_inst = std::nullopt;
  131. DeclIntroducerState introducer = DeclIntroducerState();
  132. };
  133. } // namespace
  134. // Handles common logic for `let` and `var` declarations.
  135. // TODO: There's still a lot of divergence here, including logic in
  136. // handle_binding_pattern. These should really be better unified.
  137. template <const Lex::TokenKind& IntroducerTokenKind,
  138. const Parse::NodeKind& IntroducerNodeKind,
  139. const Parse::NodeKind& InitializerNodeKind, typename NodeT>
  140. static auto HandleDecl(Context& context, NodeT node_id)
  141. -> std::optional<DeclInfo> {
  142. std::optional<DeclInfo> decl_info = DeclInfo();
  143. // Handle the optional initializer.
  144. if (context.node_stack().PeekNextIs(InitializerNodeKind)) {
  145. decl_info->init_id = context.node_stack().PopExpr();
  146. context.node_stack().PopAndDiscardSoloNodeId<InitializerNodeKind>();
  147. if (context.scope_stack().PeekIndex() == ScopeIndex::Package) {
  148. context.global_init().Suspend();
  149. }
  150. context.full_pattern_stack().EndPatternInitializer();
  151. } else {
  152. EndFullPattern(context);
  153. }
  154. context.full_pattern_stack().PopFullPattern();
  155. if (context.node_stack().PeekIs(Parse::NodeKind::TuplePattern)) {
  156. if (decl_info->init_id &&
  157. context.scope_stack().PeekIndex() == ScopeIndex::Package) {
  158. context.global_init().Suspend();
  159. }
  160. context.TODO(node_id, "tuple pattern in let/var");
  161. decl_info = std::nullopt;
  162. return decl_info;
  163. }
  164. decl_info->pattern_id = context.node_stack().PopPattern();
  165. context.node_stack().PopAndDiscardSoloNodeId<IntroducerNodeKind>();
  166. // Process declaration modifiers.
  167. // TODO: For a qualified `let` or `var` declaration, this should use the
  168. // target scope of the name introduced in the declaration. See #2590.
  169. decl_info->parent_scope_inst =
  170. context.name_scopes()
  171. .GetInstIfValid(context.scope_stack().PeekNameScopeId())
  172. .second;
  173. decl_info->introducer =
  174. context.decl_introducer_state_stack().Pop<IntroducerTokenKind>();
  175. CheckAccessModifiersOnDecl(context, decl_info->introducer,
  176. decl_info->parent_scope_inst);
  177. return decl_info;
  178. }
  179. static auto HandleAssociatedConstantDecl(Context& context,
  180. Parse::LetDeclId node_id,
  181. DeclInfo decl_info,
  182. SemIR::InterfaceDecl interface_scope)
  183. -> void {
  184. auto pattern = context.insts().GetWithLocId(decl_info.pattern_id);
  185. if (decl_info.init_id) {
  186. // Convert the value to match the type of the pattern.
  187. ConvertToValueOfType(context, node_id, *decl_info.init_id,
  188. pattern.inst.type_id());
  189. }
  190. if (auto decl = pattern.inst.TryAs<SemIR::AssociatedConstantDecl>();
  191. !decl.has_value()) {
  192. CARBON_DIAGNOSTIC(ExpectedSymbolicBindingInAssociatedConstant, Error,
  193. "pattern in associated constant declaration must be a "
  194. "single `:!` binding");
  195. context.emitter().Emit(pattern.loc_id,
  196. ExpectedSymbolicBindingInAssociatedConstant);
  197. context.name_scopes()
  198. .Get(context.interfaces().Get(interface_scope.interface_id).scope_id)
  199. .set_has_error();
  200. }
  201. }
  202. auto HandleParseNode(Context& context, Parse::LetDeclId node_id) -> bool {
  203. auto decl_info =
  204. HandleDecl<Lex::TokenKind::Let, Parse::NodeKind::LetIntroducer,
  205. Parse::NodeKind::LetInitializer>(context, node_id);
  206. if (!decl_info) {
  207. return false;
  208. }
  209. RequireDefaultFinalOnlyInInterfaces(context, decl_info->introducer,
  210. decl_info->parent_scope_inst);
  211. LimitModifiersOnDecl(
  212. context, decl_info->introducer,
  213. KeywordModifierSet::Access | KeywordModifierSet::Interface);
  214. if (decl_info->introducer.modifier_set.HasAnyOf(
  215. KeywordModifierSet::Interface)) {
  216. context.TODO(decl_info->introducer.modifier_node_id(ModifierOrder::Decl),
  217. "interface modifier");
  218. }
  219. // At interface scope, we are forming an associated constant, which has
  220. // different rules.
  221. if (auto interface_scope = context.GetCurrentScopeAs<SemIR::InterfaceDecl>();
  222. interface_scope) {
  223. HandleAssociatedConstantDecl(context, node_id, *decl_info,
  224. *interface_scope);
  225. return true;
  226. }
  227. if (decl_info->init_id) {
  228. LocalPatternMatch(context, decl_info->pattern_id, *decl_info->init_id);
  229. } else {
  230. CARBON_DIAGNOSTIC(
  231. ExpectedInitializerAfterLet, Error,
  232. "expected `=`; `let` declaration must have an initializer");
  233. context.emitter().Emit(TokenOnly(node_id), ExpectedInitializerAfterLet);
  234. }
  235. return true;
  236. }
  237. auto HandleParseNode(Context& context, Parse::VariableDeclId node_id) -> bool {
  238. auto decl_info =
  239. HandleDecl<Lex::TokenKind::Var, Parse::NodeKind::VariableIntroducer,
  240. Parse::NodeKind::VariableInitializer>(context, node_id);
  241. if (!decl_info) {
  242. return false;
  243. }
  244. LimitModifiersOnDecl(
  245. context, decl_info->introducer,
  246. KeywordModifierSet::Access | KeywordModifierSet::Returned);
  247. if (context.GetCurrentScopeAs<SemIR::ClassDecl>()) {
  248. if (decl_info->init_id) {
  249. // TODO: In a class scope, we should instead save the initializer
  250. // somewhere so that we can use it as a default.
  251. context.TODO(node_id, "Field initializer");
  252. }
  253. return true;
  254. }
  255. LocalPatternMatch(context, decl_info->pattern_id,
  256. decl_info->init_id.value_or(SemIR::InstId::None));
  257. return true;
  258. }
  259. } // namespace Carbon::Check