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