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