1use core::panic;
6use std::ops::Deref;
7use std::sync::Arc;
8
9use ast::PathSegment;
10use cairo_lang_debug::DebugWithDb;
11use cairo_lang_defs::db::{get_all_path_leaves, validate_attributes_flat};
12use cairo_lang_defs::diagnostic_utils::StableLocation;
13use cairo_lang_defs::ids::{
14 FunctionTitleId, GenericKind, LanguageElementId, LocalVarLongId, LookupItemId, MemberId,
15 ModuleFileId, ModuleItemId, NamedLanguageElementId, StatementConstLongId, StatementItemId,
16 StatementUseLongId, TraitFunctionId, TraitId, VarId,
17};
18use cairo_lang_defs::plugin::{InlineMacroExprPlugin, MacroPluginMetadata};
19use cairo_lang_diagnostics::{Maybe, skip_diagnostic};
20use cairo_lang_filesystem::cfg::CfgSet;
21use cairo_lang_filesystem::ids::CodeOrigin::{CallSite, Span, Start};
22use cairo_lang_filesystem::ids::{CodeMapping, FileKind, FileLongId, VirtualFile};
23use cairo_lang_filesystem::span::TextOffset;
24use cairo_lang_proc_macros::DebugWithDb;
25use cairo_lang_syntax::node::ast::{
26 BinaryOperator, BlockOrIf, ClosureParamWrapper, ConditionListAnd, ExprPtr,
27 OptionReturnTypeClause, PatternListOr, PatternStructParam, TerminalIdentifier, UnaryOperator,
28};
29use cairo_lang_syntax::node::db::SyntaxGroup;
30use cairo_lang_syntax::node::helpers::{GetIdentifier, PathSegmentEx};
31use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
32use cairo_lang_syntax::node::kind::SyntaxKind;
33use cairo_lang_syntax::node::{Terminal, TypedStablePtr, TypedSyntaxNode, ast};
34use cairo_lang_utils::ordered_hash_map::{Entry, OrderedHashMap};
35use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
36use cairo_lang_utils::unordered_hash_map::UnorderedHashMap;
37use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;
38use cairo_lang_utils::{
39 self as utils, Intern, LookupIntern, OptionHelper, extract_matches, require,
40 try_extract_matches,
41};
42use itertools::{Itertools, chain, zip_eq};
43use num_bigint::BigInt;
44use num_traits::ToPrimitive;
45use smol_str::SmolStr;
46
47use super::inference::canonic::ResultNoErrEx;
48use super::inference::conform::InferenceConform;
49use super::inference::infers::InferenceEmbeddings;
50use super::inference::{Inference, InferenceData, InferenceError};
51use super::objects::*;
52use super::pattern::{
53 Pattern, PatternEnumVariant, PatternFixedSizeArray, PatternLiteral, PatternMissing,
54 PatternOtherwise, PatternTuple, PatternVariable,
55};
56use crate::corelib::{
57 core_binary_operator, core_bool_ty, core_unary_operator, false_literal_expr, get_usize_ty,
58 never_ty, true_literal_expr, try_get_core_ty_by_name, unit_expr, unit_ty,
59 unwrap_error_propagation_type, validate_literal,
60};
61use crate::db::SemanticGroup;
62use crate::diagnostic::SemanticDiagnosticKind::{self, *};
63use crate::diagnostic::{
64 ElementKind, MultiArmExprKind, NotFoundItemType, SemanticDiagnostics,
65 SemanticDiagnosticsBuilder, TraitInferenceErrors, UnsupportedOutsideOfFunctionFeatureName,
66};
67use crate::expr::inference::solver::SolutionSet;
68use crate::expr::inference::{ImplVarTraitItemMappings, InferenceId};
69use crate::items::constant::{ConstValue, resolve_const_expr_and_evaluate, validate_const_expr};
70use crate::items::enm::SemanticEnumEx;
71use crate::items::feature_kind::extract_item_feature_config;
72use crate::items::functions::{concrete_function_closure_params, function_signature_params};
73use crate::items::imp::{ImplLookupContext, filter_candidate_traits, infer_impl_by_self};
74use crate::items::macro_declaration::{MatcherContext, expand_macro_rule, is_macro_rule_match};
75use crate::items::modifiers::compute_mutability;
76use crate::items::us::get_use_path_segments;
77use crate::items::visibility;
78use crate::keyword::MACRO_CALL_SITE;
79use crate::resolve::{
80 AsSegments, EnrichedMembers, EnrichedTypeMemberAccess, ResolutionContext, ResolvedConcreteItem,
81 ResolvedGenericItem, Resolver, ResolverMacroData,
82};
83use crate::semantic::{self, Binding, FunctionId, LocalVariable, TypeId, TypeLongId};
84use crate::substitution::SemanticRewriter;
85use crate::types::{
86 ClosureTypeLongId, ConcreteTypeId, add_type_based_diagnostics, are_coupons_enabled,
87 extract_fixed_size_array_size, peel_snapshots, peel_snapshots_ex, resolve_type_ex,
88 verify_fixed_size_array_size, wrap_in_snapshots,
89};
90use crate::usage::Usages;
91use crate::{
92 ConcreteEnumId, ConcreteVariant, GenericArgumentId, GenericParam, LocalItem, Member,
93 Mutability, Parameter, PatternStringLiteral, PatternStruct, Signature, StatementItemKind,
94};
95
96#[derive(Debug, Clone, PartialEq, Eq)]
98struct MacroExpansionInfo {
99 mappings: Arc<[CodeMapping]>,
101 kind: MacroKind,
103 vars_to_expose: Vec<(SmolStr, Binding)>,
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
109pub struct ExpansionOffset(TextOffset);
110impl ExpansionOffset {
111 pub fn new(offset: TextOffset) -> Self {
113 Self(offset)
114 }
115 pub fn mapped(self, mappings: &[CodeMapping]) -> Option<Self> {
117 let mapping = mappings
118 .iter()
119 .find(|mapping| mapping.span.start <= self.0 && self.0 <= mapping.span.end)?;
120 Some(Self::new(match mapping.origin {
121 Start(text_offset) => text_offset.add_width(self.0 - mapping.span.start),
122 Span(text_span) | CallSite(text_span) => text_span.start,
123 }))
124 }
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub enum MacroKind {
130 UserDefined,
132 Plugin,
134 Unhygienic,
136}
137
138#[derive(Debug, Clone)]
140pub struct ExprAndId {
141 pub expr: Expr,
142 pub id: ExprId,
143}
144impl Deref for ExprAndId {
145 type Target = Expr;
146
147 fn deref(&self) -> &Self::Target {
148 &self.expr
149 }
150}
151
152#[derive(Debug, Clone)]
153pub struct PatternAndId {
154 pub pattern: Pattern,
155 pub id: PatternId,
156}
157impl Deref for PatternAndId {
158 type Target = Pattern;
159
160 fn deref(&self) -> &Self::Target {
161 &self.pattern
162 }
163}
164
165#[derive(Debug, Clone)]
167pub struct NamedArg(ExprAndId, Option<ast::TerminalIdentifier>, Mutability);
168
169pub enum ContextFunction {
170 Global,
171 Function(Maybe<FunctionId>),
172}
173
174#[derive(Debug, Clone)]
176struct InnerContext {
177 return_type: TypeId,
179 kind: InnerContextKind,
181}
182
183#[derive(Debug, Clone)]
185enum InnerContextKind {
186 Loop { type_merger: FlowMergeTypeHelper },
188 While,
190 For,
192 Closure,
194}
195
196#[derive(Debug, Clone)]
198struct InlineMacroExpansion {
199 pub content: Arc<str>,
200 pub name: String,
201 pub info: MacroExpansionInfo,
202}
203
204pub struct ComputationContext<'ctx> {
206 pub db: &'ctx dyn SemanticGroup,
207 pub diagnostics: &'ctx mut SemanticDiagnostics,
208 pub resolver: Resolver<'ctx>,
209 signature: Option<&'ctx Signature>,
210 environment: Box<Environment>,
211 pub arenas: Arenas,
213 function_id: ContextFunction,
214 pub semantic_defs: UnorderedHashMap<semantic::VarId, semantic::Binding>,
216 inner_ctx: Option<InnerContext>,
217 cfg_set: Arc<CfgSet>,
218 are_closures_in_context: bool,
221 macro_defined_var_unhygienic: bool,
224}
225impl<'ctx> ComputationContext<'ctx> {
226 pub fn new(
227 db: &'ctx dyn SemanticGroup,
228 diagnostics: &'ctx mut SemanticDiagnostics,
229 resolver: Resolver<'ctx>,
230 signature: Option<&'ctx Signature>,
231 environment: Environment,
232 function_id: ContextFunction,
233 ) -> Self {
234 let semantic_defs =
235 environment.variables.values().by_ref().map(|var| (var.id(), var.clone())).collect();
236 let cfg_set =
237 resolver.settings.cfg_set.clone().map(Arc::new).unwrap_or_else(|| db.cfg_set());
238 Self {
239 db,
240 diagnostics,
241 resolver,
242 signature,
243 environment: Box::new(environment),
244 arenas: Default::default(),
245 function_id,
246 semantic_defs,
247 inner_ctx: None,
248 cfg_set,
249 are_closures_in_context: false,
250 macro_defined_var_unhygienic: false,
251 }
252 }
253
254 fn run_in_subscope<T, F>(&mut self, f: F) -> T
259 where
260 F: FnOnce(&mut Self) -> T,
261 {
262 self.run_in_subscope_ex(f, None)
263 }
264
265 fn run_in_macro_subscope<T, F>(&mut self, operation: F, macro_info: MacroExpansionInfo) -> T
270 where
271 F: FnOnce(&mut Self) -> T,
272 {
273 let prev_macro_hygiene_kind = self.macro_defined_var_unhygienic;
274 let prev_suppress_modifiers_diagnostics = self.resolver.suppress_modifiers_diagnostics;
275 match macro_info.kind {
276 MacroKind::Unhygienic => {
277 self.macro_defined_var_unhygienic = true;
278 }
279 MacroKind::Plugin => {
280 self.resolver.set_suppress_modifiers_diagnostics(true);
281 }
282 MacroKind::UserDefined => {}
283 }
284 let result = self.run_in_subscope_ex(operation, Some(macro_info));
285 self.macro_defined_var_unhygienic = prev_macro_hygiene_kind;
286 self.resolver.set_suppress_modifiers_diagnostics(prev_suppress_modifiers_diagnostics);
287 result
288 }
289 fn run_in_subscope_ex<T, F>(&mut self, f: F, macro_info: Option<MacroExpansionInfo>) -> T
293 where
294 F: FnOnce(&mut Self) -> T,
295 {
296 let parent = std::mem::replace(&mut self.environment, Environment::empty().into());
298 self.environment.parent = Some(parent);
299 self.environment.macro_info = macro_info;
300 let res = f(self);
301
302 let parent = self.environment.parent.take().unwrap();
304 let mut closed = std::mem::replace(&mut self.environment, parent);
305 let parent = &mut self.environment;
306 if let Some(macro_info) = closed.macro_info {
307 for (name, binding) in macro_info.vars_to_expose {
308 if !closed.used_variables.insert(binding.id()) {
311 parent.used_variables.insert(binding.id());
315 }
316 if let Some(old_var) = parent.variables.insert(name.clone(), binding.clone()) {
317 add_unused_binding_warning(
318 self.diagnostics,
319 self.db,
320 &parent.used_variables,
321 &name,
322 &old_var,
323 );
324 }
325 if let Some(parent_macro_info) = parent.macro_info.as_mut() {
326 parent_macro_info.vars_to_expose.push((name, binding));
327 }
328 }
329 }
330 for (name, binding) in closed.variables {
331 add_unused_binding_warning(
332 self.diagnostics,
333 self.db,
334 &closed.used_variables,
335 &name,
336 &binding,
337 );
338 }
339 for (ty_name, statement_ty) in closed.use_items {
341 if !closed.used_use_items.contains(&ty_name) && !ty_name.starts_with('_') {
342 self.diagnostics.report(statement_ty.stable_ptr, UnusedUse);
343 }
344 }
345 res
346 }
347
348 fn get_return_type(&mut self) -> Option<TypeId> {
350 if let Some(inner_ctx) = &self.inner_ctx {
351 return Some(inner_ctx.return_type);
352 }
353
354 if let Some(signature) = self.signature {
355 return Some(signature.return_type);
356 }
357
358 None
359 }
360
361 fn reduce_ty(&mut self, ty: TypeId) -> TypeId {
362 self.resolver.inference().rewrite(ty).no_err()
363 }
364
365 pub fn apply_inference_rewriter_to_exprs(&mut self) {
368 let mut analyzed_types = UnorderedHashSet::<_>::default();
369 for (_id, expr) in &mut self.arenas.exprs {
370 self.resolver.inference().internal_rewrite(expr).no_err();
371 if analyzed_types.insert(expr.ty()) {
373 add_type_based_diagnostics(self.db, self.diagnostics, expr.ty(), &*expr);
374 }
375 }
376 }
377
378 fn apply_inference_rewriter(&mut self) {
380 self.apply_inference_rewriter_to_exprs();
381 for (_id, pattern) in &mut self.arenas.patterns {
382 self.resolver.inference().internal_rewrite(pattern).no_err();
383 }
384 for (_id, stmt) in &mut self.arenas.statements {
385 self.resolver.inference().internal_rewrite(stmt).no_err();
386 }
387 }
388 fn is_inside_loop(&self) -> bool {
390 let Some(inner_ctx) = &self.inner_ctx else {
391 return false;
392 };
393
394 match inner_ctx.kind {
395 InnerContextKind::Closure => false,
396 InnerContextKind::Loop { .. } | InnerContextKind::While | InnerContextKind::For => true,
397 }
398 }
399}
400
401fn add_unused_binding_warning(
403 diagnostics: &mut SemanticDiagnostics,
404 db: &dyn SemanticGroup,
405 used_bindings: &UnorderedHashSet<VarId>,
406 name: &str,
407 binding: &Binding,
408) {
409 if !name.starts_with('_') && !used_bindings.contains(&binding.id()) {
410 match binding {
411 Binding::LocalItem(local_item) => match local_item.id {
412 StatementItemId::Constant(_) => {
413 diagnostics.report(binding.stable_ptr(db), UnusedConstant);
414 }
415 StatementItemId::Use(_) => {
416 diagnostics.report(binding.stable_ptr(db), UnusedUse);
417 }
418 },
419 Binding::LocalVar(_) | Binding::Param(_) => {
420 diagnostics.report(binding.stable_ptr(db), UnusedVariable);
421 }
422 }
423 }
424}
425
426pub type EnvVariables = OrderedHashMap<SmolStr, Binding>;
428
429type EnvItems = OrderedHashMap<SmolStr, StatementGenericItemData>;
430
431#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
433#[debug_db(dyn SemanticGroup + 'static)]
434struct StatementGenericItemData {
435 resolved_generic_item: ResolvedGenericItem,
436 stable_ptr: SyntaxStablePtrId,
437}
438
439#[derive(Clone, Debug, PartialEq, Eq)]
443pub struct Environment {
444 parent: Option<Box<Environment>>,
445 variables: EnvVariables,
446 used_variables: UnorderedHashSet<semantic::VarId>,
447 use_items: EnvItems,
448 used_use_items: UnorderedHashSet<SmolStr>,
449 macro_info: Option<MacroExpansionInfo>,
451}
452impl Environment {
453 pub fn add_param(
455 &mut self,
456 db: &dyn SemanticGroup,
457 diagnostics: &mut SemanticDiagnostics,
458 semantic_param: Parameter,
459 ast_param: &ast::Param,
460 function_title_id: Option<FunctionTitleId>,
461 ) -> Maybe<()> {
462 if let utils::ordered_hash_map::Entry::Vacant(entry) =
463 self.variables.entry(semantic_param.name.clone())
464 {
465 entry.insert(Binding::Param(semantic_param));
466 Ok(())
467 } else {
468 Err(diagnostics.report(
469 ast_param.stable_ptr(db),
470 ParamNameRedefinition { function_title_id, param_name: semantic_param.name },
471 ))
472 }
473 }
474
475 pub fn empty() -> Self {
476 Self {
477 parent: None,
478 variables: Default::default(),
479 used_variables: Default::default(),
480 use_items: Default::default(),
481 used_use_items: Default::default(),
482 macro_info: None,
483 }
484 }
485}
486
487pub fn get_statement_item_by_name(
489 env: &mut Environment,
490 item_name: &SmolStr,
491) -> Option<ResolvedGenericItem> {
492 let mut maybe_env = Some(&mut *env);
493 while let Some(curr_env) = maybe_env {
494 if let Some(var) = curr_env.use_items.get(item_name) {
495 curr_env.used_use_items.insert(item_name.clone());
496 return Some(var.resolved_generic_item.clone());
497 }
498 maybe_env = curr_env.parent.as_deref_mut();
499 }
500 None
501}
502
503pub fn compute_expr_semantic(ctx: &mut ComputationContext<'_>, syntax: &ast::Expr) -> ExprAndId {
507 let expr = maybe_compute_expr_semantic(ctx, syntax);
508 let expr = wrap_maybe_with_missing(ctx, expr, syntax.stable_ptr(ctx.db));
509 let id = ctx.arenas.exprs.alloc(expr.clone());
510 ExprAndId { expr, id }
511}
512
513fn wrap_maybe_with_missing(
515 ctx: &mut ComputationContext<'_>,
516 expr: Maybe<Expr>,
517 stable_ptr: ast::ExprPtr,
518) -> Expr {
519 expr.unwrap_or_else(|diag_added| {
520 Expr::Missing(ExprMissing {
521 ty: TypeId::missing(ctx.db, diag_added),
522 stable_ptr,
523 diag_added,
524 })
525 })
526}
527
528pub fn maybe_compute_expr_semantic(
530 ctx: &mut ComputationContext<'_>,
531 syntax: &ast::Expr,
532) -> Maybe<Expr> {
533 let db = ctx.db;
534
535 match syntax {
537 ast::Expr::Path(path) => resolve_expr_path(ctx, path),
538 ast::Expr::Literal(literal_syntax) => {
539 Ok(Expr::Literal(literal_to_semantic(ctx, literal_syntax)?))
540 }
541 ast::Expr::ShortString(literal_syntax) => {
542 Ok(Expr::Literal(short_string_to_semantic(ctx, literal_syntax)?))
543 }
544 ast::Expr::String(literal_syntax) => {
545 Ok(Expr::StringLiteral(string_literal_to_semantic(ctx, literal_syntax)?))
546 }
547 ast::Expr::False(syntax) => Ok(false_literal_expr(ctx, syntax.stable_ptr(db).into())),
548 ast::Expr::True(syntax) => Ok(true_literal_expr(ctx, syntax.stable_ptr(db).into())),
549 ast::Expr::Parenthesized(paren_syntax) => {
550 maybe_compute_expr_semantic(ctx, &paren_syntax.expr(db))
551 }
552 ast::Expr::Unary(syntax) => compute_expr_unary_semantic(ctx, syntax),
553 ast::Expr::Binary(binary_op_syntax) => compute_expr_binary_semantic(ctx, binary_op_syntax),
554 ast::Expr::Tuple(tuple_syntax) => compute_expr_tuple_semantic(ctx, tuple_syntax),
555 ast::Expr::FunctionCall(call_syntax) => {
556 compute_expr_function_call_semantic(ctx, call_syntax)
557 }
558 ast::Expr::StructCtorCall(ctor_syntax) => struct_ctor_expr(ctx, ctor_syntax),
559 ast::Expr::Block(block_syntax) => compute_expr_block_semantic(ctx, block_syntax),
560 ast::Expr::Match(expr_match) => compute_expr_match_semantic(ctx, expr_match),
561 ast::Expr::If(expr_if) => compute_expr_if_semantic(ctx, expr_if),
562 ast::Expr::Loop(expr_loop) => compute_expr_loop_semantic(ctx, expr_loop),
563 ast::Expr::While(expr_while) => compute_expr_while_semantic(ctx, expr_while),
564 ast::Expr::ErrorPropagate(expr) => compute_expr_error_propagate_semantic(ctx, expr),
565 ast::Expr::InlineMacro(expr) => compute_expr_inline_macro_semantic(ctx, expr),
566 ast::Expr::Missing(_) | ast::Expr::FieldInitShorthand(_) => {
567 Err(ctx.diagnostics.report(syntax.stable_ptr(db), SemanticDiagnosticKind::Unsupported))
568 }
569 ast::Expr::Indexed(expr) => compute_expr_indexed_semantic(ctx, expr),
570 ast::Expr::FixedSizeArray(expr) => compute_expr_fixed_size_array_semantic(ctx, expr),
571 ast::Expr::For(expr) => compute_expr_for_semantic(ctx, expr),
572 ast::Expr::Closure(expr) => compute_expr_closure_semantic(ctx, expr, None),
573 ast::Expr::Placeholder(_) => todo!(),
574 }
575}
576
577fn expand_inline_macro(
579 ctx: &mut ComputationContext<'_>,
580 syntax: &ast::ExprInlineMacro,
581) -> Maybe<InlineMacroExpansion> {
582 let db = ctx.db;
583 let macro_name = syntax.path(db).identifier(ctx.db).to_string();
584 let crate_id = ctx.resolver.owning_crate_id;
585 if syntax.as_syntax_node().descendants(db).any(|node| {
587 matches!(
588 node.kind(db),
589 SyntaxKind::ExprMissing
590 | SyntaxKind::WrappedArgListMissing
591 | SyntaxKind::StatementMissing
592 | SyntaxKind::ModuleItemMissing
593 | SyntaxKind::TraitItemMissing
594 | SyntaxKind::ImplItemMissing
595 | SyntaxKind::TokenMissing
596 | SyntaxKind::TokenSkipped
597 | SyntaxKind::WrappedTokenTreeMissing
598 )
599 }) {
600 return Err(skip_diagnostic());
601 }
602 let user_defined_macro = ctx.resolver.resolve_generic_path(
605 &mut Default::default(),
606 &syntax.path(db),
607 NotFoundItemType::Macro,
608 ResolutionContext::Statement(&mut ctx.environment),
609 );
610 if let Ok(ResolvedGenericItem::Macro(macro_declaration_id)) = user_defined_macro {
611 let macro_rules = ctx.db.macro_declaration_rules(macro_declaration_id)?;
612 let Some((rule, (captures, placeholder_to_rep_id))) = macro_rules.iter().find_map(|rule| {
613 is_macro_rule_match(ctx.db, rule, &syntax.arguments(db)).map(|res| (rule, res))
614 }) else {
615 return Err(ctx.diagnostics.report(
616 syntax.stable_ptr(ctx.db),
617 InlineMacroNoMatchingRule(macro_name.clone().into()),
618 ));
619 };
620 let mut matcher_ctx =
621 MatcherContext { captures, placeholder_to_rep_id, ..Default::default() };
622 let expanded_code = expand_macro_rule(ctx.db, rule, &mut matcher_ctx)?;
623
624 let macro_defsite_resolver_data =
625 ctx.db.macro_declaration_resolver_data(macro_declaration_id)?;
626 let inference_id = ctx.resolver.inference().inference_id;
627 let callsite_resolver = ctx.resolver.data.clone_with_inference_id(ctx.db, inference_id);
628 let parent_macro_call_data = ctx.resolver.macro_call_data.clone();
629 let info = MacroExpansionInfo {
630 mappings: expanded_code.code_mappings,
631 kind: MacroKind::UserDefined,
632 vars_to_expose: vec![],
633 };
634 ctx.resolver.macro_call_data = Some(ResolverMacroData {
635 defsite_module_file_id: macro_defsite_resolver_data.module_file_id,
636 callsite_module_file_id: callsite_resolver.module_file_id,
637 expansion_mappings: info.mappings.clone(),
638 parent_macro_call_data: parent_macro_call_data.map(|data| data.into()),
639 });
640 Ok(InlineMacroExpansion { content: expanded_code.text, name: macro_name, info })
641 } else if let Some(macro_plugin_id) =
642 ctx.db.crate_inline_macro_plugins(crate_id).get(¯o_name).cloned()
643 {
644 let macro_plugin = ctx.db.lookup_intern_inline_macro_plugin(macro_plugin_id);
645 let result = macro_plugin.generate_code(
646 db,
647 syntax,
648 &MacroPluginMetadata {
649 cfg_set: &ctx.cfg_set,
650 declared_derives: &ctx.db.declared_derives(crate_id),
651 allowed_features: &ctx.resolver.data.feature_config.allowed_features,
652 edition: ctx.resolver.settings.edition,
653 },
654 );
655 let mut diag_added = None;
656 for diagnostic in result.diagnostics {
657 diag_added = match diagnostic.inner_span {
658 None => Some(
659 ctx.diagnostics.report(diagnostic.stable_ptr, PluginDiagnostic(diagnostic)),
660 ),
661 Some((offset, width)) => Some(ctx.diagnostics.report_with_inner_span(
662 diagnostic.stable_ptr,
663 (offset, width),
664 PluginDiagnostic(diagnostic),
665 )),
666 }
667 }
668 let Some(code) = result.code else {
669 return Err(diag_added.unwrap_or_else(|| {
670 ctx.diagnostics
671 .report(syntax.stable_ptr(ctx.db), InlineMacroNotFound(macro_name.into()))
672 }));
673 };
674 Ok(InlineMacroExpansion {
675 content: code.content.into(),
676 name: code.name.to_string(),
677 info: MacroExpansionInfo {
678 mappings: code.code_mappings.into(),
679 kind: if code.is_unhygienic { MacroKind::Unhygienic } else { MacroKind::Plugin },
680 vars_to_expose: vec![],
681 },
682 })
683 } else {
684 Err(ctx.diagnostics.report(
685 syntax.stable_ptr(db),
686 InlineMacroNotFound(
687 syntax.path(db).as_syntax_node().get_text_without_trivia(db).into(),
688 ),
689 ))
690 }
691}
692
693fn compute_expr_inline_macro_semantic(
695 ctx: &mut ComputationContext<'_>,
696 syntax: &ast::ExprInlineMacro,
697) -> Maybe<Expr> {
698 let prev_macro_call_data = ctx.resolver.macro_call_data.clone();
699 let InlineMacroExpansion { content, name, info } = expand_inline_macro(ctx, syntax)?;
700 let new_file_id = FileLongId::Virtual(VirtualFile {
701 parent: Some(syntax.stable_ptr(ctx.db).untyped().file_id(ctx.db)),
702 name: name.into(),
703 content,
704 code_mappings: info.mappings.clone(),
705 kind: FileKind::Expr,
706 original_item_removed: true,
707 })
708 .intern(ctx.db);
709 let expr_syntax = ctx.db.file_expr_syntax(new_file_id)?;
710 let parser_diagnostics = ctx.db.file_syntax_diagnostics(new_file_id);
711 if let Err(diag_added) = parser_diagnostics.check_error_free() {
712 for diag in parser_diagnostics.get_diagnostics_without_duplicates(ctx.db.elongate()) {
713 ctx.diagnostics.report(
714 syntax.stable_ptr(ctx.db),
715 SemanticDiagnosticKind::MacroGeneratedCodeParserDiagnostic(diag),
716 );
717 }
718 return Err(diag_added);
719 }
720 let expr = ctx.run_in_macro_subscope(|ctx| compute_expr_semantic(ctx, &expr_syntax), info);
721 ctx.resolver.macro_call_data = prev_macro_call_data;
722 Ok(expr.expr)
723}
724
725fn compute_tail_semantic(
728 ctx: &mut ComputationContext<'_>,
729 tail: &ast::StatementExpr,
730 statements_ids: &mut Vec<StatementId>,
731) -> ExprAndId {
732 let expr = tail.expr(ctx.db);
733 let ast::Expr::InlineMacro(inline_macro_syntax) = &expr else {
734 return compute_expr_semantic(ctx, &expr);
735 };
736 match expand_macro_for_statement(ctx, inline_macro_syntax, true, statements_ids) {
737 Ok(Some(expr_and_id)) => expr_and_id,
738 Ok(None) => unreachable!("Tail expression should not be None"),
739 Err(diag_added) => {
740 let expr = Expr::Missing(ExprMissing {
741 ty: TypeId::missing(ctx.db, diag_added),
742 stable_ptr: expr.stable_ptr(ctx.db),
743 diag_added,
744 });
745 ExprAndId { id: ctx.arenas.exprs.alloc(expr.clone()), expr }
746 }
747 }
748}
749
750fn expand_macro_for_statement(
753 ctx: &mut ComputationContext<'_>,
754 syntax: &ast::ExprInlineMacro,
755 is_tail: bool,
756 statements_ids: &mut Vec<StatementId>,
757) -> Maybe<Option<ExprAndId>> {
758 let prev_macro_call_data = ctx.resolver.macro_call_data.clone();
759 let InlineMacroExpansion { content, name, info } = expand_inline_macro(ctx, syntax)?;
760 let new_file_id = FileLongId::Virtual(VirtualFile {
761 parent: Some(syntax.stable_ptr(ctx.db).untyped().file_id(ctx.db)),
762 name: name.into(),
763 content,
764 code_mappings: info.mappings.clone(),
765 kind: FileKind::StatementList,
766 original_item_removed: true,
767 })
768 .intern(ctx.db);
769 let parser_diagnostics = ctx.db.file_syntax_diagnostics(new_file_id);
770 if let Err(diag_added) = parser_diagnostics.check_error_free() {
771 for diag in parser_diagnostics.get_diagnostics_without_duplicates(ctx.db.elongate()) {
772 ctx.diagnostics.report(
773 syntax.stable_ptr(ctx.db),
774 SemanticDiagnosticKind::MacroGeneratedCodeParserDiagnostic(diag),
775 );
776 }
777 return Err(diag_added);
778 }
779 let statement_list = ctx.db.file_statement_list_syntax(new_file_id)?;
780 let (parsed_statements, tail) = statements_and_tail(ctx.db, statement_list);
781 let result = ctx.run_in_macro_subscope(
782 |ctx| {
783 compute_statements_semantic_and_extend(ctx, parsed_statements, statements_ids);
784 if is_tail {
785 if let Some(tail_expr) = tail {
786 Ok(Some(compute_tail_semantic(ctx, &tail_expr, statements_ids)))
787 } else {
788 Err(ctx.diagnostics.report_after(syntax.stable_ptr(ctx.db), MissingSemicolon))
789 }
790 } else {
791 if let Some(tail_expr) = tail {
792 let expr = compute_expr_semantic(ctx, &tail_expr.expr(ctx.db));
793 statements_ids.push(ctx.arenas.statements.alloc(semantic::Statement::Expr(
794 semantic::StatementExpr {
795 expr: expr.id,
796 stable_ptr: tail_expr.stable_ptr(ctx.db).into(),
797 },
798 )));
799 }
800 Ok(None)
801 }
802 },
803 info,
804 );
805 ctx.resolver.macro_call_data = prev_macro_call_data;
806 result
807}
808
809fn compute_expr_unary_semantic(
810 ctx: &mut ComputationContext<'_>,
811 syntax: &ast::ExprUnary,
812) -> Maybe<Expr> {
813 let db = ctx.db;
814 let unary_op = syntax.op(db);
815 let inner = syntax.expr(db);
816 match (&unary_op, &inner) {
817 (UnaryOperator::Minus(_), ast::Expr::Literal(literal)) => {
819 let (value, ty) = literal.numeric_value_and_suffix(db).unwrap_or_default();
820 let ty = ty.as_ref().map(SmolStr::as_str);
821
822 Ok(Expr::Literal(new_literal_expr(ctx, ty, -value, syntax.stable_ptr(db).into())?))
823 }
824 (UnaryOperator::At(_), inner) => {
825 let expr = compute_expr_semantic(ctx, inner);
826
827 let ty = TypeLongId::Snapshot(expr.ty()).intern(ctx.db);
828 Ok(Expr::Snapshot(ExprSnapshot {
829 inner: expr.id,
830 ty,
831 stable_ptr: syntax.stable_ptr(db).into(),
832 }))
833 }
834 (UnaryOperator::Desnap(_), inner) => {
835 let (desnapped_expr, desnapped_ty) = {
836 let desnapped_expr = compute_expr_semantic(ctx, inner);
838 let desnapped_expr_type = ctx.reduce_ty(desnapped_expr.ty());
839
840 let desnapped_ty = match desnapped_expr_type.lookup_intern(ctx.db) {
841 TypeLongId::Var(_) | TypeLongId::ImplType(_) => {
842 let inference = &mut ctx.resolver.inference();
843 let desnap_expr_type =
845 inference.new_type_var(Some(inner.stable_ptr(db).untyped()));
846 let desnapped_expr_type_var =
847 TypeLongId::Snapshot(desnap_expr_type).intern(ctx.db);
848 if let Err(err_set) =
849 inference.conform_ty(desnapped_expr_type_var, desnapped_expr_type)
850 {
851 let diag_added = ctx.diagnostics.report(
852 syntax.stable_ptr(db),
853 WrongArgumentType {
854 expected_ty: desnapped_expr_type_var,
855 actual_ty: desnapped_expr_type,
856 },
857 );
858 inference.consume_reported_error(err_set, diag_added);
859 return Err(diag_added);
860 };
861 ctx.reduce_ty(desnap_expr_type)
862 }
863 TypeLongId::Snapshot(ty) => ty,
864 _ => {
865 return Err(ctx
866 .diagnostics
867 .report(unary_op.stable_ptr(db), DesnapNonSnapshot));
868 }
869 };
870 (desnapped_expr, desnapped_ty)
871 };
872
873 Ok(Expr::Desnap(ExprDesnap {
874 inner: desnapped_expr.id,
875 ty: desnapped_ty,
876 stable_ptr: syntax.stable_ptr(db).into(),
877 }))
878 }
879 (_, inner) => {
880 let expr = compute_expr_semantic(ctx, inner);
881
882 let concrete_trait_function = match core_unary_operator(
883 ctx.db,
884 &mut ctx.resolver.inference(),
885 &unary_op,
886 syntax.stable_ptr(db).untyped(),
887 )? {
888 Err(err_kind) => {
889 return Err(ctx.diagnostics.report(unary_op.stable_ptr(db), err_kind));
890 }
891 Ok(function) => function,
892 };
893
894 let impl_lookup_context = ctx.resolver.impl_lookup_context();
895 let inference = &mut ctx.resolver.inference();
896 let function = inference
897 .infer_trait_function(
898 concrete_trait_function,
899 &impl_lookup_context,
900 Some(syntax.stable_ptr(db).untyped()),
901 )
902 .map_err(|err_set| {
903 inference.report_on_pending_error(
904 err_set,
905 ctx.diagnostics,
906 syntax.stable_ptr(db).untyped(),
907 )
908 })?;
909
910 expr_function_call(
911 ctx,
912 function,
913 vec![NamedArg(expr, None, Mutability::Immutable)],
914 syntax.stable_ptr(db),
915 syntax.stable_ptr(db).into(),
916 )
917 }
918 }
919}
920
921fn compute_expr_binary_semantic(
922 ctx: &mut ComputationContext<'_>,
923 syntax: &ast::ExprBinary,
924) -> Maybe<Expr> {
925 let db = ctx.db;
926
927 let stable_ptr = syntax.stable_ptr(db).into();
928 let binary_op = syntax.op(db);
929 let lhs_syntax = &syntax.lhs(db);
930 let rhs_syntax = syntax.rhs(db);
931
932 match binary_op {
933 ast::BinaryOperator::Dot(_) => {
934 let lexpr = compute_expr_semantic(ctx, lhs_syntax);
935 dot_expr(ctx, lexpr, rhs_syntax, stable_ptr)
936 }
937 ast::BinaryOperator::Eq(_) => {
938 let lexpr = compute_expr_semantic(ctx, lhs_syntax);
939 let rexpr = compute_expr_semantic(ctx, &rhs_syntax);
940
941 let member_path = match lexpr.expr {
942 Expr::Var(expr) => ExprVarMemberPath::Var(expr),
943 Expr::MemberAccess(ExprMemberAccess { member_path: Some(ref_arg), .. }) => ref_arg,
944 _ => {
945 return Err(ctx
946 .diagnostics
947 .report(lhs_syntax.stable_ptr(db), InvalidLhsForAssignment));
948 }
949 };
950
951 let inference = &mut ctx.resolver.inference();
952 inference.conform_ty_for_diag(
953 rexpr.ty(),
954 member_path.ty(),
955 ctx.diagnostics,
956 || rhs_syntax.stable_ptr(db).untyped(),
957 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
958 )?;
959 if !ctx.semantic_defs[&member_path.base_var()].is_mut() {
961 ctx.diagnostics.report(syntax.stable_ptr(db), AssignmentToImmutableVar);
962 }
963 Ok(Expr::Assignment(ExprAssignment {
964 ref_arg: member_path,
965 rhs: rexpr.id,
966 ty: unit_ty(db),
967 stable_ptr,
968 }))
969 }
970 ast::BinaryOperator::AndAnd(_) | ast::BinaryOperator::OrOr(_) => {
971 let lexpr = compute_expr_semantic(ctx, lhs_syntax);
972 let rexpr = compute_expr_semantic(ctx, &rhs_syntax);
973
974 let op = match binary_op {
975 ast::BinaryOperator::AndAnd(_) => LogicalOperator::AndAnd,
976 ast::BinaryOperator::OrOr(_) => LogicalOperator::OrOr,
977 _ => unreachable!(),
978 };
979
980 let inference = &mut ctx.resolver.inference();
981 let bool_ty = core_bool_ty(db);
982 let _ = inference.conform_ty_for_diag(
983 lexpr.expr.ty(),
984 bool_ty,
985 ctx.diagnostics,
986 || lhs_syntax.stable_ptr(db).untyped(),
987 |actual_ty, expected_ty| WrongType { expected_ty, actual_ty },
988 );
989 let _ = inference.conform_ty_for_diag(
990 rexpr.expr.ty(),
991 bool_ty,
992 ctx.diagnostics,
993 || rhs_syntax.stable_ptr(db).untyped(),
994 |actual_ty, expected_ty| WrongType { expected_ty, actual_ty },
995 );
996
997 Ok(Expr::LogicalOperator(ExprLogicalOperator {
998 lhs: lexpr.id,
999 op,
1000 rhs: rexpr.id,
1001 ty: bool_ty,
1002 stable_ptr,
1003 }))
1004 }
1005 _ => call_core_binary_op(ctx, syntax, lhs_syntax, &rhs_syntax),
1006 }
1007}
1008
1009fn call_core_binary_op(
1011 ctx: &mut ComputationContext<'_>,
1012 syntax: &ast::ExprBinary,
1013 lhs_syntax: &ast::Expr,
1014 rhs_syntax: &ast::Expr,
1015) -> Maybe<Expr> {
1016 let db = ctx.db;
1017 let stable_ptr = syntax.stable_ptr(db);
1018 let binary_op = syntax.op(db);
1019
1020 let (concrete_trait_function, snapshot) = match core_binary_operator(
1021 db,
1022 &mut ctx.resolver.inference(),
1023 &binary_op,
1024 stable_ptr.untyped(),
1025 )? {
1026 Err(err_kind) => {
1027 return Err(ctx.diagnostics.report(binary_op.stable_ptr(db), err_kind));
1028 }
1029 Ok(res) => res,
1030 };
1031
1032 let impl_lookup_context = ctx.resolver.impl_lookup_context();
1033 let inference = &mut ctx.resolver.inference();
1034 let function = inference
1035 .infer_trait_function(
1036 concrete_trait_function,
1037 &impl_lookup_context,
1038 Some(stable_ptr.untyped()),
1039 )
1040 .map_err(|err_set| {
1041 inference.report_on_pending_error(err_set, ctx.diagnostics, stable_ptr.untyped())
1042 })?;
1043
1044 let mut lexpr = compute_expr_semantic(ctx, lhs_syntax);
1045
1046 if let (Expr::Missing(_), BinaryOperator::LT(_)) = (&lexpr.expr, &binary_op) {
1047 return Err(ctx
1048 .diagnostics
1049 .report(binary_op.stable_ptr(db), SemanticDiagnosticKind::MaybeMissingColonColon));
1050 }
1051
1052 let mut rexpr = compute_expr_semantic(ctx, rhs_syntax);
1053
1054 ctx.reduce_ty(lexpr.ty()).check_not_missing(db)?;
1055 ctx.reduce_ty(rexpr.ty()).check_not_missing(db)?;
1056
1057 if snapshot {
1058 let ty = TypeLongId::Snapshot(lexpr.ty()).intern(ctx.db);
1059 let expr =
1060 Expr::Snapshot(ExprSnapshot { inner: lexpr.id, ty, stable_ptr: lexpr.stable_ptr() });
1061 lexpr = ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) };
1062 let ty = TypeLongId::Snapshot(rexpr.ty()).intern(ctx.db);
1063 let expr =
1064 Expr::Snapshot(ExprSnapshot { inner: rexpr.id, ty, stable_ptr: rexpr.stable_ptr() });
1065 rexpr = ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) };
1066 }
1067
1068 let sig = ctx.db.concrete_function_signature(function)?;
1069 let first_param = sig.params.into_iter().next().unwrap();
1070
1071 expr_function_call(
1072 ctx,
1073 function,
1074 vec![
1075 NamedArg(lexpr, None, first_param.mutability),
1076 NamedArg(rexpr, None, Mutability::Immutable),
1077 ],
1078 stable_ptr,
1079 stable_ptr.into(),
1080 )
1081}
1082
1083fn compute_expr_tuple_semantic(
1084 ctx: &mut ComputationContext<'_>,
1085 syntax: &ast::ExprListParenthesized,
1086) -> Maybe<Expr> {
1087 let db = ctx.db;
1088
1089 let mut items: Vec<ExprId> = vec![];
1090 let mut types: Vec<TypeId> = vec![];
1091 for expr_syntax in syntax.expressions(db).elements(db) {
1092 let expr_semantic = compute_expr_semantic(ctx, &expr_syntax);
1093 types.push(ctx.reduce_ty(expr_semantic.ty()));
1094 items.push(expr_semantic.id);
1095 }
1096 Ok(Expr::Tuple(ExprTuple {
1097 items,
1098 ty: TypeLongId::Tuple(types).intern(db),
1099 stable_ptr: syntax.stable_ptr(db).into(),
1100 }))
1101}
1102fn compute_expr_fixed_size_array_semantic(
1104 ctx: &mut ComputationContext<'_>,
1105 syntax: &ast::ExprFixedSizeArray,
1106) -> Maybe<Expr> {
1107 let db = ctx.db;
1108 let exprs = syntax.exprs(db).elements_vec(db);
1109 let size_ty = get_usize_ty(db);
1110 let (items, type_id, size) = if let Some(size_const_id) =
1111 extract_fixed_size_array_size(db, ctx.diagnostics, syntax, &ctx.resolver)?
1112 {
1113 let [expr] = exprs.as_slice() else {
1115 return Err(ctx
1116 .diagnostics
1117 .report(syntax.stable_ptr(db), FixedSizeArrayNonSingleValue));
1118 };
1119 let expr_semantic = compute_expr_semantic(ctx, expr);
1120 let size = size_const_id
1121 .lookup_intern(db)
1122 .into_int()
1123 .ok_or_else(|| {
1124 ctx.diagnostics.report(syntax.stable_ptr(db), FixedSizeArrayNonNumericSize)
1125 })?
1126 .to_usize()
1127 .unwrap();
1128 verify_fixed_size_array_size(db, ctx.diagnostics, &size.into(), syntax)?;
1129 (
1130 FixedSizeArrayItems::ValueAndSize(expr_semantic.id, size_const_id),
1131 expr_semantic.ty(),
1132 size_const_id,
1133 )
1134 } else if let Some((first_expr, tail_exprs)) = exprs.split_first() {
1135 let size = ConstValue::Int((tail_exprs.len() + 1).into(), size_ty).intern(db);
1136 let first_expr_semantic = compute_expr_semantic(ctx, first_expr);
1137 let mut items: Vec<ExprId> = vec![first_expr_semantic.id];
1138 let first_expr_ty = ctx.reduce_ty(first_expr_semantic.ty());
1141 for expr_syntax in tail_exprs {
1142 let expr_semantic = compute_expr_semantic(ctx, expr_syntax);
1143 let inference = &mut ctx.resolver.inference();
1144 inference.conform_ty_for_diag(
1145 expr_semantic.ty(),
1146 first_expr_ty,
1147 ctx.diagnostics,
1148 || expr_syntax.stable_ptr(db).untyped(),
1149 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
1150 )?;
1151 items.push(expr_semantic.id);
1152 }
1153 (FixedSizeArrayItems::Items(items), first_expr_ty, size)
1154 } else {
1155 (
1156 FixedSizeArrayItems::Items(vec![]),
1157 ctx.resolver.inference().new_type_var(Some(syntax.stable_ptr(db).untyped())),
1158 ConstValue::Int(0.into(), size_ty).intern(db),
1159 )
1160 };
1161 Ok(Expr::FixedSizeArray(ExprFixedSizeArray {
1162 items,
1163 ty: TypeLongId::FixedSizeArray { type_id, size }.intern(db),
1164 stable_ptr: syntax.stable_ptr(db).into(),
1165 }))
1166}
1167
1168fn compute_expr_function_call_semantic(
1169 ctx: &mut ComputationContext<'_>,
1170 syntax: &ast::ExprFunctionCall,
1171) -> Maybe<Expr> {
1172 let db = ctx.db;
1173
1174 let path = syntax.path(db);
1175 let args_syntax = syntax.arguments(db).arguments(db);
1176 let mut is_shadowed_by_variable = false;
1178 if let Some((identifier, is_callsite_prefixed)) = try_extract_identifier_from_path(db, &path) {
1179 let variable_name = identifier.text(ctx.db);
1180 if let Some(var) = get_binded_expr_by_name(
1181 ctx,
1182 &variable_name,
1183 is_callsite_prefixed,
1184 path.stable_ptr(ctx.db).into(),
1185 ) {
1186 is_shadowed_by_variable = true;
1187 if ctx.are_closures_in_context {
1189 let info = db.core_info();
1190 let fn_once_trait = info.fn_once_trt;
1192 let fn_trait = info.fn_trt;
1193 let self_expr = ExprAndId { expr: var.clone(), id: ctx.arenas.exprs.alloc(var) };
1194 let mut closure_call_data = |call_trait| {
1195 compute_method_function_call_data(
1196 ctx,
1197 &[call_trait],
1198 "call".into(),
1199 self_expr.clone(),
1200 syntax.stable_ptr(db).untyped(),
1201 None,
1202 |ty, _, inference_errors| {
1203 if call_trait == fn_once_trait {
1204 Some(CallExpressionRequiresFunction { ty, inference_errors })
1205 } else {
1206 None
1207 }
1208 },
1209 |_, _, _| {
1210 unreachable!(
1211 "There is one explicit trait, FnOnce trait. No implementations of \
1212 the trait, caused by both lack of implementation or multiple \
1213 implementations of the trait, are handled in \
1214 NoImplementationOfTrait function."
1215 )
1216 },
1217 )
1218 };
1219 let (call_function_id, _, fixed_closure, closure_mutability) =
1220 closure_call_data(fn_trait).or_else(|_| closure_call_data(fn_once_trait))?;
1221
1222 let args_iter = args_syntax.elements(db);
1223 let mut args = vec![];
1225 let mut arg_types = vec![];
1226 for arg_syntax in args_iter {
1227 let stable_ptr = arg_syntax.stable_ptr(db);
1228 let arg = compute_named_argument_clause(ctx, arg_syntax, None);
1229 if arg.2 != Mutability::Immutable {
1230 return Err(ctx.diagnostics.report(stable_ptr, RefClosureArgument));
1231 }
1232 args.push(arg.0.id);
1233 arg_types.push(arg.0.ty());
1234 }
1235 let args_expr = Expr::Tuple(ExprTuple {
1236 items: args,
1237 ty: TypeLongId::Tuple(arg_types).intern(db),
1238 stable_ptr: syntax.stable_ptr(db).into(),
1239 });
1240 let args_expr =
1241 ExprAndId { expr: args_expr.clone(), id: ctx.arenas.exprs.alloc(args_expr) };
1242 let call_ptr = syntax.stable_ptr(db);
1243 return expr_function_call(
1244 ctx,
1245 call_function_id,
1246 vec![
1247 NamedArg(fixed_closure, None, closure_mutability),
1248 NamedArg(args_expr, None, Mutability::Immutable),
1249 ],
1250 call_ptr,
1251 call_ptr.into(),
1252 );
1253 }
1254 }
1255 }
1256
1257 let item = ctx
1258 .resolver
1259 .resolve_concrete_path_ex(
1260 ctx.diagnostics,
1261 &path,
1262 NotFoundItemType::Function,
1263 ResolutionContext::Statement(&mut ctx.environment),
1264 )
1265 .inspect_err(|_| {
1266 for arg in args_syntax.elements(db) {
1268 compute_named_argument_clause(ctx, arg, None);
1269 }
1270 })?;
1271
1272 match item {
1273 ResolvedConcreteItem::Variant(variant) => {
1274 let concrete_enum_type =
1275 TypeLongId::Concrete(ConcreteTypeId::Enum(variant.concrete_enum_id)).intern(db);
1276 if concrete_enum_type.is_phantom(db) {
1277 ctx.diagnostics.report(syntax.stable_ptr(db), CannotCreateInstancesOfPhantomTypes);
1278 }
1279
1280 let named_args: Vec<_> = args_syntax
1283 .elements(db)
1284 .map(|arg_syntax| compute_named_argument_clause(ctx, arg_syntax, None))
1285 .collect();
1286 if named_args.len() != 1 {
1287 return Err(ctx.diagnostics.report(
1288 syntax.stable_ptr(db),
1289 WrongNumberOfArguments { expected: 1, actual: named_args.len() },
1290 ));
1291 }
1292 let NamedArg(arg, name_terminal, mutability) = named_args[0].clone();
1293 if let Some(name_terminal) = name_terminal {
1294 ctx.diagnostics.report(name_terminal.stable_ptr(db), NamedArgumentsAreNotSupported);
1295 }
1296 if mutability != Mutability::Immutable {
1297 return Err(ctx
1298 .diagnostics
1299 .report(args_syntax.stable_ptr(db), VariantCtorNotImmutable));
1300 }
1301 let inference = &mut ctx.resolver.inference();
1302 inference.conform_ty_for_diag(
1303 arg.ty(),
1304 variant.ty,
1305 ctx.diagnostics,
1306 || args_syntax.stable_ptr(db).untyped(),
1307 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
1308 )?;
1309 Ok(semantic::Expr::EnumVariantCtor(semantic::ExprEnumVariantCtor {
1310 variant,
1311 value_expr: arg.id,
1312 ty: concrete_enum_type,
1313 stable_ptr: syntax.stable_ptr(db).into(),
1314 }))
1315 }
1316 ResolvedConcreteItem::Function(function) => {
1317 if is_shadowed_by_variable {
1318 return Err(ctx.diagnostics.report(
1319 path.stable_ptr(ctx.db),
1320 CallingShadowedFunction {
1321 shadowed_function_name: path
1322 .segments(db)
1323 .elements(db)
1324 .next()
1325 .unwrap()
1326 .identifier(db),
1327 },
1328 ));
1329 }
1330 let mut args_iter = args_syntax.elements(db);
1335 let mut named_args = vec![];
1337 let closure_params = concrete_function_closure_params(db, function)?;
1338 for ty in function_parameter_types(ctx, function)? {
1339 let Some(arg_syntax) = args_iter.next() else {
1340 continue;
1341 };
1342 named_args.push(compute_named_argument_clause(
1343 ctx,
1344 arg_syntax,
1345 closure_params.get(&ty).copied(),
1346 ));
1347 }
1348
1349 if let Some(arg_syntax) = args_iter.next() {
1351 named_args.push(compute_named_argument_clause(ctx, arg_syntax, None));
1352 }
1353 let call_ptr = syntax.stable_ptr(db);
1354 expr_function_call(ctx, function, named_args, call_ptr, call_ptr.into())
1355 }
1356 _ => Err(ctx.diagnostics.report(
1357 path.stable_ptr(db),
1358 UnexpectedElement { expected: vec![ElementKind::Function], actual: (&item).into() },
1359 )),
1360 }
1361}
1362
1363pub fn compute_named_argument_clause(
1367 ctx: &mut ComputationContext<'_>,
1368 arg_syntax: ast::Arg,
1369 closure_params_tuple_ty: Option<TypeId>,
1370) -> NamedArg {
1371 let db = ctx.db;
1372
1373 let mutability =
1374 compute_mutability(ctx.diagnostics, db, &arg_syntax.modifiers(db).elements_vec(db));
1375
1376 let arg_clause = arg_syntax.arg_clause(db);
1377 let (expr, arg_name_identifier) = match arg_clause {
1378 ast::ArgClause::Unnamed(arg_unnamed) => (
1379 handle_possible_closure_expr(ctx, &arg_unnamed.value(db), closure_params_tuple_ty),
1380 None,
1381 ),
1382 ast::ArgClause::Named(arg_named) => (
1383 handle_possible_closure_expr(ctx, &arg_named.value(db), closure_params_tuple_ty),
1384 Some(arg_named.name(db)),
1385 ),
1386 ast::ArgClause::FieldInitShorthand(arg_field_init_shorthand) => {
1387 let name_expr = arg_field_init_shorthand.name(db);
1388 let stable_ptr: ast::ExprPtr = name_expr.stable_ptr(db).into();
1389 let arg_name_identifier = name_expr.name(db);
1390 let maybe_expr = resolve_variable_by_name(ctx, &arg_name_identifier, stable_ptr);
1391 let expr = wrap_maybe_with_missing(ctx, maybe_expr, stable_ptr);
1392 let expr = ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) };
1393 (expr, Some(arg_name_identifier))
1394 }
1395 };
1396 NamedArg(expr, arg_name_identifier, mutability)
1397}
1398
1399fn handle_possible_closure_expr(
1404 ctx: &mut ComputationContext<'_>,
1405 expr: &ast::Expr,
1406 closure_param_types: Option<TypeId>,
1407) -> ExprAndId {
1408 if let ast::Expr::Closure(expr_closure) = expr {
1409 let expr = compute_expr_closure_semantic(ctx, expr_closure, closure_param_types);
1410 let expr = wrap_maybe_with_missing(ctx, expr, expr_closure.stable_ptr(ctx.db).into());
1411 let id = ctx.arenas.exprs.alloc(expr.clone());
1412 ExprAndId { expr, id }
1413 } else {
1414 compute_expr_semantic(ctx, expr)
1415 }
1416}
1417
1418pub fn compute_root_expr(
1419 ctx: &mut ComputationContext<'_>,
1420 syntax: &ast::ExprBlock,
1421 return_type: TypeId,
1422) -> Maybe<ExprId> {
1423 let inference = &mut ctx.resolver.data.inference_data.inference(ctx.db);
1425 for param in &ctx.resolver.data.generic_params {
1426 let Ok(GenericParam::Impl(imp)) = ctx.db.generic_param_semantic(*param) else {
1427 continue;
1428 };
1429 let Ok(concrete_trait_id) = imp.concrete_trait else {
1430 continue;
1431 };
1432 if crate::corelib::fn_traits(ctx.db).contains(&concrete_trait_id.trait_id(ctx.db)) {
1433 ctx.are_closures_in_context = true;
1434 }
1435 }
1436 let constrains =
1437 ctx.db.generic_params_type_constraints(ctx.resolver.data.generic_params.clone());
1438 inference.conform_generic_params_type_constraints(&constrains);
1439
1440 let return_type = ctx.reduce_ty(return_type);
1441 let res = compute_expr_block_semantic(ctx, syntax)?;
1442 let res_ty = ctx.reduce_ty(res.ty());
1443 let res = ctx.arenas.exprs.alloc(res);
1444 let inference = &mut ctx.resolver.inference();
1445 let db = ctx.db;
1446 let _ = inference.conform_ty_for_diag(
1447 res_ty,
1448 return_type,
1449 ctx.diagnostics,
1450 || {
1451 ctx.signature
1452 .map(|s| match s.stable_ptr.lookup(db).ret_ty(db) {
1453 OptionReturnTypeClause::Empty(_) => syntax.stable_ptr(db).untyped(),
1454 OptionReturnTypeClause::ReturnTypeClause(return_type_clause) => {
1455 return_type_clause.ty(db).stable_ptr(db).untyped()
1456 }
1457 })
1458 .unwrap_or_else(|| syntax.stable_ptr(db).untyped())
1459 },
1460 |actual_ty, expected_ty| WrongReturnType { expected_ty, actual_ty },
1461 );
1462
1463 inference.finalize(ctx.diagnostics, syntax.stable_ptr(db).untyped());
1465
1466 ctx.apply_inference_rewriter();
1467 if ctx.signature.map(|s| s.is_const) == Some(true) {
1468 validate_const_expr(ctx, res);
1469 }
1470 Ok(res)
1471}
1472
1473pub fn compute_statements_semantic_and_extend(
1475 ctx: &mut ComputationContext<'_>,
1476 statements_syntax: impl Iterator<Item = ast::Statement>,
1477 statement_ids: &mut Vec<StatementId>,
1478) {
1479 for statement_syntax in statements_syntax {
1480 compute_and_append_statement_semantic(ctx, statement_syntax, statement_ids)
1481 .unwrap_or_default();
1482 }
1483}
1484
1485pub fn compute_expr_block_semantic(
1487 ctx: &mut ComputationContext<'_>,
1488 syntax: &ast::ExprBlock,
1489) -> Maybe<Expr> {
1490 let db = ctx.db;
1491 ctx.run_in_subscope(|new_ctx| {
1492 let (statements, tail) = statements_and_tail(db, syntax.statements(db));
1493 let mut statements_semantic = vec![];
1494 compute_statements_semantic_and_extend(new_ctx, statements, &mut statements_semantic);
1495 let tail_semantic_expr =
1496 tail.map(|tail| compute_tail_semantic(new_ctx, &tail, &mut statements_semantic));
1497 let ty = block_ty(new_ctx, &statements_semantic, &tail_semantic_expr);
1498 Ok(Expr::Block(ExprBlock {
1499 statements: statements_semantic,
1500 tail: tail_semantic_expr.map(|expr| expr.id),
1501 ty,
1502 stable_ptr: syntax.stable_ptr(db).into(),
1503 }))
1504 })
1505}
1506
1507fn block_ty(
1509 ctx: &ComputationContext<'_>,
1510 statements: &[StatementId],
1511 tail: &Option<ExprAndId>,
1512) -> TypeId {
1513 if let Some(tail) = tail {
1514 return tail.ty();
1515 }
1516 let Some(statement) = statements
1517 .iter()
1518 .rev()
1519 .map(|id| &ctx.arenas.statements[*id])
1520 .find(|s| !matches!(s, Statement::Item(_)))
1521 else {
1522 return unit_ty(ctx.db);
1523 };
1524 match statement {
1525 Statement::Item(_) => unreachable!("Was previously filtered out."),
1526 Statement::Let(_) => unit_ty(ctx.db),
1527 Statement::Return(_) | Statement::Break(_) | Statement::Continue(_) => never_ty(ctx.db),
1528 Statement::Expr(expr) => {
1529 let never_ty = never_ty(ctx.db);
1530 if ctx.arenas.exprs[expr.expr].ty() == never_ty { never_ty } else { unit_ty(ctx.db) }
1531 }
1532 }
1533}
1534
1535#[derive(Debug, Clone)]
1537struct FlowMergeTypeHelper {
1538 multi_arm_expr_kind: MultiArmExprKind,
1539 never_type: TypeId,
1540 final_type: Option<TypeId>,
1541 had_merge_error: bool,
1543}
1544impl FlowMergeTypeHelper {
1545 fn new(db: &dyn SemanticGroup, multi_arm_expr_kind: MultiArmExprKind) -> Self {
1546 Self {
1547 multi_arm_expr_kind,
1548 never_type: never_ty(db),
1549 final_type: None,
1550 had_merge_error: false,
1551 }
1552 }
1553
1554 fn try_merge_types(
1558 &mut self,
1559 db: &dyn SemanticGroup,
1560 diagnostics: &mut SemanticDiagnostics,
1561 inference: &mut Inference<'_>,
1562 ty: TypeId,
1563 stable_ptr: SyntaxStablePtrId,
1564 ) -> bool {
1565 if self.had_merge_error {
1566 return false;
1567 }
1568
1569 if (ty == never_ty(db) && self.multi_arm_expr_kind != MultiArmExprKind::Loop)
1571 || ty.is_missing(db)
1572 {
1573 return true;
1574 }
1575
1576 if let Some(pending) = &self.final_type {
1577 if let Err(err_set) = inference.conform_ty(ty, *pending) {
1578 let diag_added = diagnostics.report(
1579 stable_ptr,
1580 IncompatibleArms {
1581 multi_arm_expr_kind: self.multi_arm_expr_kind,
1582 pending_ty: *pending,
1583 different_ty: ty,
1584 },
1585 );
1586 inference.consume_reported_error(err_set, diag_added);
1587 self.had_merge_error = true;
1588 return false;
1589 }
1590 } else {
1591 self.final_type = Some(ty);
1592 }
1593
1594 true
1595 }
1596
1597 fn get_final_type(self) -> TypeId {
1599 self.final_type.unwrap_or(self.never_type)
1600 }
1601}
1602
1603fn compute_arm_semantic(
1605 ctx: &mut ComputationContext<'_>,
1606 expr: &Expr,
1607 arm_expr_syntax: ast::Expr,
1608 patterns_syntax: &PatternListOr,
1609) -> (Vec<PatternAndId>, ExprAndId) {
1610 ctx.run_in_subscope(|new_ctx| {
1611 let patterns = compute_pattern_list_or_semantic(new_ctx, expr, patterns_syntax);
1612 let arm_expr = compute_expr_semantic(new_ctx, &arm_expr_syntax);
1613 (patterns, arm_expr)
1614 })
1615}
1616
1617fn compute_pattern_list_or_semantic(
1619 ctx: &mut ComputationContext<'_>,
1620 expr: &Expr,
1621 patterns_syntax: &PatternListOr,
1622) -> Vec<PatternAndId> {
1623 let db = ctx.db;
1624
1625 let mut arm_patterns_variables: UnorderedHashMap<SmolStr, LocalVariable> =
1629 UnorderedHashMap::default();
1630
1631 let patterns: Vec<_> = patterns_syntax
1632 .elements(db)
1633 .map(|pattern_syntax| {
1634 let pattern: PatternAndId = compute_pattern_semantic(
1635 ctx,
1636 &pattern_syntax,
1637 expr.ty(),
1638 &mut arm_patterns_variables,
1639 );
1640 let variables = pattern.variables(&ctx.arenas.patterns);
1641 for variable in variables {
1642 match arm_patterns_variables.entry(variable.name.clone()) {
1643 std::collections::hash_map::Entry::Occupied(entry) => {
1644 let get_location = || variable.stable_ptr.lookup(db).stable_ptr(db);
1645 let var = entry.get();
1646
1647 let expected_ty = ctx.reduce_ty(var.ty);
1648 let actual_ty = ctx.reduce_ty(variable.var.ty);
1649
1650 let mut has_inference_error = false;
1651 if !variable.var.ty.is_missing(ctx.db) {
1652 let inference = &mut ctx.resolver.inference();
1653 if inference
1654 .conform_ty_for_diag(
1655 actual_ty,
1656 expected_ty,
1657 ctx.diagnostics,
1658 || get_location().untyped(),
1659 |actual_ty, expected_ty| WrongType { expected_ty, actual_ty },
1660 )
1661 .is_err()
1662 {
1663 has_inference_error = true;
1664 }
1665 };
1666 if !has_inference_error && var.is_mut != variable.var.is_mut {
1667 ctx.diagnostics.report(get_location(), InconsistentBinding);
1668 }
1669 }
1670 std::collections::hash_map::Entry::Vacant(entry) => {
1671 entry.insert(variable.var.clone());
1672 }
1673 }
1674 }
1675 pattern
1676 })
1677 .collect();
1678
1679 for (pattern_syntax, pattern) in patterns_syntax.elements(db).zip(patterns.iter()) {
1680 let variables = pattern.variables(&ctx.arenas.patterns);
1681
1682 if variables.len() != arm_patterns_variables.len() {
1683 ctx.diagnostics.report(pattern_syntax.stable_ptr(db), MissingVariableInPattern);
1684 }
1685
1686 for v in variables {
1687 let var_def = Binding::LocalVar(v.var.clone());
1688 ctx.environment.variables.insert(v.name.clone(), var_def.clone());
1691 ctx.semantic_defs.insert(var_def.id(), var_def);
1692 }
1693 }
1694
1695 patterns
1696}
1697
1698fn compute_expr_match_semantic(
1700 ctx: &mut ComputationContext<'_>,
1701 syntax: &ast::ExprMatch,
1702) -> Maybe<Expr> {
1703 let db = ctx.db;
1705
1706 let syntax_arms = syntax.arms(db).elements(db);
1707 let expr = compute_expr_semantic(ctx, &syntax.expr(db));
1708 let patterns_and_exprs: Vec<_> = syntax_arms
1711 .map(|syntax_arm| {
1712 compute_arm_semantic(ctx, &expr, syntax_arm.expression(db), &syntax_arm.patterns(db))
1713 })
1714 .collect();
1715 let mut helper = FlowMergeTypeHelper::new(ctx.db, MultiArmExprKind::Match);
1717 for (_, expr) in &patterns_and_exprs {
1718 let expr_ty = ctx.reduce_ty(expr.ty());
1719 if !helper.try_merge_types(
1720 ctx.db,
1721 ctx.diagnostics,
1722 &mut ctx.resolver.inference(),
1723 expr_ty,
1724 expr.stable_ptr().untyped(),
1725 ) {
1726 break;
1727 };
1728 }
1729 let semantic_arms = patterns_and_exprs
1731 .into_iter()
1732 .map(|(patterns, arm_expr)| MatchArm {
1733 patterns: patterns.iter().map(|pattern| pattern.id).collect(),
1734 expression: arm_expr.id,
1735 })
1736 .collect();
1737 Ok(Expr::Match(ExprMatch {
1738 matched_expr: expr.id,
1739 arms: semantic_arms,
1740 ty: helper.get_final_type(),
1741 stable_ptr: syntax.stable_ptr(db).into(),
1742 }))
1743}
1744
1745fn compute_expr_if_semantic(ctx: &mut ComputationContext<'_>, syntax: &ast::ExprIf) -> Maybe<Expr> {
1747 let db = ctx.db;
1748
1749 let (conditions, if_block) = compute_condition_list_semantic(
1750 ctx,
1751 &syntax.conditions(db),
1752 &ast::Expr::Block(syntax.if_block(db)),
1753 );
1754
1755 let (else_block_opt, else_block_ty) = match syntax.else_clause(db) {
1756 ast::OptionElseClause::Empty(_) => (None, unit_ty(ctx.db)),
1757 ast::OptionElseClause::ElseClause(else_clause) => match else_clause.else_block_or_if(db) {
1758 BlockOrIf::Block(block) => {
1759 let else_block = compute_expr_block_semantic(ctx, &block)?;
1760 (Some(else_block.clone()), else_block.ty())
1761 }
1762 BlockOrIf::If(expr_if) => {
1763 let else_if = compute_expr_if_semantic(ctx, &expr_if)?;
1764 (Some(else_if.clone()), else_if.ty())
1765 }
1766 },
1767 };
1768
1769 let mut helper = FlowMergeTypeHelper::new(ctx.db, MultiArmExprKind::If);
1770 let if_block_ty = ctx.reduce_ty(if_block.ty());
1771 let else_block_ty = ctx.reduce_ty(else_block_ty);
1772 let inference = &mut ctx.resolver.inference();
1773 let _ = helper.try_merge_types(
1774 ctx.db,
1775 ctx.diagnostics,
1776 inference,
1777 if_block_ty,
1778 syntax.stable_ptr(db).untyped(),
1779 ) && helper.try_merge_types(
1780 ctx.db,
1781 ctx.diagnostics,
1782 inference,
1783 else_block_ty,
1784 syntax.stable_ptr(db).untyped(),
1785 );
1786 Ok(Expr::If(ExprIf {
1787 conditions,
1788 if_block: if_block.id,
1789 else_block: else_block_opt.map(|else_block| ctx.arenas.exprs.alloc(else_block)),
1790 ty: helper.get_final_type(),
1791 stable_ptr: syntax.stable_ptr(db).into(),
1792 }))
1793}
1794
1795fn compute_condition_list_semantic(
1799 ctx: &mut ComputationContext<'_>,
1800 condition_list_syntax: &ConditionListAnd,
1801 body_syntax: &ast::Expr,
1802) -> (Vec<Condition>, ExprAndId) {
1803 let mut conditions = Vec::new();
1804 let conditions_syntax = condition_list_syntax.elements(ctx.db);
1805 conditions.reserve(conditions_syntax.len());
1806
1807 let body = compute_condition_list_semantic_helper(
1808 ctx,
1809 conditions_syntax,
1810 &mut conditions,
1811 body_syntax,
1812 );
1813
1814 (conditions, body)
1815}
1816
1817fn compute_condition_list_semantic_helper(
1819 ctx: &mut ComputationContext<'_>,
1820 mut conditions_syntax: impl Iterator<Item = ast::Condition>,
1821 conditions: &mut Vec<Condition>,
1822 body_syntax: &ast::Expr,
1823) -> ExprAndId {
1824 match conditions_syntax.next() {
1825 None => compute_expr_semantic(ctx, body_syntax),
1826 Some(ast::Condition::Let(condition)) => {
1827 let expr = compute_expr_semantic(ctx, &condition.expr(ctx.db));
1828
1829 ctx.run_in_subscope(|new_ctx| {
1830 let patterns =
1831 compute_pattern_list_or_semantic(new_ctx, &expr, &condition.patterns(ctx.db));
1832 conditions.push(Condition::Let(
1833 expr.id,
1834 patterns.iter().map(|pattern| pattern.id).collect(),
1835 ));
1836 compute_condition_list_semantic_helper(
1837 new_ctx,
1838 conditions_syntax,
1839 conditions,
1840 body_syntax,
1841 )
1842 })
1843 }
1844 Some(ast::Condition::Expr(expr)) => {
1845 conditions.push(Condition::BoolExpr(
1846 compute_bool_condition_semantic(ctx, &expr.expr(ctx.db)).id,
1847 ));
1848
1849 compute_condition_list_semantic_helper(ctx, conditions_syntax, conditions, body_syntax)
1850 }
1851 }
1852}
1853
1854fn compute_expr_loop_semantic(
1856 ctx: &mut ComputationContext<'_>,
1857 syntax: &ast::ExprLoop,
1858) -> Maybe<Expr> {
1859 let db = ctx.db;
1860
1861 let (body, inner_ctx) = compute_loop_body_semantic(
1862 ctx,
1863 syntax.body(db),
1864 InnerContextKind::Loop {
1865 type_merger: FlowMergeTypeHelper::new(db, MultiArmExprKind::Loop),
1866 },
1867 );
1868
1869 let InnerContext { kind: InnerContextKind::Loop { type_merger, .. }, .. } = inner_ctx else {
1870 unreachable!("Expected loop context");
1871 };
1872 Ok(Expr::Loop(ExprLoop {
1873 body,
1874 ty: type_merger.get_final_type(),
1875 stable_ptr: syntax.stable_ptr(db).into(),
1876 }))
1877}
1878
1879fn compute_expr_while_semantic(
1881 ctx: &mut ComputationContext<'_>,
1882 syntax: &ast::ExprWhile,
1883) -> Maybe<Expr> {
1884 let db = ctx.db;
1885
1886 let Some([condition_syntax]) = &syntax.conditions(db).elements(db).collect_array() else {
1887 return Err(ctx.diagnostics.report(syntax.conditions(db).stable_ptr(db), Unsupported));
1888 };
1889
1890 let (condition, body) = match condition_syntax {
1891 ast::Condition::Let(condition) => {
1892 let expr = compute_expr_semantic(ctx, &condition.expr(db));
1893
1894 let (patterns, body) = ctx.run_in_subscope(|new_ctx| {
1895 let patterns =
1896 compute_pattern_list_or_semantic(new_ctx, &expr, &condition.patterns(db));
1897
1898 let (id, _) =
1899 compute_loop_body_semantic(new_ctx, syntax.body(db), InnerContextKind::While);
1900 let expr = new_ctx.arenas.exprs[id].clone();
1901 (patterns, ExprAndId { expr, id })
1902 });
1903
1904 (Condition::Let(expr.id, patterns.iter().map(|pattern| pattern.id).collect()), body.id)
1905 }
1906 ast::Condition::Expr(expr) => {
1907 let (body, _inner_ctx) =
1908 compute_loop_body_semantic(ctx, syntax.body(db), InnerContextKind::While);
1909 (Condition::BoolExpr(compute_bool_condition_semantic(ctx, &expr.expr(db)).id), body)
1910 }
1911 };
1912
1913 Ok(Expr::While(ExprWhile {
1914 condition,
1915 body,
1916 ty: unit_ty(ctx.db),
1917 stable_ptr: syntax.stable_ptr(db).into(),
1918 }))
1919}
1920
1921fn compute_expr_for_semantic(
1923 ctx: &mut ComputationContext<'_>,
1924 syntax: &ast::ExprFor,
1925) -> Maybe<Expr> {
1926 let db = ctx.db;
1927 let expr_ptr = syntax.expr(db).stable_ptr(db);
1928 let expr = compute_expr_semantic(ctx, &syntax.expr(db));
1929 let into_iterator_trait = ctx.db.core_info().into_iterator_trt;
1930
1931 let (into_iterator_function_id, _, fixed_into_iter_var, into_iter_mutability) =
1932 compute_method_function_call_data(
1933 ctx,
1934 &[into_iterator_trait],
1935 "into_iter".into(),
1936 expr,
1937 expr_ptr.into(),
1938 None,
1939 |ty, _, inference_errors| {
1940 Some(NoImplementationOfTrait {
1941 ty,
1942 inference_errors,
1943 trait_name: "IntoIterator".into(),
1944 })
1945 },
1946 |_, _, _| {
1947 unreachable!(
1948 "There is one explicit trait, IntoIterator trait. No implementations of the \
1949 trait, caused by both lack of implementation or multiple implementations of \
1950 the trait, are handled in NoImplementationOfTrait function."
1951 )
1952 },
1953 )?;
1954 let expr_id = fixed_into_iter_var.id;
1955 let into_iter_call = expr_function_call(
1956 ctx,
1957 into_iterator_function_id,
1958 vec![NamedArg(fixed_into_iter_var, None, into_iter_mutability)],
1959 expr_ptr,
1960 expr_ptr,
1961 )?;
1962
1963 let into_iter_variable =
1964 LocalVarLongId(ctx.resolver.module_file_id, syntax.identifier(db).stable_ptr(db))
1965 .intern(ctx.db);
1966
1967 let into_iter_expr = Expr::Var(ExprVar {
1968 var: VarId::Local(into_iter_variable),
1969 ty: into_iter_call.ty(),
1970 stable_ptr: into_iter_call.stable_ptr(),
1971 });
1972 let into_iter_member_path = ExprVarMemberPath::Var(ExprVar {
1973 var: VarId::Local(into_iter_variable),
1974 ty: into_iter_call.ty(),
1975 stable_ptr: into_iter_call.stable_ptr(),
1976 });
1977 let into_iter_expr_id = ctx.arenas.exprs.alloc(into_iter_expr.clone());
1978
1979 let iterator_trait = ctx.db.core_info().iterator_trt;
1980
1981 let (next_function_id, _, _, _) = compute_method_function_call_data(
1982 ctx,
1983 &[iterator_trait],
1984 "next".into(),
1985 ExprAndId { expr: into_iter_expr, id: into_iter_expr_id },
1986 expr_ptr.into(),
1987 None,
1988 |ty, _, inference_errors| {
1989 Some(NoImplementationOfTrait { ty, inference_errors, trait_name: "Iterator".into() })
1990 },
1991 |_, _, _| {
1992 unreachable!(
1993 "There is one explicit trait, Iterator trait. No implementations of the trait, \
1994 caused by both lack of implementation or multiple implementations of the trait, \
1995 are handled in NoImplementationOfTrait function."
1996 )
1997 },
1998 )?;
1999
2000 let next_success_variant =
2001 match db.concrete_function_signature(next_function_id)?.return_type.lookup_intern(db) {
2002 TypeLongId::Concrete(semantic::ConcreteTypeId::Enum(enm)) => {
2003 assert_eq!(enm.enum_id(db).name(db), "Option");
2004 db.concrete_enum_variants(enm).unwrap().into_iter().next().unwrap()
2005 }
2006 _ => unreachable!(),
2007 };
2008 let (body_id, pattern) = ctx.run_in_subscope(|new_ctx| {
2009 let inner_pattern = compute_pattern_semantic(
2010 new_ctx,
2011 &syntax.pattern(db),
2012 next_success_variant.ty,
2013 &mut UnorderedHashMap::default(),
2014 );
2015 let variables = inner_pattern.variables(&new_ctx.arenas.patterns);
2016 for v in variables {
2017 let var_def = Binding::LocalVar(v.var.clone());
2018 new_ctx.environment.variables.insert(v.name.clone(), var_def.clone());
2019 new_ctx.semantic_defs.insert(var_def.id(), var_def);
2020 }
2021 let (body, _inner_ctx) =
2022 compute_loop_body_semantic(new_ctx, syntax.body(db), InnerContextKind::For);
2023 (body, new_ctx.arenas.patterns.alloc(inner_pattern.pattern))
2024 });
2025 Ok(Expr::For(ExprFor {
2026 into_iter: into_iterator_function_id,
2027 into_iter_member_path,
2028 next_function_id,
2029 expr_id,
2030 pattern,
2031 body: body_id,
2032 ty: unit_ty(ctx.db),
2033 stable_ptr: syntax.stable_ptr(db).into(),
2034 }))
2035}
2036
2037fn compute_loop_body_semantic(
2039 ctx: &mut ComputationContext<'_>,
2040 syntax: ast::ExprBlock,
2041 kind: InnerContextKind,
2042) -> (ExprId, InnerContext) {
2043 let db: &dyn SemanticGroup = ctx.db;
2044 ctx.run_in_subscope(|new_ctx| {
2045 let return_type = new_ctx.get_return_type().unwrap();
2046 let old_inner_ctx = new_ctx.inner_ctx.replace(InnerContext { return_type, kind });
2047 let (statements, tail) = statements_and_tail(ctx.db, syntax.statements(db));
2048 let mut statements_semantic = vec![];
2049 compute_statements_semantic_and_extend(new_ctx, statements, &mut statements_semantic);
2050 let tail_semantic_expr =
2051 tail.map(|tail| compute_tail_semantic(new_ctx, &tail, &mut statements_semantic));
2052 if let Some(tail) = &tail_semantic_expr {
2053 if !tail.ty().is_missing(db) && !tail.ty().is_unit(db) && tail.ty() != never_ty(db) {
2054 new_ctx.diagnostics.report(tail.deref(), TailExpressionNotAllowedInLoop);
2055 }
2056 }
2057 let inner_ctx = std::mem::replace(&mut new_ctx.inner_ctx, old_inner_ctx).unwrap();
2058 let body = new_ctx.arenas.exprs.alloc(Expr::Block(ExprBlock {
2059 statements: statements_semantic,
2060 tail: tail_semantic_expr.map(|expr| expr.id),
2061 ty: unit_ty(db),
2062 stable_ptr: syntax.stable_ptr(db).into(),
2063 }));
2064 (body, inner_ctx)
2065 })
2066}
2067
2068fn compute_expr_closure_semantic(
2070 ctx: &mut ComputationContext<'_>,
2071 syntax: &ast::ExprClosure,
2072 params_tuple_ty: Option<TypeId>,
2073) -> Maybe<Expr> {
2074 ctx.are_closures_in_context = true;
2075 let db = ctx.db;
2076 let (params, ret_ty, body) = ctx.run_in_subscope(|new_ctx| {
2077 let params = if let ClosureParamWrapper::NAry(params) = syntax.wrapper(db) {
2078 function_signature_params(
2079 new_ctx.diagnostics,
2080 new_ctx.db,
2081 &mut new_ctx.resolver,
2082 ¶ms.params(db).elements_vec(db),
2083 None,
2084 &mut new_ctx.environment,
2085 )
2086 .into_iter()
2087 .collect()
2088 } else {
2089 vec![]
2090 };
2091 let closure_type =
2092 TypeLongId::Tuple(params.iter().map(|param| param.ty).collect()).intern(new_ctx.db);
2093 if let Some(param_types) = params_tuple_ty {
2094 if let Err(err_set) = new_ctx.resolver.inference().conform_ty(closure_type, param_types)
2095 {
2096 new_ctx.resolver.inference().report_on_pending_error(
2097 err_set,
2098 new_ctx.diagnostics,
2099 syntax.stable_ptr(db).untyped(),
2100 );
2101 }
2102 }
2103
2104 params.iter().filter(|param| param.mutability == Mutability::Reference).for_each(|param| {
2105 new_ctx.diagnostics.report(param.stable_ptr(ctx.db), RefClosureParam);
2106 });
2107
2108 new_ctx
2109 .semantic_defs
2110 .extend(new_ctx.environment.variables.iter().map(|(_, var)| (var.id(), var.clone())));
2111
2112 let return_type = match syntax.ret_ty(db) {
2113 OptionReturnTypeClause::ReturnTypeClause(ty_syntax) => resolve_type_ex(
2114 new_ctx.db,
2115 new_ctx.diagnostics,
2116 &mut new_ctx.resolver,
2117 &ty_syntax.ty(db),
2118 ResolutionContext::Statement(&mut new_ctx.environment),
2119 ),
2120 OptionReturnTypeClause::Empty(missing) => {
2121 new_ctx.resolver.inference().new_type_var(Some(missing.stable_ptr(db).untyped()))
2122 }
2123 };
2124
2125 let old_inner_ctx = new_ctx
2126 .inner_ctx
2127 .replace(InnerContext { return_type, kind: InnerContextKind::Closure });
2128 let body = match syntax.expr(db) {
2129 ast::Expr::Block(syntax) => compute_closure_body_semantic(new_ctx, syntax),
2130 _ => compute_expr_semantic(new_ctx, &syntax.expr(db)).id,
2131 };
2132 std::mem::replace(&mut new_ctx.inner_ctx, old_inner_ctx).unwrap();
2133 let mut inference = new_ctx.resolver.inference();
2134 let _ = inference.conform_ty_for_diag(
2135 new_ctx.arenas.exprs[body].ty(),
2136 return_type,
2137 new_ctx.diagnostics,
2138 || match syntax.ret_ty(ctx.db).stable_ptr(db).lookup(ctx.db) {
2139 OptionReturnTypeClause::Empty(_) => syntax.expr(db).stable_ptr(db).untyped(),
2140 OptionReturnTypeClause::ReturnTypeClause(return_type_clause) => {
2141 return_type_clause.ty(ctx.db).stable_ptr(db).untyped()
2142 }
2143 },
2144 |actual_ty, expected_ty| WrongReturnType { expected_ty, actual_ty },
2145 );
2146 (params, return_type, body)
2147 });
2148 let parent_function = match ctx.function_id {
2149 ContextFunction::Global => {
2150 Maybe::Err(ctx.diagnostics.report(syntax.stable_ptr(db), ClosureInGlobalScope))
2151 }
2152 ContextFunction::Function(function_id) => function_id,
2153 };
2154 if matches!(ctx.function_id, ContextFunction::Global) {
2155 ctx.diagnostics.report(syntax.stable_ptr(db), ClosureInGlobalScope);
2156 }
2157
2158 let mut usages = Usages { usages: Default::default() };
2159 let usage = usages.handle_closure(&ctx.arenas, ¶ms, body);
2160 let mut reported = UnorderedHashSet::<_>::default();
2161 for (captured_var, expr) in
2163 chain!(usage.usage.iter(), usage.snap_usage.iter(), usage.changes.iter())
2164 {
2165 let Some(var) = ctx.semantic_defs.get(&captured_var.base_var()) else {
2166 continue;
2168 };
2169
2170 if var.is_mut() && reported.insert(expr.stable_ptr()) {
2171 ctx.diagnostics.report(expr.stable_ptr(), MutableCapturedVariable);
2172 }
2173 }
2174
2175 let captured_types = chain!(
2176 chain!(usage.usage.values(), usage.changes.values()).map(|item| item.ty()),
2177 usage.snap_usage.values().map(|item| wrap_in_snapshots(ctx.db, item.ty(), 1)),
2178 )
2179 .collect_vec();
2180
2181 let ty = TypeLongId::Closure(ClosureTypeLongId {
2182 param_tys: params.iter().map(|param| param.ty).collect(),
2183 ret_ty,
2184 captured_types,
2185 parent_function,
2186 wrapper_location: StableLocation::new(syntax.wrapper(db).stable_ptr(db).into()),
2187 })
2188 .intern(ctx.db);
2189
2190 Ok(Expr::ExprClosure(ExprClosure {
2191 body,
2192 params,
2193 stable_ptr: syntax.stable_ptr(db).into(),
2194 ty,
2195 }))
2196}
2197
2198fn compute_closure_body_semantic(
2200 ctx: &mut ComputationContext<'_>,
2201 syntax: ast::ExprBlock,
2202) -> ExprId {
2203 let db = ctx.db;
2204 let (statements, tail) = statements_and_tail(db, syntax.statements(db));
2205 let mut statements_semantic = vec![];
2206 compute_statements_semantic_and_extend(ctx, statements, &mut statements_semantic);
2207 let tail_semantic_expr =
2208 tail.map(|tail| compute_tail_semantic(ctx, &tail, &mut statements_semantic));
2209 let ty = block_ty(ctx, &statements_semantic, &tail_semantic_expr);
2210 ctx.arenas.exprs.alloc(Expr::Block(ExprBlock {
2211 statements: statements_semantic,
2212 tail: tail_semantic_expr.map(|expr| expr.id),
2213 ty,
2214 stable_ptr: syntax.stable_ptr(db).into(),
2215 }))
2216}
2217
2218fn compute_expr_error_propagate_semantic(
2220 ctx: &mut ComputationContext<'_>,
2221 syntax: &ast::ExprErrorPropagate,
2222) -> Maybe<Expr> {
2223 let db = ctx.db;
2224
2225 let return_type = ctx.get_return_type().ok_or_else(|| {
2226 ctx.diagnostics.report(
2227 syntax.stable_ptr(db),
2228 UnsupportedOutsideOfFunction(UnsupportedOutsideOfFunctionFeatureName::ErrorPropagate),
2229 )
2230 })?;
2231
2232 let func_err_prop_ty = unwrap_error_propagation_type(ctx.db, return_type).ok_or_else(|| {
2233 ctx.diagnostics.report(syntax.stable_ptr(db), ReturnTypeNotErrorPropagateType)
2234 })?;
2235
2236 let inner_expr = match &func_err_prop_ty {
2238 crate::corelib::ErrorPropagationType::Option { .. } => {
2239 compute_expr_semantic(ctx, &syntax.expr(db))
2240 }
2241 crate::corelib::ErrorPropagationType::Result { .. } => {
2242 compute_expr_semantic(ctx, &syntax.expr(db))
2243 }
2244 };
2245 let func_err_variant = func_err_prop_ty.err_variant();
2246
2247 ctx.resolver.inference().solve().ok();
2249 let inner_expr_ty = ctx.reduce_ty(inner_expr.ty());
2250 inner_expr_ty.check_not_missing(ctx.db)?;
2251 let inner_expr_err_prop_ty =
2252 unwrap_error_propagation_type(ctx.db, inner_expr_ty).ok_or_else(|| {
2253 ctx.diagnostics
2254 .report(syntax.stable_ptr(db), ErrorPropagateOnNonErrorType(inner_expr_ty))
2255 })?;
2256 let inner_expr_err_variant = inner_expr_err_prop_ty.err_variant();
2257
2258 let conformed_err_variant_ty =
2259 ctx.resolver.inference().conform_ty(func_err_variant.ty, inner_expr_err_variant.ty);
2260 let err_variant_ty = match conformed_err_variant_ty {
2263 Ok(ty) => ty,
2264 Err(err_set) => {
2265 ctx.resolver.inference().consume_error_without_reporting(err_set);
2266 inner_expr_err_variant.ty
2267 }
2268 };
2269 if func_err_variant.ty != err_variant_ty
2271 || func_err_variant.concrete_enum_id.enum_id(ctx.db)
2272 != inner_expr_err_variant.concrete_enum_id.enum_id(ctx.db)
2273 {
2274 ctx.diagnostics.report(
2275 syntax.stable_ptr(db),
2276 IncompatibleErrorPropagateType {
2277 return_ty: return_type,
2278 err_ty: inner_expr_err_variant.ty,
2279 },
2280 );
2281 }
2282 Ok(Expr::PropagateError(ExprPropagateError {
2283 inner: inner_expr.id,
2284 ok_variant: *inner_expr_err_prop_ty.ok_variant(),
2285 err_variant: *inner_expr_err_variant,
2286 func_err_variant: *func_err_variant,
2287 stable_ptr: syntax.stable_ptr(db).into(),
2288 }))
2289}
2290
2291fn compute_expr_indexed_semantic(
2293 ctx: &mut ComputationContext<'_>,
2294 syntax: &ast::ExprIndexed,
2295) -> Maybe<Expr> {
2296 let db = ctx.db;
2297 let expr = compute_expr_semantic(ctx, &syntax.expr(db));
2298 let index_expr_syntax = &syntax.index_expr(db);
2299 let index_expr = compute_expr_semantic(ctx, index_expr_syntax);
2300 if !ctx.reduce_ty(expr.ty()).is_var_free(ctx.db) {
2301 ctx.resolver.inference().solve().ok();
2304 }
2305 let info = ctx.db.core_info();
2306 let candidate_traits = [info.index_trt, info.index_view_trt];
2307 let (function_id, _, fixed_expr, mutability) = compute_method_function_call_data(
2308 ctx,
2309 &candidate_traits[..],
2310 "index".into(),
2311 expr,
2312 syntax.stable_ptr(db).untyped(),
2313 None,
2314 |ty, _, inference_errors| Some(NoImplementationOfIndexOperator { ty, inference_errors }),
2315 |ty, _, _| Some(MultipleImplementationOfIndexOperator(ty)),
2316 )?;
2317
2318 expr_function_call(
2319 ctx,
2320 function_id,
2321 vec![
2322 NamedArg(fixed_expr, None, mutability),
2323 NamedArg(index_expr, None, Mutability::Immutable),
2324 ],
2325 syntax.stable_ptr(db),
2326 index_expr_syntax.stable_ptr(db),
2327 )
2328}
2329
2330#[expect(clippy::too_many_arguments)]
2335fn compute_method_function_call_data(
2336 ctx: &mut ComputationContext<'_>,
2337 candidate_traits: &[TraitId],
2338 func_name: SmolStr,
2339 self_expr: ExprAndId,
2340 method_syntax: SyntaxStablePtrId,
2341 generic_args_syntax: Option<Vec<ast::GenericArg>>,
2342 no_implementation_diagnostic: impl Fn(
2343 TypeId,
2344 SmolStr,
2345 TraitInferenceErrors,
2346 ) -> Option<SemanticDiagnosticKind>,
2347 multiple_trait_diagnostic: fn(
2348 TypeId,
2349 TraitFunctionId,
2350 TraitFunctionId,
2351 ) -> Option<SemanticDiagnosticKind>,
2352) -> Maybe<(FunctionId, TraitId, ExprAndId, Mutability)> {
2353 let expr_ptr = self_expr.stable_ptr();
2354 let self_ty = ctx.reduce_ty(self_expr.ty());
2355 let mut inference_errors = vec![];
2359 let (candidates, mut fixed_expr, fixed_ty, deref_used) = get_method_function_candidates(
2360 ctx,
2361 candidate_traits,
2362 &func_name,
2363 self_expr,
2364 method_syntax,
2365 expr_ptr,
2366 self_ty,
2367 &mut inference_errors,
2368 )?;
2369
2370 let trait_function_id = match candidates[..] {
2371 [] => {
2372 return Err(no_implementation_diagnostic(
2373 self_ty,
2374 func_name,
2375 TraitInferenceErrors { traits_and_errors: inference_errors },
2376 )
2377 .map(|diag| ctx.diagnostics.report(method_syntax, diag))
2378 .unwrap_or_else(skip_diagnostic));
2379 }
2380 [trait_function_id] => trait_function_id,
2381 [trait_function_id0, trait_function_id1, ..] => {
2382 return Err(multiple_trait_diagnostic(
2383 fixed_ty,
2384 trait_function_id0,
2385 trait_function_id1,
2386 )
2387 .map(|diag| ctx.diagnostics.report(method_syntax, diag))
2388 .unwrap_or_else(skip_diagnostic));
2389 }
2390 };
2391 let (function_id, n_snapshots) =
2392 infer_impl_by_self(ctx, trait_function_id, fixed_ty, method_syntax, generic_args_syntax)?;
2393
2394 let signature = ctx.db.trait_function_signature(trait_function_id).unwrap();
2395 let first_param = signature.params.into_iter().next().unwrap();
2396
2397 if deref_used && first_param.mutability == Mutability::Reference {
2398 return Err(no_implementation_diagnostic(
2399 self_ty,
2400 func_name,
2401 TraitInferenceErrors { traits_and_errors: inference_errors },
2402 )
2403 .map(|diag| ctx.diagnostics.report(method_syntax, diag))
2404 .unwrap_or_else(skip_diagnostic));
2405 }
2406
2407 for _ in 0..n_snapshots {
2408 let ty = TypeLongId::Snapshot(fixed_expr.ty()).intern(ctx.db);
2409 let expr = Expr::Snapshot(ExprSnapshot { inner: fixed_expr.id, ty, stable_ptr: expr_ptr });
2410 fixed_expr = ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) };
2411 }
2412
2413 Ok((function_id, trait_function_id.trait_id(ctx.db), fixed_expr, first_param.mutability))
2414}
2415
2416#[expect(clippy::too_many_arguments)]
2420fn get_method_function_candidates(
2421 ctx: &mut ComputationContext<'_>,
2422 candidate_traits: &[TraitId],
2423 func_name: &SmolStr,
2424 self_expr: ExprAndId,
2425 method_syntax: SyntaxStablePtrId,
2426 expr_ptr: ExprPtr,
2427 self_ty: TypeId,
2428 inference_errors: &mut Vec<(TraitFunctionId, InferenceError)>,
2429) -> Result<(Vec<TraitFunctionId>, ExprAndId, TypeId, bool), cairo_lang_diagnostics::DiagnosticAdded>
2430{
2431 let mut candidates = filter_candidate_traits(
2432 ctx,
2433 inference_errors,
2434 self_ty,
2435 candidate_traits,
2436 func_name.clone(),
2437 method_syntax,
2438 );
2439 if !candidates.is_empty() {
2440 return Ok((candidates, self_expr, self_ty, false));
2441 }
2442
2443 let mut fixed_expr = self_expr;
2444 let mut fixed_ty = self_ty;
2445
2446 let base_var = match &fixed_expr.expr {
2447 Expr::Var(expr_var) => Some(expr_var.var),
2448 Expr::MemberAccess(ExprMemberAccess { member_path: Some(member_path), .. }) => {
2449 Some(member_path.base_var())
2450 }
2451 _ => None,
2452 };
2453 let is_mut_var = base_var
2454 .filter(|var_id| matches!(ctx.semantic_defs.get(var_id), Some(var) if var.is_mut()))
2455 .is_some();
2456
2457 let deref_chain = ctx.db.deref_chain(self_ty, is_mut_var)?;
2458
2459 for deref_info in deref_chain.derefs.iter() {
2460 let derefed_expr = expr_function_call(
2461 ctx,
2462 deref_info.function_id,
2463 vec![NamedArg(fixed_expr, None, deref_info.self_mutability)],
2464 method_syntax,
2465 expr_ptr,
2466 )?;
2467
2468 fixed_expr =
2469 ExprAndId { expr: derefed_expr.clone(), id: ctx.arenas.exprs.alloc(derefed_expr) };
2470
2471 candidates = filter_candidate_traits(
2472 ctx,
2473 inference_errors,
2474 deref_info.target_ty,
2475 candidate_traits,
2476 func_name.clone(),
2477 method_syntax,
2478 );
2479 if !candidates.is_empty() {
2480 fixed_ty = deref_info.target_ty;
2481 break;
2482 }
2483 }
2484
2485 Ok((candidates, fixed_expr, fixed_ty, true))
2486}
2487
2488pub fn compute_pattern_semantic(
2492 ctx: &mut ComputationContext<'_>,
2493 syntax: &ast::Pattern,
2494 ty: TypeId,
2495 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2496) -> PatternAndId {
2497 let pat = maybe_compute_pattern_semantic(ctx, syntax, ty, or_pattern_variables_map);
2498 let pat = pat.unwrap_or_else(|diag_added| {
2499 Pattern::Missing(PatternMissing {
2500 ty: TypeId::missing(ctx.db, diag_added),
2501 stable_ptr: syntax.stable_ptr(ctx.db),
2502 diag_added,
2503 })
2504 });
2505 let id = ctx.arenas.patterns.alloc(pat.clone());
2506 PatternAndId { pattern: pat, id }
2507}
2508
2509fn maybe_compute_pattern_semantic(
2511 ctx: &mut ComputationContext<'_>,
2512 pattern_syntax: &ast::Pattern,
2513 ty: TypeId,
2514 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2515) -> Maybe<Pattern> {
2516 let db = ctx.db;
2518 let ty = ctx.reduce_ty(ty);
2519 let stable_ptr = pattern_syntax.stable_ptr(db).untyped();
2520 let pattern = match pattern_syntax {
2521 ast::Pattern::Underscore(otherwise_pattern) => Pattern::Otherwise(PatternOtherwise {
2522 ty,
2523 stable_ptr: otherwise_pattern.stable_ptr(db),
2524 }),
2525 ast::Pattern::Literal(literal_pattern) => {
2526 let literal = literal_to_semantic(ctx, literal_pattern)?;
2527 Pattern::Literal(PatternLiteral {
2528 literal,
2529 stable_ptr: literal_pattern.stable_ptr(db).into(),
2530 })
2531 }
2532 ast::Pattern::ShortString(short_string_pattern) => {
2533 let literal = short_string_to_semantic(ctx, short_string_pattern)?;
2534 Pattern::Literal(PatternLiteral {
2535 literal,
2536 stable_ptr: short_string_pattern.stable_ptr(db).into(),
2537 })
2538 }
2539 ast::Pattern::String(string_pattern) => {
2540 let string_literal = string_literal_to_semantic(ctx, string_pattern)?;
2541 Pattern::StringLiteral(PatternStringLiteral {
2542 string_literal,
2543 stable_ptr: string_pattern.stable_ptr(db).into(),
2544 })
2545 }
2546 ast::Pattern::Enum(enum_pattern) => {
2547 let path = enum_pattern.path(db);
2548 let item = ctx.resolver.resolve_concrete_path_ex(
2549 ctx.diagnostics,
2550 &path,
2551 NotFoundItemType::Identifier,
2552 ResolutionContext::Statement(&mut ctx.environment),
2553 )?;
2554 let concrete_variant = try_extract_matches!(item, ResolvedConcreteItem::Variant)
2555 .ok_or_else(|| ctx.diagnostics.report(path.stable_ptr(db), NotAVariant))?;
2556
2557 let n_snapshots =
2558 validate_pattern_type_and_args(ctx, pattern_syntax, ty, concrete_variant)?;
2559
2560 let inner_ty = wrap_in_snapshots(ctx.db, concrete_variant.ty, n_snapshots);
2562
2563 let inner_pattern = match enum_pattern.pattern(db) {
2564 ast::OptionPatternEnumInnerPattern::Empty(_) => None,
2565 ast::OptionPatternEnumInnerPattern::PatternEnumInnerPattern(p) => {
2566 let pattern = compute_pattern_semantic(
2567 ctx,
2568 &p.pattern(db),
2569 inner_ty,
2570 or_pattern_variables_map,
2571 );
2572 Some(pattern.id)
2573 }
2574 };
2575
2576 Pattern::EnumVariant(PatternEnumVariant {
2577 variant: concrete_variant,
2578 inner_pattern,
2579 ty,
2580 stable_ptr: enum_pattern.stable_ptr(db).into(),
2581 })
2582 }
2583 ast::Pattern::Path(path) => {
2584 let item_result = ctx.resolver.resolve_generic_path_with_args(
2585 &mut Default::default(),
2586 path,
2587 NotFoundItemType::Identifier,
2588 ResolutionContext::Statement(&mut ctx.environment),
2589 );
2590 if let Ok(ResolvedGenericItem::Variant(_)) = item_result {
2591 let item = ctx.resolver.resolve_concrete_path_ex(
2596 &mut Default::default(),
2597 path,
2598 NotFoundItemType::Identifier,
2599 ResolutionContext::Statement(&mut ctx.environment),
2600 );
2601 if let Ok(ResolvedConcreteItem::Variant(concrete_variant)) = item {
2602 let _n_snapshots =
2603 validate_pattern_type_and_args(ctx, pattern_syntax, ty, concrete_variant)?;
2604 return Ok(Pattern::EnumVariant(PatternEnumVariant {
2605 variant: concrete_variant,
2606 inner_pattern: None,
2607 ty,
2608 stable_ptr: path.stable_ptr(db).into(),
2609 }));
2610 }
2611 }
2612
2613 let mut segments = path.segments(db).elements(db);
2617 if segments.len() > 1 {
2618 return Err(ctx.diagnostics.report(path.stable_ptr(ctx.db), Unsupported));
2619 }
2620 let identifier = segments.next().unwrap().identifier_ast(db);
2622 create_variable_pattern(
2623 ctx,
2624 identifier,
2625 &[],
2626 ty,
2627 path.stable_ptr(db).into(),
2628 or_pattern_variables_map,
2629 )
2630 }
2631 ast::Pattern::Identifier(identifier) => create_variable_pattern(
2632 ctx,
2633 identifier.name(db),
2634 &identifier.modifiers(db).elements_vec(db),
2635 ty,
2636 identifier.stable_ptr(db).into(),
2637 or_pattern_variables_map,
2638 ),
2639 ast::Pattern::Struct(pattern_struct) => {
2640 let pattern_ty = try_extract_matches!(
2641 ctx.resolver.resolve_concrete_path_ex(
2642 ctx.diagnostics,
2643 &pattern_struct.path(db),
2644 NotFoundItemType::Type,
2645 ResolutionContext::Statement(&mut ctx.environment)
2646 )?,
2647 ResolvedConcreteItem::Type
2648 )
2649 .ok_or_else(|| {
2650 ctx.diagnostics.report(pattern_struct.path(db).stable_ptr(db), NotAType)
2651 })?;
2652 let inference = &mut ctx.resolver.inference();
2653 inference.conform_ty(pattern_ty, peel_snapshots(ctx.db, ty).1.intern(ctx.db)).map_err(
2654 |err_set| inference.report_on_pending_error(err_set, ctx.diagnostics, stable_ptr),
2655 )?;
2656 let ty = ctx.reduce_ty(ty);
2657 let (n_snapshots, long_ty) = peel_snapshots(ctx.db, ty);
2659
2660 let concrete_struct_id = try_extract_matches!(long_ty, TypeLongId::Concrete)
2662 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Struct))
2663 .ok_or(())
2664 .or_else(|_| {
2665 ty.check_not_missing(ctx.db)?;
2668 Err(ctx
2669 .diagnostics
2670 .report(pattern_struct.stable_ptr(db), UnexpectedStructPattern(ty)))
2671 })?;
2672 let pattern_param_asts = pattern_struct.params(db).elements(db);
2673 let struct_id = concrete_struct_id.struct_id(ctx.db);
2674 let mut members = ctx.db.concrete_struct_members(concrete_struct_id)?.as_ref().clone();
2675 let mut used_members = UnorderedHashSet::<_>::default();
2676 let mut get_member = |ctx: &mut ComputationContext<'_>,
2677 member_name: SmolStr,
2678 stable_ptr: SyntaxStablePtrId| {
2679 let member = members.swap_remove(&member_name).on_none(|| {
2680 ctx.diagnostics.report(
2681 stable_ptr,
2682 if used_members.contains(&member_name) {
2683 StructMemberRedefinition { struct_id, member_name: member_name.clone() }
2684 } else {
2685 NoSuchStructMember { struct_id, member_name: member_name.clone() }
2686 },
2687 );
2688 })?;
2689 check_struct_member_is_visible(ctx, &member, stable_ptr, &member_name);
2690 used_members.insert(member_name);
2691 Some(member)
2692 };
2693 let mut field_patterns = vec![];
2694 let mut has_tail = false;
2695 for pattern_param_ast in pattern_param_asts {
2696 match pattern_param_ast {
2697 PatternStructParam::Single(single) => {
2698 let name = single.name(db);
2699 let Some(member) =
2700 get_member(ctx, name.text(db), name.stable_ptr(db).untyped())
2701 else {
2702 continue;
2703 };
2704 let ty = wrap_in_snapshots(ctx.db, member.ty, n_snapshots);
2705 let pattern = create_variable_pattern(
2706 ctx,
2707 name,
2708 &single.modifiers(db).elements_vec(db),
2709 ty,
2710 single.stable_ptr(db).into(),
2711 or_pattern_variables_map,
2712 );
2713 field_patterns.push((member, ctx.arenas.patterns.alloc(pattern)));
2714 }
2715 PatternStructParam::WithExpr(with_expr) => {
2716 let name = with_expr.name(db);
2717 let Some(member) =
2718 get_member(ctx, name.text(db), name.stable_ptr(db).untyped())
2719 else {
2720 continue;
2721 };
2722 let ty = wrap_in_snapshots(ctx.db, member.ty, n_snapshots);
2723 let pattern = compute_pattern_semantic(
2724 ctx,
2725 &with_expr.pattern(db),
2726 ty,
2727 or_pattern_variables_map,
2728 );
2729 field_patterns.push((member, pattern.id));
2730 }
2731 PatternStructParam::Tail(_) => {
2732 has_tail = true;
2733 }
2734 }
2735 }
2736 if !has_tail {
2737 for (member_name, _) in members.iter() {
2738 ctx.diagnostics
2739 .report(pattern_struct.stable_ptr(db), MissingMember(member_name.clone()));
2740 }
2741 }
2742 Pattern::Struct(PatternStruct {
2743 concrete_struct_id,
2744 field_patterns,
2745 ty,
2746 n_snapshots,
2747 stable_ptr: pattern_struct.stable_ptr(db),
2748 })
2749 }
2750 ast::Pattern::Tuple(_) => compute_tuple_like_pattern_semantic(
2751 ctx,
2752 pattern_syntax,
2753 ty,
2754 or_pattern_variables_map,
2755 |ty: TypeId| UnexpectedTuplePattern(ty),
2756 |expected, actual| WrongNumberOfTupleElements { expected, actual },
2757 ),
2758 ast::Pattern::FixedSizeArray(_) => compute_tuple_like_pattern_semantic(
2759 ctx,
2760 pattern_syntax,
2761 ty,
2762 or_pattern_variables_map,
2763 |ty: TypeId| UnexpectedFixedSizeArrayPattern(ty),
2764 |expected, actual| WrongNumberOfFixedSizeArrayElements { expected, actual },
2765 ),
2766 ast::Pattern::False(pattern_false) => {
2767 let enum_expr = extract_matches!(
2768 false_literal_expr(ctx, pattern_false.stable_ptr(db).into()),
2769 Expr::EnumVariantCtor
2770 );
2771
2772 extract_concrete_enum_from_pattern_and_validate(
2773 ctx,
2774 pattern_syntax,
2775 ty,
2776 enum_expr.variant.concrete_enum_id,
2777 )?;
2778
2779 Pattern::EnumVariant(PatternEnumVariant {
2780 variant: enum_expr.variant,
2781 stable_ptr: pattern_false.stable_ptr(db).into(),
2782 ty,
2783 inner_pattern: None,
2784 })
2785 }
2786 ast::Pattern::True(pattern_true) => {
2787 let enum_expr = extract_matches!(
2788 true_literal_expr(ctx, pattern_true.stable_ptr(db).into()),
2789 Expr::EnumVariantCtor
2790 );
2791 extract_concrete_enum_from_pattern_and_validate(
2792 ctx,
2793 pattern_syntax,
2794 ty,
2795 enum_expr.variant.concrete_enum_id,
2796 )?;
2797
2798 Pattern::EnumVariant(PatternEnumVariant {
2799 variant: enum_expr.variant,
2800 stable_ptr: pattern_true.stable_ptr(db).into(),
2801 ty,
2802 inner_pattern: None,
2803 })
2804 }
2805 };
2806 let inference = &mut ctx.resolver.inference();
2807 inference.conform_ty(pattern.ty(), ty).map_err(|err_set| {
2808 inference.report_on_pending_error(err_set, ctx.diagnostics, stable_ptr)
2809 })?;
2810 Ok(pattern)
2811}
2812
2813fn compute_tuple_like_pattern_semantic(
2816 ctx: &mut ComputationContext<'_>,
2817 pattern_syntax: &ast::Pattern,
2818 ty: TypeId,
2819 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2820 unexpected_pattern: fn(TypeId) -> SemanticDiagnosticKind,
2821 wrong_number_of_elements: fn(usize, usize) -> SemanticDiagnosticKind,
2822) -> Pattern {
2823 let db = ctx.db;
2824 let (n_snapshots, mut long_ty) =
2825 match finalized_snapshot_peeled_ty(ctx, ty, pattern_syntax.stable_ptr(db)) {
2826 Ok(value) => value,
2827 Err(diag_added) => (0, TypeLongId::Missing(diag_added)),
2828 };
2829 match (pattern_syntax, &long_ty) {
2831 (_, TypeLongId::Var(_) | TypeLongId::Missing(_))
2832 | (ast::Pattern::Tuple(_), TypeLongId::Tuple(_))
2833 | (ast::Pattern::FixedSizeArray(_), TypeLongId::FixedSizeArray { .. }) => {}
2834 _ => {
2835 long_ty = TypeLongId::Missing(
2836 ctx.diagnostics.report(pattern_syntax.stable_ptr(db), unexpected_pattern(ty)),
2837 );
2838 }
2839 };
2840 let patterns_syntax = match pattern_syntax {
2841 ast::Pattern::Tuple(pattern_tuple) => pattern_tuple.patterns(db).elements_vec(db),
2842 ast::Pattern::FixedSizeArray(pattern_fixed_size_array) => {
2843 pattern_fixed_size_array.patterns(db).elements_vec(db)
2844 }
2845 _ => unreachable!(),
2846 };
2847 let mut inner_tys = match long_ty {
2848 TypeLongId::Tuple(inner_tys) => inner_tys,
2849 TypeLongId::FixedSizeArray { type_id: inner_ty, size } => {
2850 let size = if let ConstValue::Int(value, _) = size.lookup_intern(db) {
2851 value.to_usize().expect("Fixed sized array size must always be usize.")
2852 } else {
2853 let inference = &mut ctx.resolver.inference();
2854 let expected_size =
2855 ConstValue::Int(patterns_syntax.len().into(), get_usize_ty(db)).intern(db);
2856 if let Err(err) = inference.conform_const(size, expected_size) {
2857 let _ = inference.report_on_pending_error(
2858 err,
2859 ctx.diagnostics,
2860 pattern_syntax.stable_ptr(db).untyped(),
2861 );
2862 }
2863 patterns_syntax.len()
2864 };
2865
2866 [inner_ty].repeat(size)
2867 }
2868 TypeLongId::Var(_) => {
2869 let inference = &mut ctx.resolver.inference();
2870 let (inner_tys, tuple_like_ty) = if matches!(pattern_syntax, ast::Pattern::Tuple(_)) {
2871 let inner_tys: Vec<_> = patterns_syntax
2872 .iter()
2873 .map(|e| inference.new_type_var(Some(e.stable_ptr(db).untyped())))
2874 .collect();
2875 (inner_tys.clone(), TypeLongId::Tuple(inner_tys))
2876 } else {
2877 let var = inference.new_type_var(Some(pattern_syntax.stable_ptr(db).untyped()));
2878 (
2879 vec![var; patterns_syntax.len()],
2880 TypeLongId::FixedSizeArray {
2881 type_id: var,
2882 size: ConstValue::Int(patterns_syntax.len().into(), get_usize_ty(db))
2883 .intern(db),
2884 },
2885 )
2886 };
2887 match inference.conform_ty(long_ty.intern(db), tuple_like_ty.intern(db)) {
2888 Ok(_) => {}
2889 Err(_) => unreachable!("As the type is a var, conforming should always succeed."),
2890 }
2891 inner_tys
2892 }
2893 TypeLongId::Missing(diag_added) => {
2894 let missing = TypeId::missing(db, diag_added);
2895 vec![missing; patterns_syntax.len()]
2896 }
2897 _ => unreachable!(),
2898 };
2899 let size = inner_tys.len();
2900 if size != patterns_syntax.len() {
2901 let diag_added = ctx.diagnostics.report(
2902 pattern_syntax.stable_ptr(db),
2903 wrong_number_of_elements(size, patterns_syntax.len()),
2904 );
2905 let missing = TypeId::missing(db, diag_added);
2906
2907 inner_tys = vec![missing; patterns_syntax.len()];
2908 }
2909 let subpatterns = zip_eq(patterns_syntax, inner_tys)
2910 .map(|(pattern_ast, ty)| {
2911 let ty = wrap_in_snapshots(db, ty, n_snapshots);
2912 compute_pattern_semantic(ctx, &pattern_ast, ty, or_pattern_variables_map).id
2913 })
2914 .collect();
2915 match pattern_syntax {
2916 ast::Pattern::Tuple(syntax) => Pattern::Tuple(PatternTuple {
2917 field_patterns: subpatterns,
2918 ty,
2919 stable_ptr: syntax.stable_ptr(db),
2920 }),
2921 ast::Pattern::FixedSizeArray(syntax) => Pattern::FixedSizeArray(PatternFixedSizeArray {
2922 elements_patterns: subpatterns,
2923 ty,
2924 stable_ptr: syntax.stable_ptr(db),
2925 }),
2926 _ => unreachable!(),
2927 }
2928}
2929
2930fn extract_concrete_enum_from_pattern_and_validate(
2932 ctx: &mut ComputationContext<'_>,
2933 pattern: &ast::Pattern,
2934 ty: TypeId,
2935 concrete_enum_id: ConcreteEnumId,
2936) -> Maybe<(ConcreteEnumId, usize)> {
2937 let (n_snapshots, long_ty) = finalized_snapshot_peeled_ty(ctx, ty, pattern.stable_ptr(ctx.db))?;
2939
2940 let concrete_enum = try_extract_matches!(long_ty, TypeLongId::Concrete)
2942 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Enum))
2943 .ok_or(())
2944 .or_else(|_| {
2945 ty.check_not_missing(ctx.db)?;
2948 Err(ctx.diagnostics.report(pattern.stable_ptr(ctx.db), UnexpectedEnumPattern(ty)))
2949 })?;
2950 let pattern_enum = concrete_enum_id.enum_id(ctx.db);
2952 if pattern_enum != concrete_enum.enum_id(ctx.db) {
2953 return Err(ctx.diagnostics.report(
2954 pattern.stable_ptr(ctx.db),
2955 WrongEnum { expected_enum: concrete_enum.enum_id(ctx.db), actual_enum: pattern_enum },
2956 ));
2957 }
2958 Ok((concrete_enum, n_snapshots))
2959}
2960
2961fn validate_pattern_type_and_args(
2965 ctx: &mut ComputationContext<'_>,
2966 pattern: &ast::Pattern,
2967 ty: TypeId,
2968 concrete_variant: ConcreteVariant,
2969) -> Maybe<usize> {
2970 let db = ctx.db;
2971
2972 let (concrete_enum, n_snapshots) = extract_concrete_enum_from_pattern_and_validate(
2973 ctx,
2974 pattern,
2975 ty,
2976 concrete_variant.concrete_enum_id,
2977 )?;
2978
2979 if let Err(err_set) = ctx.resolver.inference().conform_generic_args(
2980 &concrete_variant.concrete_enum_id.lookup_intern(db).generic_args,
2981 &concrete_enum.lookup_intern(db).generic_args,
2982 ) {
2983 let diag_added = ctx.diagnostics.report(
2984 pattern.stable_ptr(db),
2985 InternalInferenceError(InferenceError::TypeKindMismatch {
2986 ty0: ty,
2987 ty1: TypeLongId::Concrete(ConcreteTypeId::Enum(concrete_variant.concrete_enum_id))
2988 .intern(db),
2989 }),
2990 );
2991 ctx.resolver.inference().consume_reported_error(err_set, diag_added);
2992 };
2993
2994 let generic_variant = db
2995 .variant_semantic(concrete_variant.concrete_enum_id.enum_id(db), concrete_variant.id)
2996 .expect("concrete variant has to exist");
2997
2998 let needs_args = generic_variant.ty != unit_ty(db);
2999 let has_args = matches!(
3000 pattern,
3001 ast::Pattern::Enum(inner)
3002 if matches!(
3003 inner.pattern(db),
3004 ast::OptionPatternEnumInnerPattern::PatternEnumInnerPattern(_)
3005 )
3006 );
3007
3008 if needs_args && !has_args {
3009 let path = match pattern {
3010 ast::Pattern::Enum(pattern) => pattern.path(db),
3011 ast::Pattern::Path(p) => p.clone(),
3012 _ => unreachable!("Expected enum pattern in variant extraction."),
3013 };
3014 ctx.diagnostics.report(pattern.stable_ptr(db), PatternMissingArgs(path));
3015 }
3016
3017 Ok(n_snapshots)
3018}
3019
3020fn create_variable_pattern(
3022 ctx: &mut ComputationContext<'_>,
3023 identifier: ast::TerminalIdentifier,
3024 modifier_list: &[ast::Modifier],
3025 ty: TypeId,
3026 stable_ptr: ast::PatternPtr,
3027 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
3028) -> Pattern {
3029 let db = ctx.db;
3030
3031 let var_id = match or_pattern_variables_map.get(&identifier.text(db)) {
3032 Some(var) => var.id,
3033 None => {
3034 LocalVarLongId(ctx.resolver.module_file_id, identifier.stable_ptr(db)).intern(ctx.db)
3035 }
3036 };
3037 let is_mut = match compute_mutability(ctx.diagnostics, db, modifier_list) {
3038 Mutability::Immutable => false,
3039 Mutability::Mutable => true,
3040 Mutability::Reference => {
3041 ctx.diagnostics.report(identifier.stable_ptr(db), ReferenceLocalVariable);
3042 false
3043 }
3044 };
3045 Pattern::Variable(PatternVariable {
3046 name: identifier.text(db),
3047 var: LocalVariable { id: var_id, ty, is_mut },
3048 stable_ptr,
3049 })
3050}
3051
3052fn struct_ctor_expr(
3054 ctx: &mut ComputationContext<'_>,
3055 ctor_syntax: &ast::ExprStructCtorCall,
3056) -> Maybe<Expr> {
3057 let db = ctx.db;
3058 let path = ctor_syntax.path(db);
3059
3060 let ty = resolve_type_ex(
3062 db,
3063 ctx.diagnostics,
3064 &mut ctx.resolver,
3065 &ast::Expr::Path(path.clone()),
3066 ResolutionContext::Statement(&mut ctx.environment),
3067 );
3068 ty.check_not_missing(db)?;
3069
3070 let concrete_struct_id = try_extract_matches!(ty.lookup_intern(ctx.db), TypeLongId::Concrete)
3071 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Struct))
3072 .ok_or_else(|| ctx.diagnostics.report(path.stable_ptr(db), NotAStruct))?;
3073
3074 if ty.is_phantom(db) {
3075 ctx.diagnostics.report(ctor_syntax.stable_ptr(db), CannotCreateInstancesOfPhantomTypes);
3076 }
3077
3078 let members = db.concrete_struct_members(concrete_struct_id)?;
3079 let mut member_exprs: OrderedHashMap<MemberId, Option<ExprId>> = OrderedHashMap::default();
3080 let mut base_struct = None;
3081
3082 for (index, arg) in ctor_syntax.arguments(db).arguments(db).elements(db).enumerate() {
3083 match arg {
3085 ast::StructArg::StructArgSingle(arg) => {
3086 let arg_identifier = arg.identifier(db);
3087 let arg_name = arg_identifier.text(db);
3088
3089 let Some(member) = members.get(&arg_name) else {
3091 ctx.diagnostics.report(arg_identifier.stable_ptr(db), UnknownMember);
3092 continue;
3093 };
3094 check_struct_member_is_visible(
3095 ctx,
3096 member,
3097 arg_identifier.stable_ptr(db).untyped(),
3098 &arg_name,
3099 );
3100
3101 let arg_expr = match arg.arg_expr(db) {
3103 ast::OptionStructArgExpr::Empty(_) => {
3104 let Ok(expr) = resolve_variable_by_name(
3105 ctx,
3106 &arg_identifier,
3107 path.stable_ptr(db).into(),
3108 ) else {
3109 if member_exprs.insert(member.id, None).is_some() {
3111 ctx.diagnostics.report(
3112 arg_identifier.stable_ptr(db),
3113 MemberSpecifiedMoreThanOnce,
3114 );
3115 }
3116 continue;
3117 };
3118 ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) }
3119 }
3120 ast::OptionStructArgExpr::StructArgExpr(arg_expr) => {
3121 compute_expr_semantic(ctx, &arg_expr.expr(db))
3122 }
3123 };
3124
3125 if member_exprs.insert(member.id, Some(arg_expr.id)).is_some() {
3127 ctx.diagnostics
3128 .report(arg_identifier.stable_ptr(db), MemberSpecifiedMoreThanOnce);
3129 }
3130
3131 let inference = &mut ctx.resolver.inference();
3133 if inference
3134 .conform_ty_for_diag(
3135 arg_expr.ty(),
3136 member.ty,
3137 ctx.diagnostics,
3138 || arg_identifier.stable_ptr(db).untyped(),
3139 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
3140 )
3141 .is_err()
3142 {
3143 continue;
3144 }
3145 }
3146 ast::StructArg::StructArgTail(base_struct_syntax) => {
3147 if index != ctor_syntax.arguments(db).arguments(db).elements(db).len() - 1 {
3149 ctx.diagnostics.report(
3150 base_struct_syntax.stable_ptr(db),
3151 StructBaseStructExpressionNotLast,
3152 );
3153 continue;
3154 }
3155 let base_struct_expr =
3156 compute_expr_semantic(ctx, &base_struct_syntax.expression(db));
3157 let inference = &mut ctx.resolver.inference();
3158 if inference
3159 .conform_ty_for_diag(
3160 base_struct_expr.ty(),
3161 ty,
3162 ctx.diagnostics,
3163 || base_struct_syntax.expression(db).stable_ptr(db).untyped(),
3164 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
3165 )
3166 .is_err()
3167 {
3168 continue;
3169 }
3170
3171 base_struct = Some((base_struct_expr.id, base_struct_syntax));
3172 }
3173 };
3174 }
3175
3176 for (member_name, member) in members.iter() {
3178 if !member_exprs.contains_key(&member.id) {
3179 if base_struct.is_some() {
3180 check_struct_member_is_visible(
3181 ctx,
3182 member,
3183 base_struct.clone().unwrap().1.stable_ptr(db).untyped(),
3184 member_name,
3185 );
3186 } else {
3187 ctx.diagnostics
3188 .report(ctor_syntax.stable_ptr(db), MissingMember(member_name.clone()));
3189 }
3190 }
3191 }
3192 if members.len() == member_exprs.len() {
3193 if let Some((_, base_struct_syntax)) = base_struct {
3194 return Err(ctx
3195 .diagnostics
3196 .report(base_struct_syntax.stable_ptr(db), StructBaseStructExpressionNoEffect));
3197 }
3198 }
3199 Ok(Expr::StructCtor(ExprStructCtor {
3200 concrete_struct_id,
3201 members: member_exprs.into_iter().filter_map(|(x, y)| Some((x, y?))).collect(),
3202 base_struct: base_struct.map(|(x, _)| x),
3203 ty: TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)).intern(db),
3204 stable_ptr: ctor_syntax.stable_ptr(db).into(),
3205 }))
3206}
3207
3208fn statements_and_tail<'a>(
3212 db: &'a dyn SemanticGroup,
3213 syntax: ast::StatementList,
3214) -> (impl Iterator<Item = ast::Statement> + 'a, Option<ast::StatementExpr>) {
3215 let mut statements = syntax.elements(db);
3216 let last = statements.next_back();
3217 if let Some(ast::Statement::Expr(expr)) = &last {
3218 if matches!(expr.semicolon(db), ast::OptionTerminalSemicolon::Empty(_)) {
3220 return (chain!(statements, None), Some(expr.clone()));
3221 }
3222 }
3223 (chain!(statements, last), None)
3224}
3225
3226fn new_literal_expr(
3228 ctx: &mut ComputationContext<'_>,
3229 ty: Option<&str>,
3230 value: BigInt,
3231 stable_ptr: ExprPtr,
3232) -> Maybe<ExprLiteral> {
3233 if let Some(ty_str) = ty {
3234 if ty_str == "NonZero" {
3236 return Err(ctx.diagnostics.report(
3237 stable_ptr.untyped(),
3238 SemanticDiagnosticKind::WrongNumberOfArguments { expected: 1, actual: 0 },
3239 ));
3240 }
3241 let ty = try_get_core_ty_by_name(ctx.db, ty_str.into(), vec![])
3242 .map_err(|err| ctx.diagnostics.report(stable_ptr.untyped(), err))?;
3243 if let Err(err) = validate_literal(ctx.db, ty, &value) {
3244 ctx.diagnostics.report(stable_ptr, SemanticDiagnosticKind::LiteralError(err));
3245 }
3246 return Ok(ExprLiteral { value, ty, stable_ptr });
3247 };
3248 let ty = ctx.resolver.inference().new_type_var(Some(stable_ptr.untyped()));
3249
3250 let trait_id = ctx.db.core_info().numeric_literal_trt;
3252 let generic_args = vec![GenericArgumentId::Type(ty)];
3253 let concrete_trait_id = semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(ctx.db);
3254 let lookup_context = ctx.resolver.impl_lookup_context();
3255 let inference = &mut ctx.resolver.inference();
3256 inference.new_impl_var(concrete_trait_id, Some(stable_ptr.untyped()), lookup_context);
3257
3258 Ok(ExprLiteral { value, ty, stable_ptr })
3259}
3260
3261fn literal_to_semantic(
3263 ctx: &mut ComputationContext<'_>,
3264 literal_syntax: &ast::TerminalLiteralNumber,
3265) -> Maybe<ExprLiteral> {
3266 let db = ctx.db;
3267
3268 let (value, ty) = literal_syntax.numeric_value_and_suffix(db).unwrap_or_default();
3269 let ty = ty.as_ref().map(SmolStr::as_str);
3270
3271 new_literal_expr(ctx, ty, value, literal_syntax.stable_ptr(db).into())
3272}
3273
3274fn short_string_to_semantic(
3276 ctx: &mut ComputationContext<'_>,
3277 short_string_syntax: &ast::TerminalShortString,
3278) -> Maybe<ExprLiteral> {
3279 let db = ctx.db;
3280
3281 let value = short_string_syntax.numeric_value(db).unwrap_or_default();
3282
3283 let suffix = short_string_syntax.suffix(db);
3284 let suffix = suffix.as_ref().map(SmolStr::as_str);
3285
3286 new_literal_expr(ctx, suffix, value, short_string_syntax.stable_ptr(db).into())
3287}
3288
3289fn new_string_literal_expr(
3291 ctx: &mut ComputationContext<'_>,
3292 value: String,
3293 stable_ptr: ExprPtr,
3294) -> Maybe<ExprStringLiteral> {
3295 let ty = ctx.resolver.inference().new_type_var(Some(stable_ptr.untyped()));
3296
3297 let trait_id = ctx.db.core_info().string_literal_trt;
3298 let generic_args = vec![GenericArgumentId::Type(ty)];
3299 let concrete_trait_id = semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(ctx.db);
3300 let lookup_context = ctx.resolver.impl_lookup_context();
3301 let inference = &mut ctx.resolver.inference();
3302 inference.new_impl_var(concrete_trait_id, Some(stable_ptr.untyped()), lookup_context);
3303
3304 Ok(ExprStringLiteral { value, ty, stable_ptr })
3305}
3306
3307fn string_literal_to_semantic(
3309 ctx: &mut ComputationContext<'_>,
3310 string_syntax: &ast::TerminalString,
3311) -> Maybe<ExprStringLiteral> {
3312 let db = ctx.db;
3313 let stable_ptr = string_syntax.stable_ptr(db);
3314
3315 let value = string_syntax.string_value(db).unwrap_or_default();
3316 new_string_literal_expr(ctx, value, stable_ptr.into())
3319}
3320fn try_extract_identifier_from_path(
3324 db: &dyn SyntaxGroup,
3325 path: &ast::ExprPath,
3326) -> Option<(TerminalIdentifier, bool)> {
3327 let mut segments = path.segments(db).elements(db);
3328 require(segments.len() <= 2)?;
3329 let Some(PathSegment::Simple(first)) = segments.next() else {
3330 return None;
3331 };
3332 let Some(second) = segments.next() else {
3333 return Some((first.ident(db), false));
3334 };
3335 let second = try_extract_matches!(second, PathSegment::Simple)?;
3336 if first.identifier(db) == MACRO_CALL_SITE && path.placeholder_marker(db).is_some() {
3337 Some((second.ident(db), true))
3338 } else {
3339 None
3340 }
3341}
3342
3343fn expr_as_identifier(
3346 ctx: &mut ComputationContext<'_>,
3347 path: &ast::ExprPath,
3348 db: &dyn SyntaxGroup,
3349) -> Maybe<SmolStr> {
3350 let mut segments = path.segments(db).elements(db);
3351 if segments.len() == 1 {
3352 Ok(segments.next().unwrap().identifier(db))
3353 } else {
3354 Err(ctx.diagnostics.report(path.stable_ptr(db), InvalidMemberExpression))
3355 }
3356}
3357
3358fn dot_expr(
3361 ctx: &mut ComputationContext<'_>,
3362 lexpr: ExprAndId,
3363 rhs_syntax: ast::Expr,
3364 stable_ptr: ast::ExprPtr,
3365) -> Maybe<Expr> {
3366 match rhs_syntax {
3368 ast::Expr::Path(expr) => member_access_expr(ctx, lexpr, expr, stable_ptr),
3369 ast::Expr::FunctionCall(expr) => method_call_expr(ctx, lexpr, expr, stable_ptr),
3370 _ => Err(ctx.diagnostics.report(rhs_syntax.stable_ptr(ctx.db), InvalidMemberExpression)),
3371 }
3372}
3373
3374fn traits_in_context(
3376 ctx: &mut ComputationContext<'_>,
3377) -> Maybe<OrderedHashMap<TraitId, LookupItemId>> {
3378 let mut traits =
3379 ctx.db.module_usable_trait_ids(ctx.resolver.prelude_submodule())?.deref().clone();
3380 traits.extend(
3381 ctx.db
3382 .module_usable_trait_ids(ctx.resolver.module_file_id.0)?
3383 .iter()
3384 .map(|(k, v)| (*k, *v)),
3385 );
3386 Ok(traits)
3387}
3388
3389fn method_call_expr(
3393 ctx: &mut ComputationContext<'_>,
3394 lexpr: ExprAndId,
3395 expr: ast::ExprFunctionCall,
3396 stable_ptr: ast::ExprPtr,
3397) -> Maybe<Expr> {
3398 let db = ctx.db;
3401 let path = expr.path(db);
3402 let Some([segment]) = path.segments(db).elements(db).collect_array() else {
3403 return Err(ctx.diagnostics.report(expr.stable_ptr(ctx.db), InvalidMemberExpression));
3404 };
3405 let func_name = segment.identifier(db);
3406 let generic_args_syntax = segment.generic_args(db);
3407
3408 if !ctx.reduce_ty(lexpr.ty()).is_var_free(ctx.db) {
3409 ctx.resolver.inference().solve().ok();
3413 }
3414
3415 let mut candidate_traits = traits_in_context(ctx)?;
3416
3417 for generic_param in &ctx.resolver.data.generic_params {
3419 if generic_param.kind(ctx.db) == GenericKind::Impl {
3420 let Ok(trait_id) = ctx.db.generic_impl_param_trait(*generic_param) else {
3421 continue;
3422 };
3423 candidate_traits
3424 .insert(trait_id, LookupItemId::ModuleItem(ModuleItemId::Trait(trait_id)));
3425 }
3426 }
3427
3428 let module_file_id = ctx.resolver.module_file_id;
3430 let lookup_context = ctx.resolver.impl_lookup_context();
3431 let lexpr_clone = lexpr.clone();
3432 let db = ctx.db;
3433 let (function_id, actual_trait_id, fixed_lexpr, mutability) =
3434 compute_method_function_call_data(
3435 ctx,
3436 candidate_traits.keys().copied().collect_vec().as_slice(),
3437 func_name.clone(),
3438 lexpr,
3439 path.stable_ptr(db).untyped(),
3440 generic_args_syntax,
3441 |ty, method_name, inference_errors| {
3442 let relevant_traits = if !inference_errors.is_empty() {
3443 vec![]
3444 } else {
3445 match_method_to_traits(
3446 db,
3447 ty,
3448 &method_name,
3449 lookup_context.clone(),
3450 module_file_id,
3451 lexpr_clone.stable_ptr().untyped(),
3452 )
3453 };
3454 Some(CannotCallMethod { ty, method_name, inference_errors, relevant_traits })
3455 },
3456 |_, trait_function_id0, trait_function_id1| {
3457 Some(AmbiguousTrait { trait_function_id0, trait_function_id1 })
3458 },
3459 )
3460 .inspect_err(|_| {
3461 for arg in expr.arguments(db).arguments(db).elements(db) {
3463 compute_named_argument_clause(ctx, arg, None);
3464 }
3465 })?;
3466
3467 if let Ok(trait_definition_data) = ctx.db.priv_trait_definition_data(actual_trait_id) {
3468 if let Some(trait_item_info) = trait_definition_data.get_trait_item_info(&func_name) {
3469 ctx.resolver.validate_feature_constraints(
3470 ctx.diagnostics,
3471 &segment.identifier_ast(db),
3472 &trait_item_info,
3473 );
3474 }
3475 }
3476 if let LookupItemId::ModuleItem(item_id) = candidate_traits[&actual_trait_id] {
3477 ctx.resolver.insert_used_use(item_id);
3478 }
3479 ctx.resolver.data.resolved_items.mark_concrete(
3480 ctx.db,
3481 &segment,
3482 ResolvedConcreteItem::Function(function_id),
3483 );
3484
3485 let mut args_iter = expr.arguments(db).arguments(db).elements(db);
3487 let mut named_args = vec![NamedArg(fixed_lexpr, None, mutability)];
3489 let closure_params: OrderedHashMap<TypeId, TypeId> =
3491 concrete_function_closure_params(ctx.db, function_id)?;
3492 for ty in function_parameter_types(ctx, function_id)?.skip(1) {
3493 let Some(arg_syntax) = args_iter.next() else {
3494 break;
3495 };
3496 named_args.push(compute_named_argument_clause(
3497 ctx,
3498 arg_syntax,
3499 closure_params.get(&ty).copied(),
3500 ));
3501 }
3502
3503 if let Some(arg_syntax) = args_iter.next() {
3505 named_args.push(compute_named_argument_clause(ctx, arg_syntax, None));
3506 }
3507
3508 expr_function_call(ctx, function_id, named_args, expr.stable_ptr(db), stable_ptr)
3509}
3510
3511fn member_access_expr(
3513 ctx: &mut ComputationContext<'_>,
3514 lexpr: ExprAndId,
3515 rhs_syntax: ast::ExprPath,
3516 stable_ptr: ast::ExprPtr,
3517) -> Maybe<Expr> {
3518 let db = ctx.db;
3519
3520 let member_name = expr_as_identifier(ctx, &rhs_syntax, db)?;
3522 let (n_snapshots, long_ty) =
3523 finalized_snapshot_peeled_ty(ctx, lexpr.ty(), rhs_syntax.stable_ptr(db))?;
3524
3525 match &long_ty {
3526 TypeLongId::Concrete(_) | TypeLongId::Tuple(_) | TypeLongId::FixedSizeArray { .. } => {
3527 let Some(EnrichedTypeMemberAccess { member, deref_functions }) =
3528 get_enriched_type_member_access(ctx, lexpr.clone(), stable_ptr, &member_name)?
3529 else {
3530 return Err(ctx.diagnostics.report(
3531 rhs_syntax.stable_ptr(db),
3532 NoSuchTypeMember { ty: long_ty.intern(ctx.db), member_name },
3533 ));
3534 };
3535 check_struct_member_is_visible(
3536 ctx,
3537 &member,
3538 rhs_syntax.stable_ptr(db).untyped(),
3539 &member_name,
3540 );
3541 let member_path = match &long_ty {
3542 TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id))
3543 if n_snapshots == 0 && deref_functions.is_empty() =>
3544 {
3545 lexpr.as_member_path().map(|parent| ExprVarMemberPath::Member {
3546 parent: Box::new(parent),
3547 member_id: member.id,
3548 stable_ptr,
3549 concrete_struct_id: *concrete_struct_id,
3550 ty: member.ty,
3551 })
3552 }
3553 _ => None,
3554 };
3555 let mut derefed_expr: ExprAndId = lexpr;
3556 for (deref_function, mutability) in &deref_functions {
3557 let cur_expr = expr_function_call(
3558 ctx,
3559 *deref_function,
3560 vec![NamedArg(derefed_expr, None, *mutability)],
3561 stable_ptr,
3562 stable_ptr,
3563 )
3564 .unwrap();
3565
3566 derefed_expr =
3567 ExprAndId { expr: cur_expr.clone(), id: ctx.arenas.exprs.alloc(cur_expr) };
3568 }
3569 let (_, long_ty) =
3570 finalized_snapshot_peeled_ty(ctx, derefed_expr.ty(), rhs_syntax.stable_ptr(db))?;
3571 let derefed_expr_concrete_struct_id = match long_ty {
3572 TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) => {
3573 concrete_struct_id
3574 }
3575 _ => unreachable!(),
3576 };
3577 let ty = if !deref_functions.is_empty() {
3578 member.ty
3579 } else {
3580 wrap_in_snapshots(ctx.db, member.ty, n_snapshots)
3581 };
3582 Ok(Expr::MemberAccess(ExprMemberAccess {
3583 expr: derefed_expr.id,
3584 concrete_struct_id: derefed_expr_concrete_struct_id,
3585 member: member.id,
3586 ty,
3587 member_path,
3588 n_snapshots,
3589 stable_ptr,
3590 }))
3591 }
3592
3593 TypeLongId::Snapshot(_) => {
3594 Err(ctx.diagnostics.report(rhs_syntax.stable_ptr(db), Unsupported))
3596 }
3597 TypeLongId::Closure(_) => {
3598 Err(ctx.diagnostics.report(rhs_syntax.stable_ptr(db), Unsupported))
3599 }
3600 TypeLongId::ImplType(impl_type_id) => {
3601 unreachable!(
3602 "Impl type should've been reduced {:?}.",
3603 impl_type_id.debug(ctx.db.elongate())
3604 )
3605 }
3606 TypeLongId::Var(_) => Err(ctx.diagnostics.report(
3607 rhs_syntax.stable_ptr(db),
3608 InternalInferenceError(InferenceError::TypeNotInferred(long_ty.intern(ctx.db))),
3609 )),
3610 TypeLongId::GenericParameter(_) | TypeLongId::Coupon(_) => Err(ctx.diagnostics.report(
3611 rhs_syntax.stable_ptr(db),
3612 TypeHasNoMembers { ty: long_ty.intern(ctx.db), member_name },
3613 )),
3614 TypeLongId::Missing(diag_added) => Err(*diag_added),
3615 }
3616}
3617
3618fn get_enriched_type_member_access(
3623 ctx: &mut ComputationContext<'_>,
3624 expr: ExprAndId,
3625 stable_ptr: ast::ExprPtr,
3626 accessed_member_name: &str,
3627) -> Maybe<Option<EnrichedTypeMemberAccess>> {
3628 let mut ty = ctx.reduce_ty(expr.ty());
3629 if !ty.is_var_free(ctx.db) {
3630 ctx.resolver.inference().solve().ok();
3634 ty = ctx.reduce_ty(ty);
3635 }
3636 let base_var = match &expr.expr {
3637 Expr::Var(expr_var) => Some(expr_var.var),
3638 Expr::MemberAccess(ExprMemberAccess { member_path: Some(member_path), .. }) => {
3639 Some(member_path.base_var())
3640 }
3641 _ => None,
3642 };
3643 let is_mut_var = base_var
3644 .filter(|var_id| matches!(ctx.semantic_defs.get(var_id), Some(var) if var.is_mut()))
3645 .is_some();
3646 let key = (ty, is_mut_var);
3647 let mut enriched_members = match ctx.resolver.type_enriched_members.entry(key) {
3648 Entry::Occupied(entry) => {
3649 let e = entry.get();
3650 match e.get_member(accessed_member_name) {
3651 Some(value) => return Ok(Some(value)),
3652 None => {
3653 if e.deref_chain.len() == e.explored_derefs {
3654 return Ok(None);
3656 }
3657 }
3658 }
3659 entry.swap_remove()
3661 }
3662 Entry::Vacant(_) => {
3663 let (_, long_ty) = finalized_snapshot_peeled_ty(ctx, ty, stable_ptr)?;
3664 let members =
3665 if let TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) = long_ty {
3666 let members = ctx.db.concrete_struct_members(concrete_struct_id)?;
3667 if let Some(member) = members.get(accessed_member_name) {
3668 return Ok(Some(EnrichedTypeMemberAccess {
3670 member: member.clone(),
3671 deref_functions: vec![],
3672 }));
3673 }
3674 members.iter().map(|(k, v)| (k.clone(), (v.clone(), 0))).collect()
3675 } else {
3676 Default::default()
3677 };
3678
3679 EnrichedMembers {
3680 members,
3681 deref_chain: ctx.db.deref_chain(ty, is_mut_var)?.derefs,
3682 explored_derefs: 0,
3683 }
3684 }
3685 };
3686 enrich_members(ctx, &mut enriched_members, stable_ptr, accessed_member_name)?;
3687 let e = ctx.resolver.type_enriched_members.entry(key).or_insert(enriched_members);
3688 Ok(e.get_member(accessed_member_name))
3689}
3690
3691fn enrich_members(
3696 ctx: &mut ComputationContext<'_>,
3697 enriched_members: &mut EnrichedMembers,
3698 stable_ptr: ast::ExprPtr,
3699 accessed_member_name: &str,
3700) -> Maybe<()> {
3701 let EnrichedMembers { members: enriched, deref_chain, explored_derefs } = enriched_members;
3702
3703 for deref_info in deref_chain.iter().skip(*explored_derefs).cloned() {
3705 *explored_derefs += 1;
3706 let (_, long_ty) = finalized_snapshot_peeled_ty(ctx, deref_info.target_ty, stable_ptr)?;
3707 if let TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) = long_ty {
3708 let members = ctx.db.concrete_struct_members(concrete_struct_id)?;
3709 for (member_name, member) in members.iter() {
3710 enriched
3712 .entry(member_name.clone())
3713 .or_insert_with(|| (member.clone(), *explored_derefs));
3714 }
3715 if members.contains_key(accessed_member_name) {
3717 break;
3719 }
3720 }
3721 }
3722 Ok::<(), cairo_lang_diagnostics::DiagnosticAdded>(())
3723}
3724
3725fn finalized_snapshot_peeled_ty(
3727 ctx: &mut ComputationContext<'_>,
3728 ty: TypeId,
3729 stable_ptr: impl Into<SyntaxStablePtrId>,
3730) -> Maybe<(usize, TypeLongId)> {
3731 let ty = ctx.reduce_ty(ty);
3732 let (base_snapshots, mut long_ty) = peel_snapshots(ctx.db, ty);
3733 if let TypeLongId::ImplType(impl_type_id) = long_ty {
3734 let inference = &mut ctx.resolver.inference();
3735 let Ok(ty) = inference.reduce_impl_ty(impl_type_id) else {
3736 return Err(ctx
3737 .diagnostics
3738 .report(stable_ptr, InternalInferenceError(InferenceError::TypeNotInferred(ty))));
3739 };
3740 long_ty = ty.lookup_intern(ctx.db);
3741 }
3742 if matches!(long_ty, TypeLongId::Var(_)) {
3743 ctx.resolver.inference().solve().ok();
3745 long_ty = ctx.resolver.inference().rewrite(long_ty).no_err();
3746 }
3747 let (additional_snapshots, long_ty) = peel_snapshots_ex(ctx.db, long_ty);
3748 Ok((base_snapshots + additional_snapshots, long_ty))
3749}
3750
3751fn resolve_expr_path(ctx: &mut ComputationContext<'_>, path: &ast::ExprPath) -> Maybe<Expr> {
3753 let db = ctx.db;
3754 if path.segments(db).elements(db).len() == 0 {
3755 return Err(ctx.diagnostics.report(path.stable_ptr(db), Unsupported));
3756 }
3757
3758 if let Some((identifier, is_callsite_prefixed)) = try_extract_identifier_from_path(db, path) {
3760 let variable_name = identifier.text(ctx.db);
3761 if let Some(res) = get_binded_expr_by_name(
3762 ctx,
3763 &variable_name,
3764 is_callsite_prefixed,
3765 path.stable_ptr(ctx.db).into(),
3766 ) {
3767 match res.clone() {
3768 Expr::Var(expr_var) => {
3769 let item = ResolvedGenericItem::Variable(expr_var.var);
3770 ctx.resolver
3771 .data
3772 .resolved_items
3773 .generic
3774 .insert(identifier.stable_ptr(db), item);
3775 }
3776 Expr::Constant(expr_const) => {
3777 let item = ResolvedConcreteItem::Constant(expr_const.const_value_id);
3778 ctx.resolver
3779 .data
3780 .resolved_items
3781 .concrete
3782 .insert(identifier.stable_ptr(db), item);
3783 }
3784 _ => unreachable!(
3785 "get_binded_expr_by_name should only return variables or constants"
3786 ),
3787 };
3788 return Ok(res);
3789 }
3790 }
3791
3792 let resolved_item: ResolvedConcreteItem = ctx.resolver.resolve_concrete_path_ex(
3793 ctx.diagnostics,
3794 path,
3795 NotFoundItemType::Identifier,
3796 ResolutionContext::Statement(&mut ctx.environment),
3797 )?;
3798
3799 match resolved_item {
3800 ResolvedConcreteItem::Constant(const_value_id) => Ok(Expr::Constant(ExprConstant {
3801 const_value_id,
3802 ty: const_value_id.ty(db)?,
3803 stable_ptr: path.stable_ptr(db).into(),
3804 })),
3805
3806 ResolvedConcreteItem::Variant(variant) if variant.ty == unit_ty(db) => {
3807 let stable_ptr = path.stable_ptr(db).into();
3808 let concrete_enum_id = variant.concrete_enum_id;
3809 Ok(semantic::Expr::EnumVariantCtor(semantic::ExprEnumVariantCtor {
3810 variant,
3811 value_expr: unit_expr(ctx, stable_ptr),
3812 ty: TypeLongId::Concrete(ConcreteTypeId::Enum(concrete_enum_id)).intern(db),
3813 stable_ptr,
3814 }))
3815 }
3816 resolved_item => Err(ctx.diagnostics.report(
3817 path.stable_ptr(db),
3818 UnexpectedElement {
3819 expected: vec![ElementKind::Variable, ElementKind::Constant],
3820 actual: (&resolved_item).into(),
3821 },
3822 )),
3823 }
3824}
3825
3826pub fn resolve_variable_by_name(
3832 ctx: &mut ComputationContext<'_>,
3833 identifier: &ast::TerminalIdentifier,
3834 stable_ptr: ast::ExprPtr,
3835) -> Maybe<Expr> {
3836 let variable_name = identifier.text(ctx.db);
3837 let res = get_binded_expr_by_name(ctx, &variable_name, false, stable_ptr).ok_or_else(|| {
3838 ctx.diagnostics.report(identifier.stable_ptr(ctx.db), VariableNotFound(variable_name))
3839 })?;
3840 let item = ResolvedGenericItem::Variable(extract_matches!(&res, Expr::Var).var);
3841 ctx.resolver.data.resolved_items.generic.insert(identifier.stable_ptr(ctx.db), item);
3842 Ok(res)
3843}
3844
3845pub fn get_binded_expr_by_name(
3847 ctx: &mut ComputationContext<'_>,
3848 variable_name: &SmolStr,
3849 is_callsite_prefixed: bool,
3850 stable_ptr: ast::ExprPtr,
3851) -> Option<Expr> {
3852 let mut maybe_env = Some(&mut *ctx.environment);
3853 let mut cur_offset =
3854 ExpansionOffset::new(stable_ptr.lookup(ctx.db).as_syntax_node().offset(ctx.db));
3855 let mut found_callsite_scope = false;
3856 while let Some(env) = maybe_env {
3857 if let Some(macro_info) = &env.macro_info {
3860 if let Some(new_offset) = cur_offset.mapped(¯o_info.mappings) {
3861 maybe_env = env.parent.as_deref_mut();
3862 cur_offset = new_offset;
3863 continue;
3864 }
3865 }
3866 if !is_callsite_prefixed || found_callsite_scope {
3867 if let Some(var) = env.variables.get(variable_name) {
3868 env.used_variables.insert(var.id());
3869 return match var {
3870 Binding::LocalItem(local_const) => match local_const.kind.clone() {
3871 crate::StatementItemKind::Constant(const_value_id, ty) => {
3872 Some(Expr::Constant(ExprConstant { const_value_id, ty, stable_ptr }))
3873 }
3874 },
3875 Binding::LocalVar(_) | Binding::Param(_) => {
3876 Some(Expr::Var(ExprVar { var: var.id(), ty: var.ty(), stable_ptr }))
3877 }
3878 };
3879 }
3880 }
3881
3882 if env.macro_info.is_some() {
3884 if is_callsite_prefixed && !found_callsite_scope {
3885 found_callsite_scope = true;
3886 } else {
3887 break;
3888 }
3889 }
3890 maybe_env = env.parent.as_deref_mut();
3891 }
3892 None
3893}
3894
3895fn expr_function_call(
3897 ctx: &mut ComputationContext<'_>,
3898 function_id: FunctionId,
3899 mut named_args: Vec<NamedArg>,
3900 call_ptr: impl Into<SyntaxStablePtrId>,
3901 stable_ptr: ast::ExprPtr,
3902) -> Maybe<Expr> {
3903 let coupon_arg = maybe_pop_coupon_argument(ctx, &mut named_args, function_id);
3904
3905 let signature = ctx.db.concrete_function_signature(function_id)?;
3906 let signature = ctx.resolver.inference().rewrite(signature).unwrap();
3907
3908 if named_args.len() != signature.params.len() {
3910 return Err(ctx.diagnostics.report(
3911 call_ptr,
3912 WrongNumberOfArguments { expected: signature.params.len(), actual: named_args.len() },
3913 ));
3914 }
3915
3916 check_named_arguments(&named_args, &signature, ctx)?;
3918
3919 let mut args = Vec::new();
3920 for (NamedArg(arg, _name, mutability), param) in
3921 named_args.into_iter().zip(signature.params.iter())
3922 {
3923 let arg_ty = arg.ty();
3924 let param_ty = param.ty;
3925 if !arg_ty.is_missing(ctx.db) {
3929 let inference = &mut ctx.resolver.inference();
3930 let _ = inference.conform_ty_for_diag(
3931 arg_ty,
3932 param_ty,
3933 ctx.diagnostics,
3934 || arg.stable_ptr().untyped(),
3935 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
3936 );
3937 }
3938
3939 args.push(if param.mutability == Mutability::Reference {
3940 let Some(ref_arg) = arg.as_member_path() else {
3942 return Err(ctx.diagnostics.report(arg.deref(), RefArgNotAVariable));
3943 };
3944 if !ctx.semantic_defs[&ref_arg.base_var()].is_mut() {
3946 ctx.diagnostics.report(arg.deref(), RefArgNotMutable);
3947 }
3948 if mutability != Mutability::Reference {
3950 ctx.diagnostics.report(arg.deref(), RefArgNotExplicit);
3951 }
3952 ExprFunctionCallArg::Reference(ref_arg)
3953 } else {
3954 if mutability != Mutability::Immutable {
3956 ctx.diagnostics.report(arg.deref(), ImmutableArgWithModifiers);
3957 }
3958 ExprFunctionCallArg::Value(arg.id)
3959 });
3960 }
3961
3962 let expr_function_call = ExprFunctionCall {
3963 function: function_id,
3964 args,
3965 coupon_arg,
3966 ty: signature.return_type,
3967 stable_ptr,
3968 };
3969 if signature.panicable && has_panic_incompatibility(ctx) {
3971 return Err(ctx.diagnostics.report(call_ptr, PanicableFromNonPanicable));
3974 }
3975 Ok(Expr::FunctionCall(expr_function_call))
3976}
3977
3978fn maybe_pop_coupon_argument(
3981 ctx: &mut ComputationContext<'_>,
3982 named_args: &mut Vec<NamedArg>,
3983 function_id: FunctionId,
3984) -> Option<id_arena::Id<Expr>> {
3985 let mut coupon_arg: Option<ExprId> = None;
3986 if let Some(NamedArg(arg, Some(name_terminal), mutability)) = named_args.last() {
3987 let coupons_enabled = are_coupons_enabled(ctx.db, ctx.resolver.module_file_id);
3988 if name_terminal.text(ctx.db) == "__coupon__" && coupons_enabled {
3989 let expected_ty = TypeLongId::Coupon(function_id).intern(ctx.db);
3991 let arg_ty = arg.ty();
3992 if !arg_ty.is_missing(ctx.db) {
3993 let inference = &mut ctx.resolver.inference();
3994 let _ = inference.conform_ty_for_diag(
3995 arg_ty,
3996 expected_ty,
3997 ctx.diagnostics,
3998 || arg.stable_ptr().untyped(),
3999 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
4000 );
4001 }
4002
4003 if *mutability != Mutability::Immutable {
4005 ctx.diagnostics.report(arg.deref(), CouponArgumentNoModifiers);
4006 }
4007
4008 coupon_arg = Some(arg.id);
4009
4010 named_args.pop();
4012 }
4013 }
4014 coupon_arg
4015}
4016
4017fn has_panic_incompatibility(ctx: &mut ComputationContext<'_>) -> bool {
4019 if let Some(signature) = ctx.signature {
4020 !signature.panicable
4022 } else {
4023 false
4024 }
4025}
4026
4027fn check_named_arguments(
4029 named_args: &[NamedArg],
4030 signature: &Signature,
4031 ctx: &mut ComputationContext<'_>,
4032) -> Maybe<()> {
4033 let mut res: Maybe<()> = Ok(());
4034
4035 let mut seen_named_arguments: bool = false;
4038 let mut reported_unnamed_argument_follows_named: bool = false;
4041 for (NamedArg(arg, name_opt, _mutability), param) in
4042 named_args.iter().zip(signature.params.iter())
4043 {
4044 if let Some(name_terminal) = name_opt {
4046 seen_named_arguments = true;
4047 let name = name_terminal.text(ctx.db);
4048 if param.name != name.clone() {
4049 res = Err(ctx.diagnostics.report(
4050 name_terminal.stable_ptr(ctx.db),
4051 NamedArgumentMismatch { expected: param.name.clone(), found: name },
4052 ));
4053 }
4054 } else if seen_named_arguments && !reported_unnamed_argument_follows_named {
4055 reported_unnamed_argument_follows_named = true;
4056 res = Err(ctx.diagnostics.report(arg.deref(), UnnamedArgumentFollowsNamed));
4057 }
4058 }
4059 res
4060}
4061
4062pub fn compute_and_append_statement_semantic(
4065 ctx: &mut ComputationContext<'_>,
4066 syntax: ast::Statement,
4067 statements: &mut Vec<StatementId>,
4068) -> Maybe<()> {
4069 let db = ctx.db;
4070 let crate_id = ctx.resolver.owning_crate_id;
4071
4072 validate_statement_attributes(ctx, &syntax);
4075 let feature_restore = ctx
4076 .resolver
4077 .data
4078 .feature_config
4079 .override_with(extract_item_feature_config(db, crate_id, &syntax, ctx.diagnostics));
4080 let _ = match &syntax {
4081 ast::Statement::Let(let_syntax) => {
4082 let rhs_syntax = &let_syntax.rhs(db);
4083 let (rhs_expr, ty) = match let_syntax.type_clause(db) {
4084 ast::OptionTypeClause::Empty(_) => {
4085 let rhs_expr = compute_expr_semantic(ctx, rhs_syntax);
4086 let inferred_type = rhs_expr.ty();
4087 (rhs_expr, inferred_type)
4088 }
4089 ast::OptionTypeClause::TypeClause(type_clause) => {
4090 let var_type_path = type_clause.ty(db);
4091 let explicit_type = resolve_type_ex(
4092 db,
4093 ctx.diagnostics,
4094 &mut ctx.resolver,
4095 &var_type_path,
4096 ResolutionContext::Statement(&mut ctx.environment),
4097 );
4098
4099 let rhs_expr = compute_expr_semantic(ctx, rhs_syntax);
4100 let inferred_type = ctx.reduce_ty(rhs_expr.ty());
4101 if !inferred_type.is_missing(db) {
4102 let inference = &mut ctx.resolver.inference();
4103 let _ = inference.conform_ty_for_diag(
4104 inferred_type,
4105 explicit_type,
4106 ctx.diagnostics,
4107 || rhs_syntax.stable_ptr(db).untyped(),
4108 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
4109 );
4110 }
4111 (rhs_expr, explicit_type)
4112 }
4113 };
4114 let rhs_expr_id = rhs_expr.id;
4115
4116 let else_clause = match let_syntax.let_else_clause(db) {
4117 ast::OptionLetElseClause::Empty(_) => None,
4118 ast::OptionLetElseClause::LetElseClause(else_clause) => {
4119 let else_block_syntax = else_clause.else_block(db);
4120 let else_block_stable_ptr = else_block_syntax.stable_ptr(db);
4121
4122 let else_block =
4123 compute_expr_semantic(ctx, &ast::Expr::Block(else_block_syntax));
4124
4125 if else_block.ty() != never_ty(db) {
4126 ctx.diagnostics.report(else_block_stable_ptr, NonNeverLetElseType);
4128 }
4129
4130 Some(else_block.id)
4131 }
4132 };
4133
4134 let pattern = compute_pattern_semantic(
4135 ctx,
4136 &let_syntax.pattern(db),
4137 ty,
4138 &mut UnorderedHashMap::default(),
4139 );
4140 let variables = pattern.variables(&ctx.arenas.patterns);
4141 for v in variables {
4142 let var_def = Binding::LocalVar(v.var.clone());
4143 if let Some(old_var) =
4144 ctx.environment.variables.insert(v.name.clone(), var_def.clone())
4145 {
4146 if matches!(old_var, Binding::LocalItem(_)) {
4147 return Err(ctx
4148 .diagnostics
4149 .report(v.stable_ptr, MultipleDefinitionforBinding(v.name.clone())));
4150 }
4151 add_unused_binding_warning(
4152 ctx.diagnostics,
4153 ctx.db,
4154 &ctx.environment.used_variables,
4155 &v.name,
4156 &old_var,
4157 );
4158 }
4159 if ctx.macro_defined_var_unhygienic {
4160 if let Some(macro_info) = &mut ctx.environment.macro_info {
4161 macro_info.vars_to_expose.push((v.name.clone(), var_def.clone()));
4162 }
4163 }
4164 ctx.semantic_defs.insert(var_def.id(), var_def);
4165 }
4166 statements.push(ctx.arenas.statements.alloc(semantic::Statement::Let(
4167 semantic::StatementLet {
4168 pattern: pattern.id,
4169 expr: rhs_expr_id,
4170 else_clause,
4171 stable_ptr: syntax.stable_ptr(db),
4172 },
4173 )));
4174 Ok(()) as Maybe<()>
4175 }
4176 ast::Statement::Expr(stmt_expr_syntax) => {
4177 let expr_syntax = stmt_expr_syntax.expr(db);
4178 if let ast::Expr::InlineMacro(inline_macro_syntax) = &expr_syntax {
4179 expand_macro_for_statement(ctx, inline_macro_syntax, false, statements)?;
4180 } else {
4181 let expr = compute_expr_semantic(ctx, &expr_syntax);
4182 if matches!(stmt_expr_syntax.semicolon(db), ast::OptionTerminalSemicolon::Empty(_))
4183 && !matches!(
4184 expr_syntax,
4185 ast::Expr::Block(_)
4186 | ast::Expr::If(_)
4187 | ast::Expr::Match(_)
4188 | ast::Expr::Loop(_)
4189 | ast::Expr::While(_)
4190 | ast::Expr::For(_)
4191 )
4192 {
4193 ctx.diagnostics.report_after(expr_syntax.stable_ptr(db), MissingSemicolon);
4194 }
4195 let ty: TypeId = expr.ty();
4196 if let TypeLongId::Concrete(concrete) = ty.lookup_intern(db) {
4197 if concrete.is_must_use(db)? {
4198 ctx.diagnostics
4199 .report(expr_syntax.stable_ptr(db), UnhandledMustUseType(ty));
4200 }
4201 }
4202 if let Expr::FunctionCall(expr_function_call) = &expr.expr {
4203 let generic_function_id =
4204 expr_function_call.function.lookup_intern(db).function.generic_function;
4205 if generic_function_id.is_must_use(db)? {
4206 ctx.diagnostics
4207 .report(expr_syntax.stable_ptr(db), UnhandledMustUseFunction);
4208 }
4209 }
4210 statements.push(ctx.arenas.statements.alloc(semantic::Statement::Expr(
4211 semantic::StatementExpr { expr: expr.id, stable_ptr: syntax.stable_ptr(db) },
4212 )));
4213 }
4214 Ok(())
4215 }
4216 ast::Statement::Continue(continue_syntax) => {
4217 if !ctx.is_inside_loop() {
4218 return Err(ctx
4219 .diagnostics
4220 .report(continue_syntax.stable_ptr(db), ContinueOnlyAllowedInsideALoop));
4221 }
4222 statements.push(ctx.arenas.statements.alloc(semantic::Statement::Continue(
4223 semantic::StatementContinue { stable_ptr: syntax.stable_ptr(db) },
4224 )));
4225 Ok(())
4226 }
4227 ast::Statement::Return(return_syntax) => {
4228 let (expr_option, expr_ty, stable_ptr) = match return_syntax.expr_clause(db) {
4229 ast::OptionExprClause::Empty(empty_clause) => {
4230 (None, unit_ty(db), empty_clause.stable_ptr(db).untyped())
4231 }
4232 ast::OptionExprClause::ExprClause(expr_clause) => {
4233 let expr_syntax = expr_clause.expr(db);
4234 let expr = compute_expr_semantic(ctx, &expr_syntax);
4235 (Some(expr.id), expr.ty(), expr_syntax.stable_ptr(db).untyped())
4236 }
4237 };
4238 let expected_ty = match &ctx.inner_ctx {
4239 None => ctx.get_return_type().ok_or_else(|| {
4240 ctx.diagnostics.report(
4241 return_syntax.stable_ptr(db),
4242 UnsupportedOutsideOfFunction(
4243 UnsupportedOutsideOfFunctionFeatureName::ReturnStatement,
4244 ),
4245 )
4246 })?,
4247 Some(ctx) => ctx.return_type,
4248 };
4249
4250 let expected_ty = ctx.reduce_ty(expected_ty);
4251 let expr_ty = ctx.reduce_ty(expr_ty);
4252 if !expected_ty.is_missing(db) && !expr_ty.is_missing(db) {
4253 let inference = &mut ctx.resolver.inference();
4254 let _ = inference.conform_ty_for_diag(
4255 expr_ty,
4256 expected_ty,
4257 ctx.diagnostics,
4258 || stable_ptr,
4259 |actual_ty, expected_ty| WrongReturnType { expected_ty, actual_ty },
4260 );
4261 }
4262 statements.push(ctx.arenas.statements.alloc(semantic::Statement::Return(
4263 semantic::StatementReturn { expr_option, stable_ptr: syntax.stable_ptr(db) },
4264 )));
4265 Ok(())
4266 }
4267 ast::Statement::Break(break_syntax) => {
4268 let (expr_option, ty, stable_ptr) = match break_syntax.expr_clause(db) {
4269 ast::OptionExprClause::Empty(expr_empty) => {
4270 (None, unit_ty(db), expr_empty.stable_ptr(db).untyped())
4271 }
4272 ast::OptionExprClause::ExprClause(expr_clause) => {
4273 let expr_syntax = expr_clause.expr(db);
4274 let expr = compute_expr_semantic(ctx, &expr_syntax);
4275
4276 (Some(expr.id), expr.ty(), expr.stable_ptr().untyped())
4277 }
4278 };
4279 let ty = ctx.reduce_ty(ty);
4280
4281 if !ctx.is_inside_loop() {
4282 return Err(ctx
4283 .diagnostics
4284 .report(break_syntax.stable_ptr(db), BreakOnlyAllowedInsideALoop));
4285 }
4286
4287 if let Some(inner_ctx) = &mut ctx.inner_ctx {
4288 match &mut inner_ctx.kind {
4289 InnerContextKind::Loop { type_merger, .. } => {
4290 type_merger.try_merge_types(
4291 ctx.db,
4292 ctx.diagnostics,
4293 &mut ctx.resolver.inference(),
4294 ty,
4295 stable_ptr,
4296 );
4297 }
4298 InnerContextKind::While | InnerContextKind::For => {
4299 if expr_option.is_some() {
4300 ctx.diagnostics.report(
4301 break_syntax.stable_ptr(db),
4302 BreakWithValueOnlyAllowedInsideALoop,
4303 );
4304 };
4305 }
4306 InnerContextKind::Closure => unreachable!("Not inside a loop."),
4307 }
4308 }
4309
4310 statements.push(ctx.arenas.statements.alloc(semantic::Statement::Break(
4311 semantic::StatementBreak { expr_option, stable_ptr: syntax.stable_ptr(db) },
4312 )));
4313 Ok(())
4314 }
4315 ast::Statement::Item(stmt_item_syntax) => {
4316 let item_syntax = &stmt_item_syntax.item(db);
4317 match item_syntax {
4318 ast::ModuleItem::Constant(const_syntax) => {
4319 let lhs = const_syntax.type_clause(db).ty(db);
4320 let rhs = const_syntax.value(db);
4321 let rhs_expr = compute_expr_semantic(ctx, &rhs);
4322 let explicit_type = resolve_type_ex(
4323 db,
4324 ctx.diagnostics,
4325 &mut ctx.resolver,
4326 &lhs,
4327 ResolutionContext::Statement(&mut ctx.environment),
4328 );
4329 let rhs_resolved_expr = resolve_const_expr_and_evaluate(
4330 db,
4331 ctx,
4332 &rhs_expr,
4333 stmt_item_syntax.stable_ptr(db).untyped(),
4334 explicit_type,
4335 false,
4336 );
4337 let name_syntax = const_syntax.name(db);
4338 let name = name_syntax.text(db);
4339 let rhs_id = StatementConstLongId(
4340 ctx.resolver.module_file_id,
4341 const_syntax.stable_ptr(db),
4342 );
4343 let var_def = Binding::LocalItem(LocalItem {
4344 id: StatementItemId::Constant(rhs_id.intern(db)),
4345 kind: StatementItemKind::Constant(
4346 db.intern_const_value(rhs_resolved_expr.clone()),
4347 rhs_resolved_expr.ty(db)?,
4348 ),
4349 });
4350 add_item_to_statement_environment(
4351 ctx,
4352 name,
4353 var_def,
4354 name_syntax.stable_ptr(db),
4355 );
4356 }
4357 ast::ModuleItem::Use(use_syntax) => {
4358 for leaf in get_all_path_leaves(db, use_syntax) {
4359 let stable_ptr = leaf.stable_ptr(db);
4360 let segments = get_use_path_segments(db, ast::UsePath::Leaf(leaf))?;
4361 let resolved_item = ctx.resolver.resolve_generic_path(
4362 ctx.diagnostics,
4363 segments,
4364 NotFoundItemType::Identifier,
4365 ResolutionContext::Statement(&mut ctx.environment),
4366 )?;
4367 let var_def_id = StatementItemId::Use(
4368 StatementUseLongId(ctx.resolver.module_file_id, stable_ptr).intern(db),
4369 );
4370 let name = var_def_id.name(db);
4371 match resolved_item {
4372 ResolvedGenericItem::GenericConstant(const_id) => {
4373 let var_def = Binding::LocalItem(LocalItem {
4374 id: var_def_id,
4375 kind: StatementItemKind::Constant(
4376 db.constant_const_value(const_id)?,
4377 db.constant_const_type(const_id)?,
4378 ),
4379 });
4380 add_item_to_statement_environment(ctx, name, var_def, stable_ptr);
4381 }
4382 ResolvedGenericItem::GenericType(generic_type_id) => {
4383 add_type_to_statement_environment(
4384 ctx,
4385 name,
4386 ResolvedGenericItem::GenericType(generic_type_id),
4387 stable_ptr,
4388 );
4389 }
4390 ResolvedGenericItem::Module(_)
4391 | ResolvedGenericItem::GenericFunction(_)
4392 | ResolvedGenericItem::GenericTypeAlias(_)
4393 | ResolvedGenericItem::GenericImplAlias(_)
4394 | ResolvedGenericItem::Variant(_)
4395 | ResolvedGenericItem::Trait(_)
4396 | ResolvedGenericItem::Impl(_)
4397 | ResolvedGenericItem::Variable(_)
4398 | ResolvedGenericItem::TraitItem(_)
4399 | ResolvedGenericItem::Macro(_) => {
4400 return Err(ctx
4401 .diagnostics
4402 .report(stable_ptr, UnsupportedUseItemInStatement));
4403 }
4404 }
4405 }
4406 }
4407 ast::ModuleItem::Module(_) => {
4408 unreachable!("Modules are not supported inside a function.")
4409 }
4410 ast::ModuleItem::FreeFunction(_) => {
4411 unreachable!("FreeFunction type not supported.")
4412 }
4413 ast::ModuleItem::ExternFunction(_) => {
4414 unreachable!("ExternFunction type not supported.")
4415 }
4416 ast::ModuleItem::ExternType(_) => unreachable!("ExternType type not supported."),
4417 ast::ModuleItem::Trait(_) => unreachable!("Trait type not supported."),
4418 ast::ModuleItem::Impl(_) => unreachable!("Impl type not supported."),
4419 ast::ModuleItem::ImplAlias(_) => unreachable!("ImplAlias type not supported."),
4420 ast::ModuleItem::Struct(_) => unreachable!("Struct type not supported."),
4421 ast::ModuleItem::Enum(_) => unreachable!("Enum type not supported."),
4422 ast::ModuleItem::TypeAlias(_) => unreachable!("TypeAlias type not supported."),
4423 ast::ModuleItem::InlineMacro(_) => unreachable!("InlineMacro type not supported."),
4424 ast::ModuleItem::HeaderDoc(_) => unreachable!("HeaderDoc type not supported."),
4425 ast::ModuleItem::Missing(_) => unreachable!("Missing type not supported."),
4426 ast::ModuleItem::MacroDeclaration(_) => todo!(),
4427 }
4428 statements.push(ctx.arenas.statements.alloc(semantic::Statement::Item(
4429 semantic::StatementItem { stable_ptr: syntax.stable_ptr(db) },
4430 )));
4431 Ok(())
4432 }
4433 ast::Statement::Missing(_) => todo!(),
4434 };
4435 ctx.resolver.data.feature_config.restore(feature_restore);
4436 Ok(())
4437}
4438fn add_item_to_statement_environment(
4441 ctx: &mut ComputationContext<'_>,
4442 name: SmolStr,
4443 var_def: Binding,
4444 stable_ptr: impl Into<SyntaxStablePtrId>,
4445) {
4446 if let Some(old_var) = ctx.environment.variables.insert(name.clone(), var_def.clone()) {
4447 ctx.diagnostics.report(
4448 stable_ptr,
4449 match old_var {
4450 Binding::LocalItem(_) => MultipleConstantDefinition(name),
4451 Binding::LocalVar(_) | Binding::Param(_) => MultipleDefinitionforBinding(name),
4452 },
4453 );
4454 }
4455 ctx.semantic_defs.insert(var_def.id(), var_def);
4456}
4457
4458fn add_type_to_statement_environment(
4461 ctx: &mut ComputationContext<'_>,
4462 name: SmolStr,
4463 resolved_generic_item: ResolvedGenericItem,
4464 stable_ptr: impl Into<SyntaxStablePtrId> + std::marker::Copy,
4465) {
4466 if ctx
4467 .environment
4468 .use_items
4469 .insert(
4470 name.clone(),
4471 StatementGenericItemData { resolved_generic_item, stable_ptr: stable_ptr.into() },
4472 )
4473 .is_some()
4474 {
4475 ctx.diagnostics.report(stable_ptr, MultipleGenericItemDefinition(name));
4476 }
4477}
4478
4479fn compute_bool_condition_semantic(
4482 ctx: &mut ComputationContext<'_>,
4483 condition_syntax: &ast::Expr,
4484) -> ExprAndId {
4485 let condition = compute_expr_semantic(ctx, condition_syntax);
4486 let inference = &mut ctx.resolver.inference();
4487 let _ = inference.conform_ty_for_diag(
4488 condition.ty(),
4489 core_bool_ty(ctx.db),
4490 ctx.diagnostics,
4491 || condition.stable_ptr().untyped(),
4492 |condition_ty, _expected_ty| ConditionNotBool(condition_ty),
4493 );
4494 condition
4495}
4496
4497fn check_struct_member_is_visible(
4499 ctx: &mut ComputationContext<'_>,
4500 member: &Member,
4501 stable_ptr: SyntaxStablePtrId,
4502 member_name: &SmolStr,
4503) {
4504 let db = ctx.db;
4505 let containing_module_id = member.id.parent_module(db);
4506 if ctx.resolver.ignore_visibility_checks(containing_module_id) {
4507 return;
4508 }
4509 let user_module_id = ctx.resolver.module_file_id.0;
4510 if !visibility::peek_visible_in(db, member.visibility, containing_module_id, user_module_id) {
4511 ctx.diagnostics.report(stable_ptr, MemberNotVisible(member_name.clone()));
4512 }
4513}
4514
4515fn validate_statement_attributes(ctx: &mut ComputationContext<'_>, syntax: &ast::Statement) {
4518 let allowed_attributes = ctx.db.allowed_statement_attributes();
4519 let mut diagnostics = vec![];
4520 validate_attributes_flat(
4521 ctx.db,
4522 &allowed_attributes,
4523 &OrderedHashSet::default(),
4524 syntax,
4525 &mut diagnostics,
4526 );
4527 for diagnostic in diagnostics {
4529 ctx.diagnostics
4530 .report(diagnostic.stable_ptr, SemanticDiagnosticKind::UnknownStatementAttribute);
4531 }
4532}
4533
4534fn function_parameter_types(
4536 ctx: &mut ComputationContext<'_>,
4537 function: FunctionId,
4538) -> Maybe<impl Iterator<Item = TypeId>> {
4539 let signature = ctx.db.concrete_function_signature(function)?;
4540 let param_types = signature.params.into_iter().map(|param| param.ty);
4541 Ok(param_types)
4542}
4543
4544fn match_method_to_traits(
4548 db: &dyn SemanticGroup,
4549 ty: semantic::TypeId,
4550 method_name: &SmolStr,
4551 lookup_context: ImplLookupContext,
4552 module_file_id: ModuleFileId,
4553 stable_ptr: SyntaxStablePtrId,
4554) -> Vec<String> {
4555 let visible_traits = db
4556 .visible_traits_from_module(module_file_id)
4557 .unwrap_or_else(|| Arc::new(OrderedHashMap::default()));
4558
4559 visible_traits
4560 .iter()
4561 .filter_map(|(trait_id, path)| {
4562 let mut data = InferenceData::new(InferenceId::NoContext);
4563 let mut inference = data.inference(db);
4564 let trait_function =
4565 db.trait_function_by_name(*trait_id, method_name.clone()).ok()??;
4566 let (concrete_trait_id, _) = inference.infer_concrete_trait_by_self(
4567 trait_function,
4568 ty,
4569 &lookup_context,
4570 Some(stable_ptr),
4571 |_| {},
4572 )?;
4573 inference.solve().ok();
4574 match inference.trait_solution_set(
4575 concrete_trait_id,
4576 ImplVarTraitItemMappings::default(),
4577 lookup_context.clone(),
4578 ) {
4579 Ok(SolutionSet::Unique(_) | SolutionSet::Ambiguous(_)) => Some(path.clone()),
4580 _ => None,
4581 }
4582 })
4583 .collect()
4584}