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