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