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