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::{get_all_path_leaves, validate_attributes_flat};
12use cairo_lang_defs::diagnostic_utils::StableLocation;
13use cairo_lang_defs::ids::{
14 EnumId, FunctionTitleId, GenericKind, LanguageElementId, LocalVarLongId, LookupItemId,
15 MemberId, ModuleFileId, ModuleItemId, NamedLanguageElementId, StatementConstLongId,
16 StatementItemId, StatementUseLongId, TraitFunctionId, TraitId, VarId,
17};
18use cairo_lang_defs::plugin::{InlineMacroExprPlugin, MacroPluginMetadata};
19use cairo_lang_diagnostics::{Maybe, ToOption, skip_diagnostic};
20use cairo_lang_filesystem::cfg::CfgSet;
21use cairo_lang_filesystem::ids::{FileKind, FileLongId, VirtualFile};
22use cairo_lang_proc_macros::DebugWithDb;
23use cairo_lang_syntax::node::ast::{
24 BinaryOperator, BlockOrIf, ClosureParamWrapper, ExprPtr, OptionReturnTypeClause, PatternListOr,
25 PatternStructParam, UnaryOperator,
26};
27use cairo_lang_syntax::node::db::SyntaxGroup;
28use cairo_lang_syntax::node::helpers::{GetIdentifier, PathSegmentEx};
29use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
30use cairo_lang_syntax::node::kind::SyntaxKind;
31use cairo_lang_syntax::node::{Terminal, TypedStablePtr, TypedSyntaxNode, ast};
32use cairo_lang_utils as utils;
33use cairo_lang_utils::ordered_hash_map::{Entry, OrderedHashMap};
34use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
35use cairo_lang_utils::unordered_hash_map::UnorderedHashMap;
36use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;
37use cairo_lang_utils::{Intern, LookupIntern, OptionHelper, extract_matches, try_extract_matches};
38use itertools::{Itertools, chain, zip_eq};
39use num_bigint::BigInt;
40use num_traits::ToPrimitive;
41use smol_str::SmolStr;
42
43use super::inference::canonic::ResultNoErrEx;
44use super::inference::conform::InferenceConform;
45use super::inference::infers::InferenceEmbeddings;
46use super::inference::{Inference, InferenceData, InferenceError};
47use super::objects::*;
48use super::pattern::{
49 Pattern, PatternEnumVariant, PatternFixedSizeArray, PatternLiteral, PatternMissing,
50 PatternOtherwise, PatternTuple, PatternVariable,
51};
52use crate::corelib::{
53 core_binary_operator, core_bool_ty, core_unary_operator, false_literal_expr, get_usize_ty,
54 never_ty, true_literal_expr, try_get_core_ty_by_name, unit_expr, unit_ty,
55 unwrap_error_propagation_type, validate_literal,
56};
57use crate::db::SemanticGroup;
58use crate::diagnostic::SemanticDiagnosticKind::{self, *};
59use crate::diagnostic::{
60 ElementKind, MultiArmExprKind, NotFoundItemType, SemanticDiagnostics,
61 SemanticDiagnosticsBuilder, TraitInferenceErrors, UnsupportedOutsideOfFunctionFeatureName,
62};
63use crate::expr::inference::solver::SolutionSet;
64use crate::expr::inference::{ImplVarTraitItemMappings, InferenceId};
65use crate::items::constant::{ConstValue, resolve_const_expr_and_evaluate, validate_const_expr};
66use crate::items::enm::SemanticEnumEx;
67use crate::items::feature_kind::extract_item_feature_config;
68use crate::items::functions::{concrete_function_closure_params, function_signature_params};
69use crate::items::imp::{ImplLookupContext, filter_candidate_traits, infer_impl_by_self};
70use crate::items::modifiers::compute_mutability;
71use crate::items::us::get_use_path_segments;
72use crate::items::visibility;
73use crate::resolve::{
74 EnrichedMembers, EnrichedTypeMemberAccess, ResolutionContext, ResolvedConcreteItem,
75 ResolvedGenericItem, Resolver,
76};
77use crate::semantic::{self, Binding, FunctionId, LocalVariable, TypeId, TypeLongId};
78use crate::substitution::SemanticRewriter;
79use crate::types::{
80 ClosureTypeLongId, ConcreteTypeId, add_type_based_diagnostics, are_coupons_enabled,
81 extract_fixed_size_array_size, peel_snapshots, peel_snapshots_ex, resolve_type_ex,
82 verify_fixed_size_array_size, wrap_in_snapshots,
83};
84use crate::usage::Usages;
85use crate::{
86 ConcreteEnumId, GenericArgumentId, GenericParam, LocalItem, Member, Mutability, Parameter,
87 PatternStringLiteral, PatternStruct, Signature, StatementItemKind,
88};
89
90#[derive(Debug, Clone)]
92pub struct ExprAndId {
93 pub expr: Expr,
94 pub id: ExprId,
95}
96impl Deref for ExprAndId {
97 type Target = Expr;
98
99 fn deref(&self) -> &Self::Target {
100 &self.expr
101 }
102}
103
104#[derive(Debug, Clone)]
105pub struct PatternAndId {
106 pub pattern: Pattern,
107 pub id: PatternId,
108}
109impl Deref for PatternAndId {
110 type Target = Pattern;
111
112 fn deref(&self) -> &Self::Target {
113 &self.pattern
114 }
115}
116
117#[derive(Debug, Clone)]
119pub struct NamedArg(ExprAndId, Option<ast::TerminalIdentifier>, Mutability);
120
121pub enum ContextFunction {
122 Global,
123 Function(Maybe<FunctionId>),
124}
125
126#[derive(Debug, Clone)]
128struct InnerContext {
129 return_type: TypeId,
131 kind: InnerContextKind,
133}
134
135#[derive(Debug, Clone)]
137enum InnerContextKind {
138 Loop { type_merger: FlowMergeTypeHelper },
140 While,
142 For,
144 Closure,
146}
147
148pub struct ComputationContext<'ctx> {
150 pub db: &'ctx dyn SemanticGroup,
151 pub diagnostics: &'ctx mut SemanticDiagnostics,
152 pub resolver: Resolver<'ctx>,
153 signature: Option<&'ctx Signature>,
154 environment: Box<Environment>,
155 pub arenas: Arenas,
157 function_id: ContextFunction,
158 pub semantic_defs: UnorderedHashMap<semantic::VarId, semantic::Binding>,
160 inner_ctx: Option<InnerContext>,
161 cfg_set: Arc<CfgSet>,
162 are_closures_in_context: bool,
165}
166impl<'ctx> ComputationContext<'ctx> {
167 pub fn new(
168 db: &'ctx dyn SemanticGroup,
169 diagnostics: &'ctx mut SemanticDiagnostics,
170 resolver: Resolver<'ctx>,
171 signature: Option<&'ctx Signature>,
172 environment: Environment,
173 function_id: ContextFunction,
174 ) -> Self {
175 let semantic_defs =
176 environment.variables.values().by_ref().map(|var| (var.id(), var.clone())).collect();
177 let cfg_set =
178 resolver.settings.cfg_set.clone().map(Arc::new).unwrap_or_else(|| db.cfg_set());
179 Self {
180 db,
181 diagnostics,
182 resolver,
183 signature,
184 environment: Box::new(environment),
185 arenas: Default::default(),
186 function_id,
187 semantic_defs,
188 inner_ctx: None,
189 cfg_set,
190 are_closures_in_context: false,
191 }
192 }
193
194 fn run_in_subscope<T, F>(&mut self, f: F) -> T
199 where
200 F: FnOnce(&mut Self) -> T,
201 {
202 let new_environment = Box::new(Environment::empty());
204 let old_environment = std::mem::replace(&mut self.environment, new_environment);
205 self.environment.parent = Some(old_environment);
206
207 let res = f(self);
208
209 let parent = self.environment.parent.take();
211 for (var_name, var) in std::mem::take(&mut self.environment.variables) {
212 self.add_unused_binding_warning(&var_name, &var);
213 }
214 for (ty_name, statement_ty) in std::mem::take(&mut self.environment.use_items) {
216 if !self.environment.used_use_items.contains(&ty_name) && !ty_name.starts_with('_') {
217 self.diagnostics.report(statement_ty.stable_ptr, UnusedUse);
218 }
219 }
220 self.environment = parent.unwrap();
221 res
222 }
223
224 fn add_unused_binding_warning(&mut self, var_name: &str, var: &Binding) {
226 if !self.environment.used_variables.contains(&var.id()) && !var_name.starts_with('_') {
227 match var {
228 Binding::LocalItem(local_item) => match local_item.id {
229 StatementItemId::Constant(_) => {
230 self.diagnostics.report(var.stable_ptr(self.db), UnusedConstant);
231 }
232 StatementItemId::Use(_) => {
233 self.diagnostics.report(var.stable_ptr(self.db), UnusedUse);
234 }
235 },
236 Binding::LocalVar(_) | Binding::Param(_) => {
237 self.diagnostics.report(var.stable_ptr(self.db), UnusedVariable);
238 }
239 }
240 }
241 }
242
243 fn get_return_type(&mut self) -> Option<TypeId> {
245 if let Some(inner_ctx) = &self.inner_ctx {
246 return Some(inner_ctx.return_type);
247 }
248
249 if let Some(signature) = self.signature {
250 return Some(signature.return_type);
251 }
252
253 None
254 }
255
256 fn reduce_ty(&mut self, ty: TypeId) -> TypeId {
257 self.resolver.inference().rewrite(ty).no_err()
258 }
259
260 pub fn apply_inference_rewriter_to_exprs(&mut self) {
263 let mut analyzed_types = UnorderedHashSet::<_>::default();
264 for (_id, expr) in &mut self.arenas.exprs {
265 self.resolver.inference().internal_rewrite(expr).no_err();
266 if analyzed_types.insert(expr.ty()) {
268 add_type_based_diagnostics(self.db, self.diagnostics, expr.ty(), &*expr);
269 }
270 }
271 }
272
273 fn apply_inference_rewriter(&mut self) {
275 self.apply_inference_rewriter_to_exprs();
276 for (_id, pattern) in &mut self.arenas.patterns {
277 self.resolver.inference().internal_rewrite(pattern).no_err();
278 }
279 for (_id, stmt) in &mut self.arenas.statements {
280 self.resolver.inference().internal_rewrite(stmt).no_err();
281 }
282 }
283 fn is_inside_loop(&self) -> bool {
285 let Some(inner_ctx) = &self.inner_ctx else {
286 return false;
287 };
288
289 match inner_ctx.kind {
290 InnerContextKind::Closure => false,
291 InnerContextKind::Loop { .. } | InnerContextKind::While | InnerContextKind::For => true,
292 }
293 }
294}
295
296pub type EnvVariables = OrderedHashMap<SmolStr, Binding>;
298
299type EnvItems = OrderedHashMap<SmolStr, StatementGenericItemData>;
300
301#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
303#[debug_db(dyn SemanticGroup + 'static)]
304struct StatementGenericItemData {
305 resolved_generic_item: ResolvedGenericItem,
306 stable_ptr: SyntaxStablePtrId,
307}
308
309#[derive(Clone, Debug, PartialEq, Eq)]
313pub struct Environment {
314 parent: Option<Box<Environment>>,
315 variables: EnvVariables,
316 used_variables: UnorderedHashSet<semantic::VarId>,
317 use_items: EnvItems,
318 used_use_items: UnorderedHashSet<SmolStr>,
319}
320impl Environment {
321 pub fn add_param(
323 &mut self,
324 db: &dyn SemanticGroup,
325 diagnostics: &mut SemanticDiagnostics,
326 semantic_param: Parameter,
327 ast_param: &ast::Param,
328 function_title_id: Option<FunctionTitleId>,
329 ) -> Maybe<()> {
330 if let utils::ordered_hash_map::Entry::Vacant(entry) =
331 self.variables.entry(semantic_param.name.clone())
332 {
333 entry.insert(Binding::Param(semantic_param));
334 Ok(())
335 } else {
336 Err(diagnostics.report(
337 ast_param.stable_ptr(db),
338 ParamNameRedefinition { function_title_id, param_name: semantic_param.name },
339 ))
340 }
341 }
342
343 pub fn empty() -> Self {
344 Self {
345 parent: None,
346 variables: Default::default(),
347 used_variables: Default::default(),
348 use_items: Default::default(),
349 used_use_items: Default::default(),
350 }
351 }
352}
353
354pub fn get_statement_item_by_name(
356 env: &mut Environment,
357 item_name: &SmolStr,
358) -> Option<ResolvedGenericItem> {
359 let mut maybe_env = Some(&mut *env);
360 while let Some(curr_env) = maybe_env {
361 if let Some(var) = curr_env.use_items.get(item_name) {
362 curr_env.used_use_items.insert(item_name.clone());
363 return Some(var.resolved_generic_item.clone());
364 }
365 maybe_env = curr_env.parent.as_deref_mut();
366 }
367 None
368}
369
370pub fn compute_expr_semantic(ctx: &mut ComputationContext<'_>, syntax: &ast::Expr) -> ExprAndId {
374 let expr = maybe_compute_expr_semantic(ctx, syntax);
375 let expr = wrap_maybe_with_missing(ctx, expr, syntax.stable_ptr(ctx.db));
376 let id = ctx.arenas.exprs.alloc(expr.clone());
377 ExprAndId { expr, id }
378}
379
380fn wrap_maybe_with_missing(
382 ctx: &mut ComputationContext<'_>,
383 expr: Maybe<Expr>,
384 stable_ptr: ast::ExprPtr,
385) -> Expr {
386 expr.unwrap_or_else(|diag_added| {
387 Expr::Missing(ExprMissing {
388 ty: TypeId::missing(ctx.db, diag_added),
389 stable_ptr,
390 diag_added,
391 })
392 })
393}
394
395pub fn maybe_compute_expr_semantic(
397 ctx: &mut ComputationContext<'_>,
398 syntax: &ast::Expr,
399) -> Maybe<Expr> {
400 let db = ctx.db;
401
402 match syntax {
404 ast::Expr::Path(path) => resolve_expr_path(ctx, path),
405 ast::Expr::Literal(literal_syntax) => {
406 Ok(Expr::Literal(literal_to_semantic(ctx, literal_syntax)?))
407 }
408 ast::Expr::ShortString(literal_syntax) => {
409 Ok(Expr::Literal(short_string_to_semantic(ctx, literal_syntax)?))
410 }
411 ast::Expr::String(literal_syntax) => {
412 Ok(Expr::StringLiteral(string_literal_to_semantic(ctx, literal_syntax)?))
413 }
414 ast::Expr::False(syntax) => Ok(false_literal_expr(ctx, syntax.stable_ptr(db).into())),
415 ast::Expr::True(syntax) => Ok(true_literal_expr(ctx, syntax.stable_ptr(db).into())),
416 ast::Expr::Parenthesized(paren_syntax) => {
417 maybe_compute_expr_semantic(ctx, &paren_syntax.expr(db))
418 }
419 ast::Expr::Unary(syntax) => compute_expr_unary_semantic(ctx, syntax),
420 ast::Expr::Binary(binary_op_syntax) => compute_expr_binary_semantic(ctx, binary_op_syntax),
421 ast::Expr::Tuple(tuple_syntax) => compute_expr_tuple_semantic(ctx, tuple_syntax),
422 ast::Expr::FunctionCall(call_syntax) => {
423 compute_expr_function_call_semantic(ctx, call_syntax)
424 }
425 ast::Expr::StructCtorCall(ctor_syntax) => struct_ctor_expr(ctx, ctor_syntax),
426 ast::Expr::Block(block_syntax) => compute_expr_block_semantic(ctx, block_syntax),
427 ast::Expr::Match(expr_match) => compute_expr_match_semantic(ctx, expr_match),
428 ast::Expr::If(expr_if) => compute_expr_if_semantic(ctx, expr_if),
429 ast::Expr::Loop(expr_loop) => compute_expr_loop_semantic(ctx, expr_loop),
430 ast::Expr::While(expr_while) => compute_expr_while_semantic(ctx, expr_while),
431 ast::Expr::ErrorPropagate(expr) => compute_expr_error_propagate_semantic(ctx, expr),
432 ast::Expr::InlineMacro(expr) => compute_expr_inline_macro_semantic(ctx, expr),
433 ast::Expr::Missing(_) | ast::Expr::FieldInitShorthand(_) => {
434 Err(ctx.diagnostics.report(syntax.stable_ptr(db), Unsupported))
435 }
436 ast::Expr::Indexed(expr) => compute_expr_indexed_semantic(ctx, expr),
437 ast::Expr::FixedSizeArray(expr) => compute_expr_fixed_size_array_semantic(ctx, expr),
438 ast::Expr::For(expr) => compute_expr_for_semantic(ctx, expr),
439 ast::Expr::Closure(expr) => compute_expr_closure_semantic(ctx, expr, None),
440 }
441}
442
443fn compute_expr_inline_macro_semantic(
444 ctx: &mut ComputationContext<'_>,
445 syntax: &ast::ExprInlineMacro,
446) -> Maybe<Expr> {
447 let db = ctx.db;
448
449 let crate_id = ctx.resolver.owning_crate_id;
450
451 let macro_name = syntax.path(db).as_syntax_node().get_text_without_trivia(db);
452 let Some(macro_plugin_id) =
453 ctx.db.crate_inline_macro_plugins(crate_id).get(¯o_name).cloned()
454 else {
455 return Err(ctx
456 .diagnostics
457 .report(syntax.stable_ptr(db), InlineMacroNotFound(macro_name.into())));
458 };
459 let macro_plugin = ctx.db.lookup_intern_inline_macro_plugin(macro_plugin_id);
460
461 if syntax.as_syntax_node().descendants(db).any(|node| {
463 matches!(
464 node.kind(db),
465 SyntaxKind::ExprMissing
466 | SyntaxKind::WrappedArgListMissing
467 | SyntaxKind::StatementMissing
468 | SyntaxKind::ModuleItemMissing
469 | SyntaxKind::TraitItemMissing
470 | SyntaxKind::ImplItemMissing
471 | SyntaxKind::TokenMissing
472 | SyntaxKind::TokenSkipped
473 )
474 }) {
475 return Err(skip_diagnostic());
476 }
477
478 let result = macro_plugin.generate_code(
479 db,
480 syntax,
481 &MacroPluginMetadata {
482 cfg_set: &ctx.cfg_set,
483 declared_derives: &ctx.db.declared_derives(crate_id),
484 allowed_features: &ctx.resolver.data.feature_config.allowed_features,
485 edition: ctx.resolver.settings.edition,
486 },
487 );
488 let mut diag_added = None;
489 for diagnostic in result.diagnostics {
490 diag_added =
491 Some(ctx.diagnostics.report(diagnostic.stable_ptr, PluginDiagnostic(diagnostic)));
492 }
493
494 let Some(code) = result.code else {
495 return Err(diag_added.unwrap_or_else(|| {
496 ctx.diagnostics.report(syntax.stable_ptr(db), InlineMacroFailed(macro_name.into()))
497 }));
498 };
499
500 let new_file = FileLongId::Virtual(VirtualFile {
502 parent: Some(syntax.stable_ptr(db).untyped().file_id(ctx.db)),
503 name: code.name,
504 content: code.content.into(),
505 code_mappings: code.code_mappings.into(),
506 kind: FileKind::Expr,
507 })
508 .intern(ctx.db);
509 let expr_syntax = ctx.db.file_expr_syntax(new_file)?;
510 let expr = compute_expr_semantic(ctx, &expr_syntax);
511 Ok(expr.expr)
512}
513
514fn compute_expr_unary_semantic(
515 ctx: &mut ComputationContext<'_>,
516 syntax: &ast::ExprUnary,
517) -> Maybe<Expr> {
518 let db = ctx.db;
519 let unary_op = syntax.op(db);
520 let inner = syntax.expr(db);
521 match (&unary_op, &inner) {
522 (UnaryOperator::Minus(_), ast::Expr::Literal(literal)) => {
524 let (value, ty) = literal.numeric_value_and_suffix(db).unwrap_or_default();
525 let ty = ty.as_ref().map(SmolStr::as_str);
526
527 Ok(Expr::Literal(new_literal_expr(ctx, ty, -value, syntax.stable_ptr(db).into())?))
528 }
529 (UnaryOperator::At(_), inner) => {
530 let expr = compute_expr_semantic(ctx, inner);
531
532 let ty = TypeLongId::Snapshot(expr.ty()).intern(ctx.db);
533 Ok(Expr::Snapshot(ExprSnapshot {
534 inner: expr.id,
535 ty,
536 stable_ptr: syntax.stable_ptr(db).into(),
537 }))
538 }
539 (UnaryOperator::Desnap(_), inner) => {
540 let (desnapped_expr, desnapped_ty) = {
541 let desnapped_expr = compute_expr_semantic(ctx, inner);
543 let desnapped_expr_type = ctx.reduce_ty(desnapped_expr.ty());
544
545 let desnapped_ty = match desnapped_expr_type.lookup_intern(ctx.db) {
546 TypeLongId::Var(_) | TypeLongId::ImplType(_) => {
547 let inference = &mut ctx.resolver.inference();
548 let desnap_expr_type =
550 inference.new_type_var(Some(inner.stable_ptr(db).untyped()));
551 let desnapped_expr_type_var =
552 TypeLongId::Snapshot(desnap_expr_type).intern(ctx.db);
553 if let Err(err_set) =
554 inference.conform_ty(desnapped_expr_type_var, desnapped_expr_type)
555 {
556 let diag_added = ctx.diagnostics.report(
557 syntax.stable_ptr(db),
558 WrongArgumentType {
559 expected_ty: desnapped_expr_type_var,
560 actual_ty: desnapped_expr_type,
561 },
562 );
563 inference.consume_reported_error(err_set, diag_added);
564 return Err(diag_added);
565 };
566 ctx.reduce_ty(desnap_expr_type)
567 }
568 TypeLongId::Snapshot(ty) => ty,
569 _ => {
570 return Err(ctx
571 .diagnostics
572 .report(unary_op.stable_ptr(db), DesnapNonSnapshot));
573 }
574 };
575 (desnapped_expr, desnapped_ty)
576 };
577
578 Ok(Expr::Desnap(ExprDesnap {
579 inner: desnapped_expr.id,
580 ty: desnapped_ty,
581 stable_ptr: syntax.stable_ptr(db).into(),
582 }))
583 }
584 (_, inner) => {
585 let expr = compute_expr_semantic(ctx, inner);
586
587 let concrete_trait_function = match core_unary_operator(
588 ctx.db,
589 &mut ctx.resolver.inference(),
590 &unary_op,
591 syntax.stable_ptr(db).untyped(),
592 )? {
593 Err(err_kind) => {
594 return Err(ctx.diagnostics.report(unary_op.stable_ptr(db), err_kind));
595 }
596 Ok(function) => function,
597 };
598
599 let impl_lookup_context = ctx.resolver.impl_lookup_context();
600 let inference = &mut ctx.resolver.inference();
601 let function = inference
602 .infer_trait_function(
603 concrete_trait_function,
604 &impl_lookup_context,
605 Some(syntax.stable_ptr(db).untyped()),
606 )
607 .map_err(|err_set| {
608 inference.report_on_pending_error(
609 err_set,
610 ctx.diagnostics,
611 syntax.stable_ptr(db).untyped(),
612 )
613 })?;
614
615 expr_function_call(
616 ctx,
617 function,
618 vec![NamedArg(expr, None, Mutability::Immutable)],
619 syntax.stable_ptr(db),
620 syntax.stable_ptr(db).into(),
621 )
622 }
623 }
624}
625
626fn compute_expr_binary_semantic(
627 ctx: &mut ComputationContext<'_>,
628 syntax: &ast::ExprBinary,
629) -> Maybe<Expr> {
630 let db = ctx.db;
631
632 let stable_ptr = syntax.stable_ptr(db).into();
633 let binary_op = syntax.op(db);
634 let lhs_syntax = &syntax.lhs(db);
635 let rhs_syntax = syntax.rhs(db);
636
637 match binary_op {
638 ast::BinaryOperator::Dot(_) => {
639 let lexpr = compute_expr_semantic(ctx, lhs_syntax);
640 dot_expr(ctx, lexpr, rhs_syntax, stable_ptr)
641 }
642 ast::BinaryOperator::Eq(_) => {
643 let lexpr = compute_expr_semantic(ctx, lhs_syntax);
644 let rexpr = compute_expr_semantic(ctx, &rhs_syntax);
645
646 let member_path = match lexpr.expr {
647 Expr::Var(expr) => ExprVarMemberPath::Var(expr),
648 Expr::MemberAccess(ExprMemberAccess { member_path: Some(ref_arg), .. }) => ref_arg,
649 _ => {
650 return Err(ctx
651 .diagnostics
652 .report(lhs_syntax.stable_ptr(db), InvalidLhsForAssignment));
653 }
654 };
655
656 let inference = &mut ctx.resolver.inference();
657 inference.conform_ty_for_diag(
658 rexpr.ty(),
659 member_path.ty(),
660 ctx.diagnostics,
661 || rhs_syntax.stable_ptr(db).untyped(),
662 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
663 )?;
664 if !ctx.semantic_defs[&member_path.base_var()].is_mut() {
666 ctx.diagnostics.report(syntax.stable_ptr(db), AssignmentToImmutableVar);
667 }
668 Ok(Expr::Assignment(ExprAssignment {
669 ref_arg: member_path,
670 rhs: rexpr.id,
671 ty: unit_ty(db),
672 stable_ptr,
673 }))
674 }
675 ast::BinaryOperator::AndAnd(_) | ast::BinaryOperator::OrOr(_) => {
676 let lexpr = compute_expr_semantic(ctx, lhs_syntax);
677 let rexpr = compute_expr_semantic(ctx, &rhs_syntax);
678
679 let op = match binary_op {
680 ast::BinaryOperator::AndAnd(_) => LogicalOperator::AndAnd,
681 ast::BinaryOperator::OrOr(_) => LogicalOperator::OrOr,
682 _ => unreachable!(),
683 };
684
685 let inference = &mut ctx.resolver.inference();
686 let bool_ty = core_bool_ty(db);
687 let _ = inference.conform_ty_for_diag(
688 lexpr.expr.ty(),
689 bool_ty,
690 ctx.diagnostics,
691 || lhs_syntax.stable_ptr(db).untyped(),
692 |actual_ty, expected_ty| WrongType { expected_ty, actual_ty },
693 );
694 let _ = inference.conform_ty_for_diag(
695 rexpr.expr.ty(),
696 bool_ty,
697 ctx.diagnostics,
698 || rhs_syntax.stable_ptr(db).untyped(),
699 |actual_ty, expected_ty| WrongType { expected_ty, actual_ty },
700 );
701
702 Ok(Expr::LogicalOperator(ExprLogicalOperator {
703 lhs: lexpr.id,
704 op,
705 rhs: rexpr.id,
706 ty: bool_ty,
707 stable_ptr,
708 }))
709 }
710 _ => call_core_binary_op(ctx, syntax, lhs_syntax, &rhs_syntax),
711 }
712}
713
714fn call_core_binary_op(
716 ctx: &mut ComputationContext<'_>,
717 syntax: &ast::ExprBinary,
718 lhs_syntax: &ast::Expr,
719 rhs_syntax: &ast::Expr,
720) -> Maybe<Expr> {
721 let db = ctx.db;
722 let stable_ptr = syntax.stable_ptr(db);
723 let binary_op = syntax.op(db);
724
725 let (concrete_trait_function, snapshot) = match core_binary_operator(
726 db,
727 &mut ctx.resolver.inference(),
728 &binary_op,
729 stable_ptr.untyped(),
730 )? {
731 Err(err_kind) => {
732 return Err(ctx.diagnostics.report(binary_op.stable_ptr(db), err_kind));
733 }
734 Ok(res) => res,
735 };
736
737 let impl_lookup_context = ctx.resolver.impl_lookup_context();
738 let inference = &mut ctx.resolver.inference();
739 let function = inference
740 .infer_trait_function(
741 concrete_trait_function,
742 &impl_lookup_context,
743 Some(stable_ptr.untyped()),
744 )
745 .map_err(|err_set| {
746 inference.report_on_pending_error(err_set, ctx.diagnostics, stable_ptr.untyped())
747 })?;
748
749 let mut lexpr = compute_expr_semantic(ctx, lhs_syntax);
750
751 if let (Expr::Missing(_), BinaryOperator::LT(_)) = (&lexpr.expr, &binary_op) {
752 return Err(ctx
753 .diagnostics
754 .report(binary_op.stable_ptr(db), SemanticDiagnosticKind::MaybeMissingColonColon));
755 }
756
757 let mut rexpr = compute_expr_semantic(ctx, rhs_syntax);
758
759 ctx.reduce_ty(lexpr.ty()).check_not_missing(db)?;
760 ctx.reduce_ty(rexpr.ty()).check_not_missing(db)?;
761
762 if snapshot {
763 let ty = TypeLongId::Snapshot(lexpr.ty()).intern(ctx.db);
764 let expr =
765 Expr::Snapshot(ExprSnapshot { inner: lexpr.id, ty, stable_ptr: lexpr.stable_ptr() });
766 lexpr = ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) };
767 let ty = TypeLongId::Snapshot(rexpr.ty()).intern(ctx.db);
768 let expr =
769 Expr::Snapshot(ExprSnapshot { inner: rexpr.id, ty, stable_ptr: rexpr.stable_ptr() });
770 rexpr = ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) };
771 }
772
773 let sig = ctx.db.concrete_function_signature(function)?;
774 let first_param = sig.params.into_iter().next().unwrap();
775
776 expr_function_call(
777 ctx,
778 function,
779 vec![
780 NamedArg(lexpr, None, first_param.mutability),
781 NamedArg(rexpr, None, Mutability::Immutable),
782 ],
783 stable_ptr,
784 stable_ptr.into(),
785 )
786}
787
788fn compute_expr_tuple_semantic(
789 ctx: &mut ComputationContext<'_>,
790 syntax: &ast::ExprListParenthesized,
791) -> Maybe<Expr> {
792 let db = ctx.db;
793
794 let mut items: Vec<ExprId> = vec![];
795 let mut types: Vec<TypeId> = vec![];
796 let expressions_syntax = &syntax.expressions(db).elements(db);
797 for expr_syntax in expressions_syntax {
798 let expr_semantic = compute_expr_semantic(ctx, expr_syntax);
799 types.push(ctx.reduce_ty(expr_semantic.ty()));
800 items.push(expr_semantic.id);
801 }
802 Ok(Expr::Tuple(ExprTuple {
803 items,
804 ty: TypeLongId::Tuple(types).intern(db),
805 stable_ptr: syntax.stable_ptr(db).into(),
806 }))
807}
808fn compute_expr_fixed_size_array_semantic(
810 ctx: &mut ComputationContext<'_>,
811 syntax: &ast::ExprFixedSizeArray,
812) -> Maybe<Expr> {
813 let db = ctx.db;
814 let exprs = syntax.exprs(db).elements(db);
815 let size_ty = get_usize_ty(db);
816 let (items, type_id, size) = if let Some(size_const_id) =
817 extract_fixed_size_array_size(db, ctx.diagnostics, syntax, &ctx.resolver)?
818 {
819 let [expr] = exprs.as_slice() else {
821 return Err(ctx
822 .diagnostics
823 .report(syntax.stable_ptr(db), FixedSizeArrayNonSingleValue));
824 };
825 let expr_semantic = compute_expr_semantic(ctx, expr);
826 let size = size_const_id
827 .lookup_intern(db)
828 .into_int()
829 .ok_or_else(|| {
830 ctx.diagnostics.report(syntax.stable_ptr(db), FixedSizeArrayNonNumericSize)
831 })?
832 .to_usize()
833 .unwrap();
834 verify_fixed_size_array_size(db, ctx.diagnostics, &size.into(), syntax)?;
835 (
836 FixedSizeArrayItems::ValueAndSize(expr_semantic.id, size_const_id),
837 expr_semantic.ty(),
838 size_const_id,
839 )
840 } else if let Some((first_expr, tail_exprs)) = exprs.split_first() {
841 let size = ConstValue::Int((tail_exprs.len() + 1).into(), size_ty).intern(db);
842 let first_expr_semantic = compute_expr_semantic(ctx, first_expr);
843 let mut items: Vec<ExprId> = vec![first_expr_semantic.id];
844 let first_expr_ty = ctx.reduce_ty(first_expr_semantic.ty());
847 for expr_syntax in tail_exprs {
848 let expr_semantic = compute_expr_semantic(ctx, expr_syntax);
849 let inference = &mut ctx.resolver.inference();
850 inference.conform_ty_for_diag(
851 expr_semantic.ty(),
852 first_expr_ty,
853 ctx.diagnostics,
854 || expr_syntax.stable_ptr(db).untyped(),
855 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
856 )?;
857 items.push(expr_semantic.id);
858 }
859 (FixedSizeArrayItems::Items(items), first_expr_ty, size)
860 } else {
861 (
862 FixedSizeArrayItems::Items(vec![]),
863 ctx.resolver.inference().new_type_var(Some(syntax.stable_ptr(db).untyped())),
864 ConstValue::Int(0.into(), size_ty).intern(db),
865 )
866 };
867 Ok(Expr::FixedSizeArray(ExprFixedSizeArray {
868 items,
869 ty: TypeLongId::FixedSizeArray { type_id, size }.intern(db),
870 stable_ptr: syntax.stable_ptr(db).into(),
871 }))
872}
873
874fn compute_expr_function_call_semantic(
875 ctx: &mut ComputationContext<'_>,
876 syntax: &ast::ExprFunctionCall,
877) -> Maybe<Expr> {
878 let db = ctx.db;
879
880 let path = syntax.path(db);
881 let args_syntax = syntax.arguments(db).arguments(db);
882 let segments = path.elements(db);
884 let mut is_shadowed_by_variable = false;
885 if let [PathSegment::Simple(ident_segment)] = &segments[..] {
886 let identifier = ident_segment.ident(db);
887 let variable_name = identifier.text(ctx.db);
888 if let Some(var) = get_binded_expr_by_name(ctx, &variable_name, path.stable_ptr(db).into())
889 {
890 is_shadowed_by_variable = true;
891 if ctx.are_closures_in_context {
893 let info = db.core_info();
894 let fn_once_trait = info.fn_once_trt;
896 let fn_trait = info.fn_trt;
897 let self_expr = ExprAndId { expr: var.clone(), id: ctx.arenas.exprs.alloc(var) };
898 let mut closure_call_data = |call_trait| {
899 compute_method_function_call_data(
900 ctx,
901 &[call_trait],
902 "call".into(),
903 self_expr.clone(),
904 syntax.stable_ptr(db).untyped(),
905 None,
906 |ty, _, inference_errors| {
907 if call_trait == fn_once_trait {
908 Some(CallExpressionRequiresFunction { ty, inference_errors })
909 } else {
910 None
911 }
912 },
913 |_, _, _| {
914 unreachable!(
915 "There is one explicit trait, FnOnce trait. No implementations of \
916 the trait, caused by both lack of implementation or multiple \
917 implementations of the trait, are handled in \
918 NoImplementationOfTrait function."
919 )
920 },
921 )
922 };
923 let (call_function_id, _, fixed_closure, closure_mutability) =
924 closure_call_data(fn_trait).or_else(|_| closure_call_data(fn_once_trait))?;
925
926 let args_iter = args_syntax.elements(db).into_iter();
927 let mut args = vec![];
929 let mut arg_types = vec![];
930 for arg_syntax in args_iter {
931 let stable_ptr = arg_syntax.stable_ptr(db);
932 let arg = compute_named_argument_clause(ctx, arg_syntax, None);
933 if arg.2 != Mutability::Immutable {
934 return Err(ctx.diagnostics.report(stable_ptr, RefClosureArgument));
935 }
936 args.push(arg.0.id);
937 arg_types.push(arg.0.ty());
938 }
939 let args_expr = Expr::Tuple(ExprTuple {
940 items: args,
941 ty: TypeLongId::Tuple(arg_types).intern(db),
942 stable_ptr: syntax.stable_ptr(db).into(),
943 });
944 let args_expr =
945 ExprAndId { expr: args_expr.clone(), id: ctx.arenas.exprs.alloc(args_expr) };
946 let call_ptr = syntax.stable_ptr(db);
947 return expr_function_call(
948 ctx,
949 call_function_id,
950 vec![
951 NamedArg(fixed_closure, None, closure_mutability),
952 NamedArg(args_expr, None, Mutability::Immutable),
953 ],
954 call_ptr,
955 call_ptr.into(),
956 );
957 }
958 }
959 }
960
961 let item = ctx.resolver.resolve_concrete_path_ex(
962 ctx.diagnostics,
963 &path,
964 NotFoundItemType::Function,
965 ResolutionContext::Statement(&mut ctx.environment),
966 )?;
967
968 match item {
969 ResolvedConcreteItem::Variant(variant) => {
970 let concrete_enum_type =
971 TypeLongId::Concrete(ConcreteTypeId::Enum(variant.concrete_enum_id)).intern(db);
972 if concrete_enum_type.is_phantom(db) {
973 ctx.diagnostics.report(syntax.stable_ptr(db), CannotCreateInstancesOfPhantomTypes);
974 }
975
976 let named_args: Vec<_> = args_syntax
979 .elements(db)
980 .into_iter()
981 .map(|arg_syntax| compute_named_argument_clause(ctx, arg_syntax, None))
982 .collect();
983 if named_args.len() != 1 {
984 return Err(ctx.diagnostics.report(
985 syntax.stable_ptr(db),
986 WrongNumberOfArguments { expected: 1, actual: named_args.len() },
987 ));
988 }
989 let NamedArg(arg, name_terminal, mutability) = named_args[0].clone();
990 if let Some(name_terminal) = name_terminal {
991 ctx.diagnostics.report(name_terminal.stable_ptr(db), NamedArgumentsAreNotSupported);
992 }
993 if mutability != Mutability::Immutable {
994 return Err(ctx
995 .diagnostics
996 .report(args_syntax.stable_ptr(db), VariantCtorNotImmutable));
997 }
998 let inference = &mut ctx.resolver.inference();
999 inference.conform_ty_for_diag(
1000 arg.ty(),
1001 variant.ty,
1002 ctx.diagnostics,
1003 || args_syntax.stable_ptr(db).untyped(),
1004 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
1005 )?;
1006 Ok(semantic::Expr::EnumVariantCtor(semantic::ExprEnumVariantCtor {
1007 variant,
1008 value_expr: arg.id,
1009 ty: concrete_enum_type,
1010 stable_ptr: syntax.stable_ptr(db).into(),
1011 }))
1012 }
1013 ResolvedConcreteItem::Function(function) => {
1014 if is_shadowed_by_variable {
1015 return Err(ctx.diagnostics.report(
1016 path.stable_ptr(db),
1017 CallingShadowedFunction {
1018 shadowed_function_name: path.elements(db).first().unwrap().identifier(db),
1019 },
1020 ));
1021 }
1022 let mut args_iter = args_syntax.elements(db).into_iter();
1027 let mut named_args = vec![];
1029 let closure_params = concrete_function_closure_params(db, function)?;
1030 for ty in function_parameter_types(ctx, function)? {
1031 let Some(arg_syntax) = args_iter.next() else {
1032 continue;
1033 };
1034 named_args.push(compute_named_argument_clause(
1035 ctx,
1036 arg_syntax,
1037 closure_params.get(&ty).copied(),
1038 ));
1039 }
1040
1041 if let Some(arg_syntax) = args_iter.next() {
1043 named_args.push(compute_named_argument_clause(ctx, arg_syntax, None));
1044 }
1045 let call_ptr = syntax.stable_ptr(db);
1046 expr_function_call(ctx, function, named_args, call_ptr, call_ptr.into())
1047 }
1048 _ => Err(ctx.diagnostics.report(
1049 path.stable_ptr(db),
1050 UnexpectedElement { expected: vec![ElementKind::Function], actual: (&item).into() },
1051 )),
1052 }
1053}
1054
1055pub fn compute_named_argument_clause(
1059 ctx: &mut ComputationContext<'_>,
1060 arg_syntax: ast::Arg,
1061 closure_params_tuple_ty: Option<TypeId>,
1062) -> NamedArg {
1063 let db = ctx.db;
1064
1065 let mutability =
1066 compute_mutability(ctx.diagnostics, db, &arg_syntax.modifiers(db).elements(db));
1067
1068 let arg_clause = arg_syntax.arg_clause(db);
1069 let (expr, arg_name_identifier) = match arg_clause {
1070 ast::ArgClause::Unnamed(arg_unnamed) => (
1071 handle_possible_closure_expr(ctx, &arg_unnamed.value(db), closure_params_tuple_ty),
1072 None,
1073 ),
1074 ast::ArgClause::Named(arg_named) => (
1075 handle_possible_closure_expr(ctx, &arg_named.value(db), closure_params_tuple_ty),
1076 Some(arg_named.name(db)),
1077 ),
1078 ast::ArgClause::FieldInitShorthand(arg_field_init_shorthand) => {
1079 let name_expr = arg_field_init_shorthand.name(db);
1080 let stable_ptr: ast::ExprPtr = name_expr.stable_ptr(db).into();
1081 let arg_name_identifier = name_expr.name(db);
1082 let maybe_expr = resolve_variable_by_name(ctx, &arg_name_identifier, stable_ptr);
1083 let expr = wrap_maybe_with_missing(ctx, maybe_expr, stable_ptr);
1084 let expr = ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) };
1085 (expr, Some(arg_name_identifier))
1086 }
1087 };
1088 NamedArg(expr, arg_name_identifier, mutability)
1089}
1090
1091fn handle_possible_closure_expr(
1096 ctx: &mut ComputationContext<'_>,
1097 expr: &ast::Expr,
1098 closure_param_types: Option<TypeId>,
1099) -> ExprAndId {
1100 if let ast::Expr::Closure(expr_closure) = expr {
1101 let expr = compute_expr_closure_semantic(ctx, expr_closure, closure_param_types);
1102 let expr = wrap_maybe_with_missing(ctx, expr, expr_closure.stable_ptr(ctx.db).into());
1103 let id = ctx.arenas.exprs.alloc(expr.clone());
1104 ExprAndId { expr, id }
1105 } else {
1106 compute_expr_semantic(ctx, expr)
1107 }
1108}
1109
1110pub fn compute_root_expr(
1111 ctx: &mut ComputationContext<'_>,
1112 syntax: &ast::ExprBlock,
1113 return_type: TypeId,
1114) -> Maybe<ExprId> {
1115 let inference = &mut ctx.resolver.data.inference_data.inference(ctx.db);
1117 for param in &ctx.resolver.data.generic_params {
1118 let Ok(GenericParam::Impl(imp)) = ctx.db.generic_param_semantic(*param) else {
1119 continue;
1120 };
1121 let Ok(concrete_trait_id) = imp.concrete_trait else {
1122 continue;
1123 };
1124 if crate::corelib::fn_traits(ctx.db).contains(&concrete_trait_id.trait_id(ctx.db)) {
1125 ctx.are_closures_in_context = true;
1126 }
1127 }
1128 let constrains =
1129 ctx.db.generic_params_type_constraints(ctx.resolver.data.generic_params.clone());
1130 inference.conform_generic_params_type_constraints(&constrains);
1131
1132 let return_type = ctx.reduce_ty(return_type);
1133 let res = compute_expr_block_semantic(ctx, syntax)?;
1134 let res_ty = ctx.reduce_ty(res.ty());
1135 let res = ctx.arenas.exprs.alloc(res);
1136 let inference = &mut ctx.resolver.inference();
1137 let db = ctx.db;
1138 let _ = inference.conform_ty_for_diag(
1139 res_ty,
1140 return_type,
1141 ctx.diagnostics,
1142 || {
1143 ctx.signature
1144 .map(|s| match s.stable_ptr.lookup(db).ret_ty(db) {
1145 OptionReturnTypeClause::Empty(_) => syntax.stable_ptr(db).untyped(),
1146 OptionReturnTypeClause::ReturnTypeClause(return_type_clause) => {
1147 return_type_clause.ty(db).stable_ptr(db).untyped()
1148 }
1149 })
1150 .unwrap_or_else(|| syntax.stable_ptr(db).untyped())
1151 },
1152 |actual_ty, expected_ty| WrongReturnType { expected_ty, actual_ty },
1153 );
1154
1155 inference.finalize(ctx.diagnostics, syntax.stable_ptr(db).untyped());
1157
1158 ctx.apply_inference_rewriter();
1159 if ctx.signature.map(|s| s.is_const) == Some(true) {
1160 validate_const_expr(ctx, res);
1161 }
1162 Ok(res)
1163}
1164
1165pub fn compute_expr_block_semantic(
1167 ctx: &mut ComputationContext<'_>,
1168 syntax: &ast::ExprBlock,
1169) -> Maybe<Expr> {
1170 let db = ctx.db;
1171
1172 ctx.run_in_subscope(|new_ctx| {
1173 let mut statements = syntax.statements(db).elements(db);
1174 let tail = get_tail_expression(db, statements.as_slice());
1177 if tail.is_some() {
1178 statements.pop();
1179 }
1180
1181 let statements_semantic: Vec<_> = statements
1183 .into_iter()
1184 .filter_map(|statement_syntax| {
1185 compute_statement_semantic(new_ctx, statement_syntax).to_option()
1186 })
1187 .collect();
1188
1189 let tail_semantic_expr = tail.map(|tail_expr| compute_expr_semantic(new_ctx, &tail_expr));
1191 let ty = if let Some(t) = &tail_semantic_expr {
1192 t.ty()
1193 } else if let Some(statement) = statements_semantic.last() {
1194 if let Statement::Return(_) | Statement::Break(_) =
1195 &new_ctx.arenas.statements[*statement]
1196 {
1197 never_ty(new_ctx.db)
1198 } else {
1199 unit_ty(db)
1200 }
1201 } else {
1202 unit_ty(db)
1203 };
1204 Ok(Expr::Block(ExprBlock {
1205 statements: statements_semantic,
1206 tail: tail_semantic_expr.map(|expr| expr.id),
1207 ty,
1208 stable_ptr: syntax.stable_ptr(db).into(),
1209 }))
1210 })
1211}
1212
1213#[derive(Debug, Clone)]
1215struct FlowMergeTypeHelper {
1216 multi_arm_expr_kind: MultiArmExprKind,
1217 never_type: TypeId,
1218 final_type: Option<TypeId>,
1219 had_merge_error: bool,
1221}
1222impl FlowMergeTypeHelper {
1223 fn new(db: &dyn SemanticGroup, multi_arm_expr_kind: MultiArmExprKind) -> Self {
1224 Self {
1225 multi_arm_expr_kind,
1226 never_type: never_ty(db),
1227 final_type: None,
1228 had_merge_error: false,
1229 }
1230 }
1231
1232 fn try_merge_types(
1236 &mut self,
1237 db: &dyn SemanticGroup,
1238 diagnostics: &mut SemanticDiagnostics,
1239 inference: &mut Inference<'_>,
1240 ty: TypeId,
1241 stable_ptr: SyntaxStablePtrId,
1242 ) -> bool {
1243 if self.had_merge_error {
1244 return false;
1245 }
1246
1247 if ty != self.never_type && !ty.is_missing(db) {
1248 if let Some(pending) = &self.final_type {
1249 if let Err(err_set) = inference.conform_ty(ty, *pending) {
1250 let diag_added = diagnostics.report(
1251 stable_ptr,
1252 IncompatibleArms {
1253 multi_arm_expr_kind: self.multi_arm_expr_kind,
1254 pending_ty: *pending,
1255 different_ty: ty,
1256 },
1257 );
1258 inference.consume_reported_error(err_set, diag_added);
1259 self.had_merge_error = true;
1260 return false;
1261 }
1262 } else {
1263 self.final_type = Some(ty);
1264 }
1265 }
1266 true
1267 }
1268
1269 fn get_final_type(self) -> TypeId {
1271 self.final_type.unwrap_or(self.never_type)
1272 }
1273}
1274
1275fn compute_arm_semantic(
1277 ctx: &mut ComputationContext<'_>,
1278 expr: &Expr,
1279 arm_expr_syntax: ast::Expr,
1280 patterns_syntax: &PatternListOr,
1281 is_while_let_arm: bool,
1283) -> (Vec<PatternAndId>, ExprAndId) {
1284 let db = ctx.db;
1285 ctx.run_in_subscope(|new_ctx| {
1286 let mut arm_patterns_variables: UnorderedHashMap<SmolStr, LocalVariable> =
1290 UnorderedHashMap::default();
1291 let patterns: Vec<_> = patterns_syntax
1292 .elements(db)
1293 .iter()
1294 .map(|pattern_syntax| {
1295 let pattern: PatternAndId = compute_pattern_semantic(
1296 new_ctx,
1297 pattern_syntax,
1298 expr.ty(),
1299 &mut arm_patterns_variables,
1300 );
1301 let variables = pattern.variables(&new_ctx.arenas.patterns);
1302 for variable in variables {
1303 match arm_patterns_variables.entry(variable.name.clone()) {
1304 std::collections::hash_map::Entry::Occupied(entry) => {
1305 let get_location = || variable.stable_ptr.lookup(db).stable_ptr(db);
1306 let var = entry.get();
1307
1308 let expected_ty = new_ctx.reduce_ty(var.ty);
1309 let actual_ty = new_ctx.reduce_ty(variable.var.ty);
1310
1311 let mut has_inference_error = false;
1312 if !variable.var.ty.is_missing(new_ctx.db) {
1313 let inference = &mut new_ctx.resolver.inference();
1314 if inference
1315 .conform_ty_for_diag(
1316 actual_ty,
1317 expected_ty,
1318 new_ctx.diagnostics,
1319 || get_location().untyped(),
1320 |actual_ty, expected_ty| WrongType {
1321 expected_ty,
1322 actual_ty,
1323 },
1324 )
1325 .is_err()
1326 {
1327 has_inference_error = true;
1328 }
1329 };
1330 if !has_inference_error && var.is_mut != variable.var.is_mut {
1331 new_ctx.diagnostics.report(get_location(), InconsistentBinding);
1332 }
1333 }
1334 std::collections::hash_map::Entry::Vacant(entry) => {
1335 entry.insert(variable.var.clone());
1336 }
1337 }
1338 }
1339 pattern
1340 })
1341 .collect();
1342
1343 for (pattern_syntax, pattern) in patterns_syntax.elements(db).iter().zip(patterns.iter()) {
1344 let variables = pattern.variables(&new_ctx.arenas.patterns);
1345
1346 if variables.len() != arm_patterns_variables.len() {
1347 new_ctx.diagnostics.report(pattern_syntax.stable_ptr(db), MissingVariableInPattern);
1348 }
1349
1350 for v in variables {
1351 let var_def = Binding::LocalVar(v.var.clone());
1352 new_ctx.environment.variables.insert(v.name.clone(), var_def.clone());
1355 new_ctx.semantic_defs.insert(var_def.id(), var_def);
1356 }
1357 }
1358 let arm_expr = if is_while_let_arm {
1359 let ast::Expr::Block(arm_expr_syntax) = arm_expr_syntax else {
1360 unreachable!("Expected a block expression for a loop arm.");
1361 };
1362
1363 let (id, _) =
1364 compute_loop_body_semantic(new_ctx, arm_expr_syntax, InnerContextKind::While);
1365 let expr = new_ctx.arenas.exprs[id].clone();
1366 ExprAndId { expr, id }
1367 } else {
1368 compute_expr_semantic(new_ctx, &arm_expr_syntax)
1369 };
1370 (patterns, arm_expr)
1371 })
1372}
1373
1374fn compute_expr_match_semantic(
1376 ctx: &mut ComputationContext<'_>,
1377 syntax: &ast::ExprMatch,
1378) -> Maybe<Expr> {
1379 let db = ctx.db;
1381
1382 let syntax_arms = syntax.arms(db).elements(db);
1383 let expr = compute_expr_semantic(ctx, &syntax.expr(db));
1384 let patterns_and_exprs: Vec<_> = syntax_arms
1387 .iter()
1388 .map(|syntax_arm| {
1389 compute_arm_semantic(
1390 ctx,
1391 &expr,
1392 syntax_arm.expression(db),
1393 &syntax_arm.patterns(db),
1394 false,
1395 )
1396 })
1397 .collect();
1398 let mut helper = FlowMergeTypeHelper::new(ctx.db, MultiArmExprKind::Match);
1400 for (_, expr) in &patterns_and_exprs {
1401 let expr_ty = ctx.reduce_ty(expr.ty());
1402 if !helper.try_merge_types(
1403 ctx.db,
1404 ctx.diagnostics,
1405 &mut ctx.resolver.inference(),
1406 expr_ty,
1407 expr.stable_ptr().untyped(),
1408 ) {
1409 break;
1410 };
1411 }
1412 let semantic_arms = patterns_and_exprs
1414 .into_iter()
1415 .map(|(patterns, arm_expr)| MatchArm {
1416 patterns: patterns.iter().map(|pattern| pattern.id).collect(),
1417 expression: arm_expr.id,
1418 })
1419 .collect();
1420 Ok(Expr::Match(ExprMatch {
1421 matched_expr: expr.id,
1422 arms: semantic_arms,
1423 ty: helper.get_final_type(),
1424 stable_ptr: syntax.stable_ptr(db).into(),
1425 }))
1426}
1427
1428fn compute_expr_if_semantic(ctx: &mut ComputationContext<'_>, syntax: &ast::ExprIf) -> Maybe<Expr> {
1430 let db = ctx.db;
1431 let (condition, if_block) = match &syntax.condition(db) {
1432 ast::Condition::Let(condition) => {
1433 let expr = compute_expr_semantic(ctx, &condition.expr(db));
1434 if let Expr::LogicalOperator(_) = expr.expr {
1435 ctx.diagnostics
1436 .report(condition.expr(db).stable_ptr(db), LogicalOperatorNotAllowedInIfLet);
1437 }
1438
1439 let (patterns, if_block) = compute_arm_semantic(
1440 ctx,
1441 &expr,
1442 ast::Expr::Block(syntax.if_block(db)),
1443 &condition.patterns(db),
1444 false,
1445 );
1446 (Condition::Let(expr.id, patterns.iter().map(|pattern| pattern.id).collect()), if_block)
1447 }
1448 ast::Condition::Expr(expr) => {
1449 let if_block = compute_expr_block_semantic(ctx, &syntax.if_block(db))?;
1450 (
1451 Condition::BoolExpr(compute_bool_condition_semantic(ctx, &expr.expr(db)).id),
1452 ExprAndId { expr: if_block.clone(), id: ctx.arenas.exprs.alloc(if_block) },
1453 )
1454 }
1455 };
1456
1457 let (else_block_opt, else_block_ty) = match syntax.else_clause(db) {
1458 ast::OptionElseClause::Empty(_) => (None, unit_ty(ctx.db)),
1459 ast::OptionElseClause::ElseClause(else_clause) => match else_clause.else_block_or_if(db) {
1460 BlockOrIf::Block(block) => {
1461 let else_block = compute_expr_block_semantic(ctx, &block)?;
1462 (Some(else_block.clone()), else_block.ty())
1463 }
1464 BlockOrIf::If(expr_if) => {
1465 let else_if = compute_expr_if_semantic(ctx, &expr_if)?;
1466 (Some(else_if.clone()), else_if.ty())
1467 }
1468 },
1469 };
1470
1471 let mut helper = FlowMergeTypeHelper::new(ctx.db, MultiArmExprKind::If);
1472 let if_block_ty = ctx.reduce_ty(if_block.ty());
1473 let else_block_ty = ctx.reduce_ty(else_block_ty);
1474 let inference = &mut ctx.resolver.inference();
1475 let _ = helper.try_merge_types(
1476 ctx.db,
1477 ctx.diagnostics,
1478 inference,
1479 if_block_ty,
1480 syntax.stable_ptr(db).untyped(),
1481 ) && helper.try_merge_types(
1482 ctx.db,
1483 ctx.diagnostics,
1484 inference,
1485 else_block_ty,
1486 syntax.stable_ptr(db).untyped(),
1487 );
1488 Ok(Expr::If(ExprIf {
1489 condition,
1490 if_block: if_block.id,
1491 else_block: else_block_opt.map(|else_block| ctx.arenas.exprs.alloc(else_block)),
1492 ty: helper.get_final_type(),
1493 stable_ptr: syntax.stable_ptr(db).into(),
1494 }))
1495}
1496
1497fn compute_expr_loop_semantic(
1499 ctx: &mut ComputationContext<'_>,
1500 syntax: &ast::ExprLoop,
1501) -> Maybe<Expr> {
1502 let db = ctx.db;
1503
1504 let (body, inner_ctx) = compute_loop_body_semantic(
1505 ctx,
1506 syntax.body(db),
1507 InnerContextKind::Loop {
1508 type_merger: FlowMergeTypeHelper::new(db, MultiArmExprKind::Loop),
1509 },
1510 );
1511
1512 let InnerContext { kind: InnerContextKind::Loop { type_merger, .. }, .. } = inner_ctx else {
1513 unreachable!("Expected loop context");
1514 };
1515 Ok(Expr::Loop(ExprLoop {
1516 body,
1517 ty: type_merger.get_final_type(),
1518 stable_ptr: syntax.stable_ptr(db).into(),
1519 }))
1520}
1521
1522fn compute_expr_while_semantic(
1524 ctx: &mut ComputationContext<'_>,
1525 syntax: &ast::ExprWhile,
1526) -> Maybe<Expr> {
1527 let db = ctx.db;
1528
1529 let (condition, body) = match &syntax.condition(db) {
1530 ast::Condition::Let(condition) => {
1531 let expr = compute_expr_semantic(ctx, &condition.expr(db));
1532 if let Expr::LogicalOperator(_) = expr.expr {
1533 ctx.diagnostics
1534 .report(condition.expr(db).stable_ptr(db), LogicalOperatorNotAllowedInWhileLet);
1535 }
1536
1537 let (patterns, body) = compute_arm_semantic(
1538 ctx,
1539 &expr,
1540 ast::Expr::Block(syntax.body(db)),
1541 &condition.patterns(db),
1542 true,
1543 );
1544 (Condition::Let(expr.id, patterns.iter().map(|pattern| pattern.id).collect()), body.id)
1545 }
1546 ast::Condition::Expr(expr) => {
1547 let (body, _inner_ctx) =
1548 compute_loop_body_semantic(ctx, syntax.body(db), InnerContextKind::While);
1549 (Condition::BoolExpr(compute_bool_condition_semantic(ctx, &expr.expr(db)).id), body)
1550 }
1551 };
1552
1553 Ok(Expr::While(ExprWhile {
1554 condition,
1555 body,
1556 ty: unit_ty(ctx.db),
1557 stable_ptr: syntax.stable_ptr(db).into(),
1558 }))
1559}
1560
1561fn compute_expr_for_semantic(
1563 ctx: &mut ComputationContext<'_>,
1564 syntax: &ast::ExprFor,
1565) -> Maybe<Expr> {
1566 let db = ctx.db;
1567 let expr_ptr = syntax.expr(db).stable_ptr(db);
1568
1569 let expr = compute_expr_semantic(ctx, &syntax.expr(db));
1570 let expr_id = expr.id;
1571
1572 let into_iterator_trait = ctx.db.core_info().into_iterator_trt;
1573
1574 let (into_iterator_function_id, _, fixed_into_iter_var, into_iter_mutability) =
1575 compute_method_function_call_data(
1576 ctx,
1577 &[into_iterator_trait],
1578 "into_iter".into(),
1579 expr,
1580 expr_ptr.into(),
1581 None,
1582 |ty, _, inference_errors| {
1583 Some(NoImplementationOfTrait {
1584 ty,
1585 inference_errors,
1586 trait_name: "IntoIterator".into(),
1587 })
1588 },
1589 |_, _, _| {
1590 unreachable!(
1591 "There is one explicit trait, IntoIterator trait. No implementations of the \
1592 trait, caused by both lack of implementation or multiple implementations of \
1593 the trait, are handled in NoImplementationOfTrait function."
1594 )
1595 },
1596 )?;
1597 let into_iter_call = expr_function_call(
1598 ctx,
1599 into_iterator_function_id,
1600 vec![NamedArg(fixed_into_iter_var, None, into_iter_mutability)],
1601 expr_ptr,
1602 expr_ptr,
1603 )?;
1604
1605 let into_iter_variable =
1606 LocalVarLongId(ctx.resolver.module_file_id, syntax.identifier(db).stable_ptr(db))
1607 .intern(ctx.db);
1608
1609 let into_iter_expr = Expr::Var(ExprVar {
1610 var: VarId::Local(into_iter_variable),
1611 ty: into_iter_call.ty(),
1612 stable_ptr: into_iter_call.stable_ptr(),
1613 });
1614 let into_iter_member_path = ExprVarMemberPath::Var(ExprVar {
1615 var: VarId::Local(into_iter_variable),
1616 ty: into_iter_call.ty(),
1617 stable_ptr: into_iter_call.stable_ptr(),
1618 });
1619 let into_iter_expr_id = ctx.arenas.exprs.alloc(into_iter_expr.clone());
1620
1621 let iterator_trait = ctx.db.core_info().iterator_trt;
1622
1623 let (next_function_id, _, _, _) = compute_method_function_call_data(
1624 ctx,
1625 &[iterator_trait],
1626 "next".into(),
1627 ExprAndId { expr: into_iter_expr, id: into_iter_expr_id },
1628 expr_ptr.into(),
1629 None,
1630 |ty, _, inference_errors| {
1631 Some(NoImplementationOfTrait { ty, inference_errors, trait_name: "Iterator".into() })
1632 },
1633 |_, _, _| {
1634 unreachable!(
1635 "There is one explicit trait, Iterator trait. No implementations of the trait, \
1636 caused by both lack of implementation or multiple implementations of the trait, \
1637 are handled in NoImplementationOfTrait function."
1638 )
1639 },
1640 )?;
1641
1642 let next_success_variant =
1643 match db.concrete_function_signature(next_function_id)?.return_type.lookup_intern(db) {
1644 TypeLongId::Concrete(semantic::ConcreteTypeId::Enum(enm)) => {
1645 assert_eq!(enm.enum_id(db).name(db), "Option");
1646 db.concrete_enum_variants(enm).unwrap().into_iter().next().unwrap()
1647 }
1648 _ => unreachable!(),
1649 };
1650 let (body_id, pattern) = ctx.run_in_subscope(|new_ctx| {
1651 let inner_pattern = compute_pattern_semantic(
1652 new_ctx,
1653 &syntax.pattern(db),
1654 next_success_variant.ty,
1655 &mut UnorderedHashMap::default(),
1656 );
1657 let variables = inner_pattern.variables(&new_ctx.arenas.patterns);
1658 for v in variables {
1659 let var_def = Binding::LocalVar(v.var.clone());
1660 new_ctx.environment.variables.insert(v.name.clone(), var_def.clone());
1661 new_ctx.semantic_defs.insert(var_def.id(), var_def);
1662 }
1663 let (body, _inner_ctx) =
1664 compute_loop_body_semantic(new_ctx, syntax.body(db), InnerContextKind::For);
1665 (body, new_ctx.arenas.patterns.alloc(inner_pattern.pattern))
1666 });
1667 Ok(Expr::For(ExprFor {
1668 into_iter: into_iterator_function_id,
1669 into_iter_member_path,
1670 next_function_id,
1671 expr_id,
1672 pattern,
1673 body: body_id,
1674 ty: unit_ty(ctx.db),
1675 stable_ptr: syntax.stable_ptr(db).into(),
1676 }))
1677}
1678
1679fn compute_loop_body_semantic(
1681 ctx: &mut ComputationContext<'_>,
1682 syntax: ast::ExprBlock,
1683 kind: InnerContextKind,
1684) -> (ExprId, InnerContext) {
1685 let db = ctx.db;
1686
1687 ctx.run_in_subscope(|new_ctx| {
1688 let return_type = new_ctx.get_return_type().unwrap();
1689 let old_inner_ctx = new_ctx.inner_ctx.replace(InnerContext { return_type, kind });
1690
1691 let mut statements = syntax.statements(db).elements(db);
1692 let tail = get_tail_expression(db, statements.as_slice());
1694 if tail.is_some() {
1695 statements.pop();
1696 }
1697
1698 let statements_semantic: Vec<_> = statements
1700 .into_iter()
1701 .filter_map(|statement_syntax| {
1702 compute_statement_semantic(new_ctx, statement_syntax).to_option()
1703 })
1704 .collect();
1705 let tail = tail.map(|tail| compute_expr_semantic(new_ctx, &tail));
1706 if let Some(tail) = &tail {
1707 if !tail.ty().is_missing(db) && !tail.ty().is_unit(db) && tail.ty() != never_ty(db) {
1708 new_ctx.diagnostics.report(tail.deref(), TailExpressionNotAllowedInLoop);
1709 }
1710 }
1711
1712 let inner_ctx = std::mem::replace(&mut new_ctx.inner_ctx, old_inner_ctx).unwrap();
1713 let body = new_ctx.arenas.exprs.alloc(Expr::Block(ExprBlock {
1714 statements: statements_semantic,
1715 tail: tail.map(|tail| tail.id),
1716 ty: unit_ty(db),
1717 stable_ptr: syntax.stable_ptr(db).into(),
1718 }));
1719
1720 (body, inner_ctx)
1721 })
1722}
1723
1724fn compute_expr_closure_semantic(
1726 ctx: &mut ComputationContext<'_>,
1727 syntax: &ast::ExprClosure,
1728 params_tuple_ty: Option<TypeId>,
1729) -> Maybe<Expr> {
1730 ctx.are_closures_in_context = true;
1731 let db = ctx.db;
1732 let (params, ret_ty, body) = ctx.run_in_subscope(|new_ctx| {
1733 let params = if let ClosureParamWrapper::NAry(params) = syntax.wrapper(db) {
1734 function_signature_params(
1735 new_ctx.diagnostics,
1736 new_ctx.db,
1737 &mut new_ctx.resolver,
1738 ¶ms.params(db).elements(db),
1739 None,
1740 &mut new_ctx.environment,
1741 )
1742 .into_iter()
1743 .collect()
1744 } else {
1745 vec![]
1746 };
1747 let closure_type =
1748 TypeLongId::Tuple(params.iter().map(|param| param.ty).collect()).intern(new_ctx.db);
1749 if let Some(param_types) = params_tuple_ty {
1750 if let Err(err_set) = new_ctx.resolver.inference().conform_ty(closure_type, param_types)
1751 {
1752 new_ctx.resolver.inference().report_on_pending_error(
1753 err_set,
1754 new_ctx.diagnostics,
1755 syntax.stable_ptr(db).untyped(),
1756 );
1757 }
1758 }
1759
1760 params.iter().filter(|param| param.mutability == Mutability::Reference).for_each(|param| {
1761 new_ctx.diagnostics.report(param.stable_ptr(ctx.db), RefClosureParam);
1762 });
1763
1764 new_ctx
1765 .semantic_defs
1766 .extend(new_ctx.environment.variables.iter().map(|(_, var)| (var.id(), var.clone())));
1767
1768 let return_type = match syntax.ret_ty(db) {
1769 OptionReturnTypeClause::ReturnTypeClause(ty_syntax) => resolve_type_ex(
1770 new_ctx.db,
1771 new_ctx.diagnostics,
1772 &mut new_ctx.resolver,
1773 &ty_syntax.ty(db),
1774 ResolutionContext::Statement(&mut new_ctx.environment),
1775 ),
1776 OptionReturnTypeClause::Empty(missing) => {
1777 new_ctx.resolver.inference().new_type_var(Some(missing.stable_ptr(db).untyped()))
1778 }
1779 };
1780
1781 let old_inner_ctx = new_ctx
1782 .inner_ctx
1783 .replace(InnerContext { return_type, kind: InnerContextKind::Closure });
1784 let body = match syntax.expr(db) {
1785 ast::Expr::Block(syntax) => compute_closure_body_semantic(new_ctx, syntax),
1786 _ => compute_expr_semantic(new_ctx, &syntax.expr(db)).id,
1787 };
1788 std::mem::replace(&mut new_ctx.inner_ctx, old_inner_ctx).unwrap();
1789 let mut inference = new_ctx.resolver.inference();
1790 let _ = inference.conform_ty_for_diag(
1791 new_ctx.arenas.exprs[body].ty(),
1792 return_type,
1793 new_ctx.diagnostics,
1794 || match syntax.ret_ty(ctx.db).stable_ptr(db).lookup(ctx.db) {
1795 OptionReturnTypeClause::Empty(_) => syntax.expr(db).stable_ptr(db).untyped(),
1796 OptionReturnTypeClause::ReturnTypeClause(return_type_clause) => {
1797 return_type_clause.ty(ctx.db).stable_ptr(db).untyped()
1798 }
1799 },
1800 |actual_ty, expected_ty| WrongReturnType { expected_ty, actual_ty },
1801 );
1802 (params, return_type, body)
1803 });
1804 let parent_function = match ctx.function_id {
1805 ContextFunction::Global => {
1806 Maybe::Err(ctx.diagnostics.report(syntax.stable_ptr(db), ClosureInGlobalScope))
1807 }
1808 ContextFunction::Function(function_id) => function_id,
1809 };
1810 if matches!(ctx.function_id, ContextFunction::Global) {
1811 ctx.diagnostics.report(syntax.stable_ptr(db), ClosureInGlobalScope);
1812 }
1813
1814 let mut usages = Usages { usages: Default::default() };
1815 let usage = usages.handle_closure(&ctx.arenas, ¶ms, body);
1816 let mut reported = UnorderedHashSet::<_>::default();
1817 for (captured_var, expr) in
1819 chain!(usage.usage.iter(), usage.snap_usage.iter(), usage.changes.iter())
1820 {
1821 let Some(var) = ctx.semantic_defs.get(&captured_var.base_var()) else {
1822 continue;
1824 };
1825
1826 if var.is_mut() && reported.insert(expr.stable_ptr()) {
1827 ctx.diagnostics.report(expr.stable_ptr(), MutableCapturedVariable);
1828 }
1829 }
1830
1831 let captured_types = chain!(
1832 chain!(usage.usage.values(), usage.changes.values()).map(|item| item.ty()),
1833 usage.snap_usage.values().map(|item| wrap_in_snapshots(ctx.db, item.ty(), 1)),
1834 )
1835 .collect_vec();
1836
1837 let ty = TypeLongId::Closure(ClosureTypeLongId {
1838 param_tys: params.iter().map(|param| param.ty).collect(),
1839 ret_ty,
1840 captured_types,
1841 parent_function,
1842 wrapper_location: StableLocation::new(syntax.wrapper(db).stable_ptr(db).into()),
1843 })
1844 .intern(ctx.db);
1845
1846 Ok(Expr::ExprClosure(ExprClosure {
1847 body,
1848 params,
1849 stable_ptr: syntax.stable_ptr(db).into(),
1850 ty,
1851 }))
1852}
1853
1854fn compute_closure_body_semantic(
1856 ctx: &mut ComputationContext<'_>,
1857 syntax: ast::ExprBlock,
1858) -> ExprId {
1859 let db = ctx.db;
1860
1861 let mut statements = syntax.statements(db).elements(db);
1862 let tail = get_tail_expression(db, statements.as_slice());
1864 if tail.is_some() {
1865 statements.pop();
1866 }
1867
1868 let statements_semantic: Vec<_> = statements
1870 .into_iter()
1871 .filter_map(|statement_syntax| {
1872 compute_statement_semantic(ctx, statement_syntax).to_option()
1873 })
1874 .collect();
1875 let tail_semantic_expr = tail.map(|tail_expr| compute_expr_semantic(ctx, &tail_expr));
1877 let ty = if let Some(t) = &tail_semantic_expr {
1878 t.ty()
1879 } else if let Some(statement) = statements_semantic.last() {
1880 if let Statement::Return(_) | Statement::Break(_) = &ctx.arenas.statements[*statement] {
1881 never_ty(ctx.db)
1882 } else {
1883 unit_ty(ctx.db)
1884 }
1885 } else {
1886 unit_ty(ctx.db)
1887 };
1888 ctx.arenas.exprs.alloc(Expr::Block(ExprBlock {
1889 statements: statements_semantic,
1890 tail: tail_semantic_expr.map(|expr| expr.id),
1891 ty,
1892 stable_ptr: syntax.stable_ptr(db).into(),
1893 }))
1894}
1895
1896fn compute_expr_error_propagate_semantic(
1898 ctx: &mut ComputationContext<'_>,
1899 syntax: &ast::ExprErrorPropagate,
1900) -> Maybe<Expr> {
1901 let db = ctx.db;
1902
1903 let return_type = ctx.get_return_type().ok_or_else(|| {
1904 ctx.diagnostics.report(
1905 syntax.stable_ptr(db),
1906 UnsupportedOutsideOfFunction(UnsupportedOutsideOfFunctionFeatureName::ErrorPropagate),
1907 )
1908 })?;
1909
1910 let func_err_prop_ty = unwrap_error_propagation_type(ctx.db, return_type).ok_or_else(|| {
1911 ctx.diagnostics.report(syntax.stable_ptr(db), ReturnTypeNotErrorPropagateType)
1912 })?;
1913
1914 let inner_expr = match &func_err_prop_ty {
1916 crate::corelib::ErrorPropagationType::Option { .. } => {
1917 compute_expr_semantic(ctx, &syntax.expr(db))
1918 }
1919 crate::corelib::ErrorPropagationType::Result { .. } => {
1920 compute_expr_semantic(ctx, &syntax.expr(db))
1921 }
1922 };
1923 let func_err_variant = func_err_prop_ty.err_variant();
1924
1925 ctx.resolver.inference().solve().ok();
1927 let inner_expr_ty = ctx.reduce_ty(inner_expr.ty());
1928 inner_expr_ty.check_not_missing(ctx.db)?;
1929 let inner_expr_err_prop_ty =
1930 unwrap_error_propagation_type(ctx.db, inner_expr_ty).ok_or_else(|| {
1931 ctx.diagnostics
1932 .report(syntax.stable_ptr(db), ErrorPropagateOnNonErrorType(inner_expr_ty))
1933 })?;
1934 let inner_expr_err_variant = inner_expr_err_prop_ty.err_variant();
1935
1936 let conformed_err_variant_ty =
1937 ctx.resolver.inference().conform_ty(func_err_variant.ty, inner_expr_err_variant.ty);
1938 let err_variant_ty = match conformed_err_variant_ty {
1941 Ok(ty) => ty,
1942 Err(err_set) => {
1943 ctx.resolver.inference().consume_error_without_reporting(err_set);
1944 inner_expr_err_variant.ty
1945 }
1946 };
1947 if func_err_variant.ty != err_variant_ty
1949 || func_err_variant.concrete_enum_id.enum_id(ctx.db)
1950 != inner_expr_err_variant.concrete_enum_id.enum_id(ctx.db)
1951 {
1952 ctx.diagnostics.report(
1953 syntax.stable_ptr(db),
1954 IncompatibleErrorPropagateType {
1955 return_ty: return_type,
1956 err_ty: inner_expr_err_variant.ty,
1957 },
1958 );
1959 }
1960 Ok(Expr::PropagateError(ExprPropagateError {
1961 inner: inner_expr.id,
1962 ok_variant: inner_expr_err_prop_ty.ok_variant().clone(),
1963 err_variant: inner_expr_err_variant.clone(),
1964 func_err_variant: func_err_variant.clone(),
1965 stable_ptr: syntax.stable_ptr(db).into(),
1966 }))
1967}
1968
1969fn compute_expr_indexed_semantic(
1971 ctx: &mut ComputationContext<'_>,
1972 syntax: &ast::ExprIndexed,
1973) -> Maybe<Expr> {
1974 let db = ctx.db;
1975 let expr = compute_expr_semantic(ctx, &syntax.expr(db));
1976 let index_expr_syntax = &syntax.index_expr(db);
1977 let index_expr = compute_expr_semantic(ctx, index_expr_syntax);
1978 if !ctx.reduce_ty(expr.ty()).is_var_free(ctx.db) {
1979 ctx.resolver.inference().solve().ok();
1982 }
1983 let info = ctx.db.core_info();
1984 let candidate_traits = [info.index_trt, info.index_view_trt];
1985 let (function_id, _, fixed_expr, mutability) = compute_method_function_call_data(
1986 ctx,
1987 &candidate_traits[..],
1988 "index".into(),
1989 expr,
1990 syntax.stable_ptr(db).untyped(),
1991 None,
1992 |ty, _, inference_errors| Some(NoImplementationOfIndexOperator { ty, inference_errors }),
1993 |ty, _, _| Some(MultipleImplementationOfIndexOperator(ty)),
1994 )?;
1995
1996 expr_function_call(
1997 ctx,
1998 function_id,
1999 vec![
2000 NamedArg(fixed_expr, None, mutability),
2001 NamedArg(index_expr, None, Mutability::Immutable),
2002 ],
2003 syntax.stable_ptr(db),
2004 index_expr_syntax.stable_ptr(db),
2005 )
2006}
2007
2008#[expect(clippy::too_many_arguments)]
2013fn compute_method_function_call_data(
2014 ctx: &mut ComputationContext<'_>,
2015 candidate_traits: &[TraitId],
2016 func_name: SmolStr,
2017 self_expr: ExprAndId,
2018 method_syntax: SyntaxStablePtrId,
2019 generic_args_syntax: Option<Vec<ast::GenericArg>>,
2020 no_implementation_diagnostic: impl Fn(
2021 TypeId,
2022 SmolStr,
2023 TraitInferenceErrors,
2024 ) -> Option<SemanticDiagnosticKind>,
2025 multiple_trait_diagnostic: fn(
2026 TypeId,
2027 TraitFunctionId,
2028 TraitFunctionId,
2029 ) -> Option<SemanticDiagnosticKind>,
2030) -> Maybe<(FunctionId, TraitId, ExprAndId, Mutability)> {
2031 let expr_ptr = self_expr.stable_ptr();
2032 let self_ty = ctx.reduce_ty(self_expr.ty());
2033 let mut inference_errors = vec![];
2037 let (candidates, mut fixed_expr, fixed_ty) = get_method_function_candidates(
2038 ctx,
2039 candidate_traits,
2040 &func_name,
2041 self_expr,
2042 method_syntax,
2043 expr_ptr,
2044 self_ty,
2045 &mut inference_errors,
2046 )?;
2047
2048 let trait_function_id = match candidates[..] {
2049 [] => {
2050 return Err(no_implementation_diagnostic(
2051 self_ty,
2052 func_name,
2053 TraitInferenceErrors { traits_and_errors: inference_errors },
2054 )
2055 .map(|diag| ctx.diagnostics.report(method_syntax, diag))
2056 .unwrap_or_else(skip_diagnostic));
2057 }
2058 [trait_function_id] => trait_function_id,
2059 [trait_function_id0, trait_function_id1, ..] => {
2060 return Err(multiple_trait_diagnostic(
2061 fixed_ty,
2062 trait_function_id0,
2063 trait_function_id1,
2064 )
2065 .map(|diag| ctx.diagnostics.report(method_syntax, diag))
2066 .unwrap_or_else(skip_diagnostic));
2067 }
2068 };
2069 let (function_id, n_snapshots) =
2070 infer_impl_by_self(ctx, trait_function_id, fixed_ty, method_syntax, generic_args_syntax)?;
2071
2072 let signature = ctx.db.trait_function_signature(trait_function_id).unwrap();
2073 let first_param = signature.params.into_iter().next().unwrap();
2074 for _ in 0..n_snapshots {
2075 let ty = TypeLongId::Snapshot(fixed_expr.ty()).intern(ctx.db);
2076 let expr = Expr::Snapshot(ExprSnapshot { inner: fixed_expr.id, ty, stable_ptr: expr_ptr });
2077 fixed_expr = ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) };
2078 }
2079
2080 Ok((function_id, trait_function_id.trait_id(ctx.db), fixed_expr, first_param.mutability))
2081}
2082
2083#[expect(clippy::too_many_arguments)]
2086fn get_method_function_candidates(
2087 ctx: &mut ComputationContext<'_>,
2088 candidate_traits: &[TraitId],
2089 func_name: &SmolStr,
2090 self_expr: ExprAndId,
2091 method_syntax: SyntaxStablePtrId,
2092 expr_ptr: ExprPtr,
2093 self_ty: TypeId,
2094 inference_errors: &mut Vec<(TraitFunctionId, InferenceError)>,
2095) -> Result<(Vec<TraitFunctionId>, ExprAndId, TypeId), cairo_lang_diagnostics::DiagnosticAdded> {
2096 let mut candidates = filter_candidate_traits(
2097 ctx,
2098 inference_errors,
2099 self_ty,
2100 candidate_traits,
2101 func_name.clone(),
2102 method_syntax,
2103 );
2104 if !candidates.is_empty() {
2105 return Ok((candidates, self_expr, self_ty));
2106 }
2107
2108 let mut fixed_expr = self_expr;
2109 let mut fixed_ty = self_ty;
2110
2111 let base_var = match &fixed_expr.expr {
2112 Expr::Var(expr_var) => Some(expr_var.var),
2113 Expr::MemberAccess(ExprMemberAccess { member_path: Some(member_path), .. }) => {
2114 Some(member_path.base_var())
2115 }
2116 _ => None,
2117 };
2118 let is_mut_var = base_var
2119 .filter(|var_id| matches!(ctx.semantic_defs.get(var_id), Some(var) if var.is_mut()))
2120 .is_some();
2121
2122 let deref_chain = ctx.db.deref_chain(self_ty, is_mut_var)?;
2123
2124 for deref_info in deref_chain.derefs.iter() {
2125 let derefed_expr = expr_function_call(
2126 ctx,
2127 deref_info.function_id,
2128 vec![NamedArg(fixed_expr, None, deref_info.self_mutability)],
2129 method_syntax,
2130 expr_ptr,
2131 )?;
2132
2133 fixed_expr =
2134 ExprAndId { expr: derefed_expr.clone(), id: ctx.arenas.exprs.alloc(derefed_expr) };
2135
2136 candidates = filter_candidate_traits(
2137 ctx,
2138 inference_errors,
2139 deref_info.target_ty,
2140 candidate_traits,
2141 func_name.clone(),
2142 method_syntax,
2143 );
2144 if !candidates.is_empty() {
2145 fixed_ty = deref_info.target_ty;
2146 break;
2147 }
2148 }
2149
2150 Ok((candidates, fixed_expr, fixed_ty))
2151}
2152
2153pub fn compute_pattern_semantic(
2157 ctx: &mut ComputationContext<'_>,
2158 syntax: &ast::Pattern,
2159 ty: TypeId,
2160 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2161) -> PatternAndId {
2162 let pat = maybe_compute_pattern_semantic(ctx, syntax, ty, or_pattern_variables_map);
2163 let pat = pat.unwrap_or_else(|diag_added| {
2164 Pattern::Missing(PatternMissing {
2165 ty: TypeId::missing(ctx.db, diag_added),
2166 stable_ptr: syntax.stable_ptr(ctx.db),
2167 diag_added,
2168 })
2169 });
2170 let id = ctx.arenas.patterns.alloc(pat.clone());
2171 PatternAndId { pattern: pat, id }
2172}
2173
2174fn maybe_compute_pattern_semantic(
2176 ctx: &mut ComputationContext<'_>,
2177 pattern_syntax: &ast::Pattern,
2178 ty: TypeId,
2179 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2180) -> Maybe<Pattern> {
2181 let db = ctx.db;
2183 let ty = ctx.reduce_ty(ty);
2184 let stable_ptr = pattern_syntax.stable_ptr(db).untyped();
2185 let pattern = match pattern_syntax {
2186 ast::Pattern::Underscore(otherwise_pattern) => Pattern::Otherwise(PatternOtherwise {
2187 ty,
2188 stable_ptr: otherwise_pattern.stable_ptr(db),
2189 }),
2190 ast::Pattern::Literal(literal_pattern) => {
2191 let literal = literal_to_semantic(ctx, literal_pattern)?;
2192 Pattern::Literal(PatternLiteral {
2193 literal,
2194 stable_ptr: literal_pattern.stable_ptr(db).into(),
2195 })
2196 }
2197 ast::Pattern::ShortString(short_string_pattern) => {
2198 let literal = short_string_to_semantic(ctx, short_string_pattern)?;
2199 Pattern::Literal(PatternLiteral {
2200 literal,
2201 stable_ptr: short_string_pattern.stable_ptr(db).into(),
2202 })
2203 }
2204 ast::Pattern::String(string_pattern) => {
2205 let string_literal = string_literal_to_semantic(ctx, string_pattern)?;
2206 Pattern::StringLiteral(PatternStringLiteral {
2207 string_literal,
2208 stable_ptr: string_pattern.stable_ptr(db).into(),
2209 })
2210 }
2211 ast::Pattern::Enum(enum_pattern) => {
2212 let path = enum_pattern.path(db);
2213 let item = ctx.resolver.resolve_generic_path(
2214 ctx.diagnostics,
2215 &path,
2216 NotFoundItemType::Identifier,
2217 ResolutionContext::Statement(&mut ctx.environment),
2218 )?;
2219 let generic_variant = try_extract_matches!(item, ResolvedGenericItem::Variant)
2220 .ok_or_else(|| ctx.diagnostics.report(path.stable_ptr(db), NotAVariant))?;
2221
2222 let (concrete_enum, n_snapshots) = extract_concrete_enum_from_pattern_and_validate(
2223 ctx,
2224 pattern_syntax,
2225 ty,
2226 generic_variant.enum_id,
2227 )?;
2228
2229 let concrete_variant = ctx
2231 .db
2232 .concrete_enum_variant(concrete_enum, &generic_variant)
2233 .map_err(|_| ctx.diagnostics.report(path.stable_ptr(db), UnknownEnum))?;
2234
2235 let inner_ty = wrap_in_snapshots(ctx.db, concrete_variant.ty, n_snapshots);
2237
2238 let inner_pattern = match enum_pattern.pattern(db) {
2239 ast::OptionPatternEnumInnerPattern::Empty(_) => None,
2240 ast::OptionPatternEnumInnerPattern::PatternEnumInnerPattern(p) => {
2241 let pattern = compute_pattern_semantic(
2242 ctx,
2243 &p.pattern(db),
2244 inner_ty,
2245 or_pattern_variables_map,
2246 );
2247 Some(pattern.id)
2248 }
2249 };
2250
2251 Pattern::EnumVariant(PatternEnumVariant {
2252 variant: concrete_variant,
2253 inner_pattern,
2254 ty,
2255 stable_ptr: enum_pattern.stable_ptr(db).into(),
2256 })
2257 }
2258 ast::Pattern::Path(path) => {
2259 let item_result = ctx.resolver.resolve_generic_path(
2260 &mut Default::default(),
2261 path,
2262 NotFoundItemType::Identifier,
2263 ResolutionContext::Statement(&mut ctx.environment),
2264 );
2265 if let Ok(item) = item_result {
2266 if let Some(generic_variant) =
2267 try_extract_matches!(item, ResolvedGenericItem::Variant)
2268 {
2269 let (concrete_enum, _n_snapshots) =
2270 extract_concrete_enum_from_pattern_and_validate(
2271 ctx,
2272 pattern_syntax,
2273 ty,
2274 generic_variant.enum_id,
2275 )?;
2276 let concrete_variant = ctx
2277 .db
2278 .concrete_enum_variant(concrete_enum, &generic_variant)
2279 .map_err(|_| ctx.diagnostics.report(path.stable_ptr(db), UnknownEnum))?;
2280 return Ok(Pattern::EnumVariant(PatternEnumVariant {
2281 variant: concrete_variant,
2282 inner_pattern: None,
2283 ty,
2284 stable_ptr: path.stable_ptr(db).into(),
2285 }));
2286 }
2287 }
2288
2289 if path.elements(db).len() > 1 {
2293 return Err(ctx.diagnostics.report(path.stable_ptr(db), Unsupported));
2294 }
2295 let identifier = path.elements(db)[0].identifier_ast(db);
2297 create_variable_pattern(
2298 ctx,
2299 identifier,
2300 &[],
2301 ty,
2302 path.stable_ptr(db).into(),
2303 or_pattern_variables_map,
2304 )
2305 }
2306 ast::Pattern::Identifier(identifier) => create_variable_pattern(
2307 ctx,
2308 identifier.name(db),
2309 &identifier.modifiers(db).elements(db),
2310 ty,
2311 identifier.stable_ptr(db).into(),
2312 or_pattern_variables_map,
2313 ),
2314 ast::Pattern::Struct(pattern_struct) => {
2315 let pattern_ty = try_extract_matches!(
2316 ctx.resolver.resolve_concrete_path_ex(
2317 ctx.diagnostics,
2318 &pattern_struct.path(db),
2319 NotFoundItemType::Type,
2320 ResolutionContext::Statement(&mut ctx.environment)
2321 )?,
2322 ResolvedConcreteItem::Type
2323 )
2324 .ok_or_else(|| {
2325 ctx.diagnostics.report(pattern_struct.path(db).stable_ptr(db), NotAType)
2326 })?;
2327 let inference = &mut ctx.resolver.inference();
2328 inference.conform_ty(pattern_ty, peel_snapshots(ctx.db, ty).1.intern(ctx.db)).map_err(
2329 |err_set| inference.report_on_pending_error(err_set, ctx.diagnostics, stable_ptr),
2330 )?;
2331 let ty = ctx.reduce_ty(ty);
2332 let (n_snapshots, long_ty) = peel_snapshots(ctx.db, ty);
2334
2335 let concrete_struct_id = try_extract_matches!(long_ty, TypeLongId::Concrete)
2337 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Struct))
2338 .ok_or(())
2339 .or_else(|_| {
2340 ty.check_not_missing(ctx.db)?;
2343 Err(ctx
2344 .diagnostics
2345 .report(pattern_struct.stable_ptr(db), UnexpectedStructPattern(ty)))
2346 })?;
2347 let pattern_param_asts = pattern_struct.params(db).elements(db);
2348 let struct_id = concrete_struct_id.struct_id(ctx.db);
2349 let mut members = ctx.db.concrete_struct_members(concrete_struct_id)?.as_ref().clone();
2350 let mut used_members = UnorderedHashSet::<_>::default();
2351 let mut get_member = |ctx: &mut ComputationContext<'_>,
2352 member_name: SmolStr,
2353 stable_ptr: SyntaxStablePtrId| {
2354 let member = members.swap_remove(&member_name).on_none(|| {
2355 ctx.diagnostics.report(
2356 stable_ptr,
2357 if used_members.contains(&member_name) {
2358 StructMemberRedefinition { struct_id, member_name: member_name.clone() }
2359 } else {
2360 NoSuchStructMember { struct_id, member_name: member_name.clone() }
2361 },
2362 );
2363 })?;
2364 check_struct_member_is_visible(ctx, &member, stable_ptr, &member_name);
2365 used_members.insert(member_name);
2366 Some(member)
2367 };
2368 let mut field_patterns = vec![];
2369 let mut has_tail = false;
2370 for pattern_param_ast in pattern_param_asts {
2371 match pattern_param_ast {
2372 PatternStructParam::Single(single) => {
2373 let name = single.name(db);
2374 let Some(member) =
2375 get_member(ctx, name.text(db), name.stable_ptr(db).untyped())
2376 else {
2377 continue;
2378 };
2379 let ty = wrap_in_snapshots(ctx.db, member.ty, n_snapshots);
2380 let pattern = create_variable_pattern(
2381 ctx,
2382 name,
2383 &single.modifiers(db).elements(db),
2384 ty,
2385 single.stable_ptr(db).into(),
2386 or_pattern_variables_map,
2387 );
2388 field_patterns.push((member, ctx.arenas.patterns.alloc(pattern)));
2389 }
2390 PatternStructParam::WithExpr(with_expr) => {
2391 let name = with_expr.name(db);
2392 let Some(member) =
2393 get_member(ctx, name.text(db), name.stable_ptr(db).untyped())
2394 else {
2395 continue;
2396 };
2397 let ty = wrap_in_snapshots(ctx.db, member.ty, n_snapshots);
2398 let pattern = compute_pattern_semantic(
2399 ctx,
2400 &with_expr.pattern(db),
2401 ty,
2402 or_pattern_variables_map,
2403 );
2404 field_patterns.push((member, pattern.id));
2405 }
2406 PatternStructParam::Tail(_) => {
2407 has_tail = true;
2408 }
2409 }
2410 }
2411 if !has_tail {
2412 for (member_name, _) in members.iter() {
2413 ctx.diagnostics
2414 .report(pattern_struct.stable_ptr(db), MissingMember(member_name.clone()));
2415 }
2416 }
2417 Pattern::Struct(PatternStruct {
2418 concrete_struct_id,
2419 field_patterns,
2420 ty,
2421 n_snapshots,
2422 stable_ptr: pattern_struct.stable_ptr(db),
2423 })
2424 }
2425 ast::Pattern::Tuple(_) => maybe_compute_tuple_like_pattern_semantic(
2426 ctx,
2427 pattern_syntax,
2428 ty,
2429 or_pattern_variables_map,
2430 |ty: TypeId| UnexpectedTuplePattern(ty),
2431 |expected, actual| WrongNumberOfTupleElements { expected, actual },
2432 )?,
2433 ast::Pattern::FixedSizeArray(_) => maybe_compute_tuple_like_pattern_semantic(
2434 ctx,
2435 pattern_syntax,
2436 ty,
2437 or_pattern_variables_map,
2438 |ty: TypeId| UnexpectedFixedSizeArrayPattern(ty),
2439 |expected, actual| WrongNumberOfFixedSizeArrayElements { expected, actual },
2440 )?,
2441 ast::Pattern::False(pattern_false) => {
2442 let enum_expr = extract_matches!(
2443 false_literal_expr(ctx, pattern_false.stable_ptr(db).into()),
2444 Expr::EnumVariantCtor
2445 );
2446
2447 extract_concrete_enum_from_pattern_and_validate(
2448 ctx,
2449 pattern_syntax,
2450 ty,
2451 enum_expr.variant.concrete_enum_id.enum_id(ctx.db),
2452 )?;
2453
2454 Pattern::EnumVariant(PatternEnumVariant {
2455 variant: enum_expr.variant,
2456 stable_ptr: pattern_false.stable_ptr(db).into(),
2457 ty,
2458 inner_pattern: None,
2459 })
2460 }
2461 ast::Pattern::True(pattern_true) => {
2462 let enum_expr = extract_matches!(
2463 true_literal_expr(ctx, pattern_true.stable_ptr(db).into()),
2464 Expr::EnumVariantCtor
2465 );
2466 extract_concrete_enum_from_pattern_and_validate(
2467 ctx,
2468 pattern_syntax,
2469 ty,
2470 enum_expr.variant.concrete_enum_id.enum_id(ctx.db),
2471 )?;
2472
2473 Pattern::EnumVariant(PatternEnumVariant {
2474 variant: enum_expr.variant,
2475 stable_ptr: pattern_true.stable_ptr(db).into(),
2476 ty,
2477 inner_pattern: None,
2478 })
2479 }
2480 };
2481 let inference = &mut ctx.resolver.inference();
2482 inference.conform_ty(pattern.ty(), ty).map_err(|err_set| {
2483 inference.report_on_pending_error(err_set, ctx.diagnostics, stable_ptr)
2484 })?;
2485 Ok(pattern)
2486}
2487
2488fn maybe_compute_tuple_like_pattern_semantic(
2491 ctx: &mut ComputationContext<'_>,
2492 pattern_syntax: &ast::Pattern,
2493 ty: TypeId,
2494 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2495 unexpected_pattern: fn(TypeId) -> SemanticDiagnosticKind,
2496 wrong_number_of_elements: fn(usize, usize) -> SemanticDiagnosticKind,
2497) -> Maybe<Pattern> {
2498 let db = ctx.db;
2499 let (n_snapshots, long_ty) =
2500 finalized_snapshot_peeled_ty(ctx, ty, pattern_syntax.stable_ptr(db))?;
2501 match (pattern_syntax, &long_ty) {
2503 (ast::Pattern::Tuple(_), TypeLongId::Tuple(_) | TypeLongId::Var(_))
2504 | (
2505 ast::Pattern::FixedSizeArray(_),
2506 TypeLongId::FixedSizeArray { .. } | TypeLongId::Var(_),
2507 ) => {}
2508 _ => {
2509 return Err(ctx
2510 .diagnostics
2511 .report(pattern_syntax.stable_ptr(db), unexpected_pattern(ty)));
2512 }
2513 };
2514 let patterns_syntax = match pattern_syntax {
2515 ast::Pattern::Tuple(pattern_tuple) => pattern_tuple.patterns(ctx.db).elements(ctx.db),
2516 ast::Pattern::FixedSizeArray(pattern_fixed_size_array) => {
2517 pattern_fixed_size_array.patterns(db).elements(db)
2518 }
2519 _ => unreachable!(),
2520 };
2521 let inner_tys = match long_ty {
2522 TypeLongId::Tuple(inner_tys) => inner_tys,
2523 TypeLongId::FixedSizeArray { type_id: inner_ty, size } => {
2524 let size = if let ConstValue::Int(value, _) = size.lookup_intern(ctx.db) {
2525 value.to_usize().expect("Fixed sized array size must always be usize.")
2526 } else {
2527 let inference = &mut ctx.resolver.inference();
2528 let expected_size =
2529 ConstValue::Int(patterns_syntax.len().into(), get_usize_ty(ctx.db))
2530 .intern(ctx.db);
2531 if let Err(err) = inference.conform_const(size, expected_size) {
2532 let _ = inference.report_on_pending_error(
2533 err,
2534 ctx.diagnostics,
2535 pattern_syntax.stable_ptr(db).untyped(),
2536 );
2537 }
2538 patterns_syntax.len()
2539 };
2540
2541 [inner_ty].repeat(size)
2542 }
2543 TypeLongId::Var(_) => {
2544 let inference = &mut ctx.resolver.inference();
2545 let (inner_tys, tuple_like_ty) = if matches!(pattern_syntax, ast::Pattern::Tuple(_)) {
2546 let inner_tys: Vec<_> = patterns_syntax
2547 .iter()
2548 .map(|e| inference.new_type_var(Some(e.stable_ptr(db).untyped())))
2549 .collect();
2550 (inner_tys.clone(), TypeLongId::Tuple(inner_tys))
2551 } else {
2552 let var = inference.new_type_var(Some(pattern_syntax.stable_ptr(db).untyped()));
2553 (
2554 vec![var; patterns_syntax.len()],
2555 TypeLongId::FixedSizeArray {
2556 type_id: var,
2557 size: ConstValue::Int(patterns_syntax.len().into(), get_usize_ty(ctx.db))
2558 .intern(ctx.db),
2559 },
2560 )
2561 };
2562 match inference.conform_ty(ty, tuple_like_ty.intern(ctx.db)) {
2563 Ok(_) => {}
2564 Err(_) => unreachable!("As the type is a var, conforming should always succeed."),
2565 }
2566 inner_tys
2567 }
2568 _ => unreachable!(),
2569 };
2570 let size = inner_tys.len();
2571 if size != patterns_syntax.len() {
2572 return Err(ctx.diagnostics.report(
2573 pattern_syntax.stable_ptr(db),
2574 wrong_number_of_elements(size, patterns_syntax.len()),
2575 ));
2576 }
2577 let pattern_options = zip_eq(patterns_syntax, inner_tys).map(|(pattern_ast, ty)| {
2578 let ty = wrap_in_snapshots(ctx.db, ty, n_snapshots);
2579 let pattern = compute_pattern_semantic(ctx, &pattern_ast, ty, or_pattern_variables_map);
2580 Ok(pattern.id)
2581 });
2582 let field_patterns: Vec<_> = pattern_options.collect::<Maybe<_>>()?;
2584 Ok(match pattern_syntax {
2585 ast::Pattern::Tuple(syntax) => {
2586 Pattern::Tuple(PatternTuple { field_patterns, ty, stable_ptr: syntax.stable_ptr(db) })
2587 }
2588 ast::Pattern::FixedSizeArray(syntax) => Pattern::FixedSizeArray(PatternFixedSizeArray {
2589 elements_patterns: field_patterns,
2590 ty,
2591 stable_ptr: syntax.stable_ptr(db),
2592 }),
2593 _ => unreachable!(),
2594 })
2595}
2596
2597fn extract_concrete_enum_from_pattern_and_validate(
2599 ctx: &mut ComputationContext<'_>,
2600 pattern: &ast::Pattern,
2601 ty: TypeId,
2602 enum_id: EnumId,
2603) -> Maybe<(ConcreteEnumId, usize)> {
2604 let db = ctx.db;
2605 let (n_snapshots, long_ty) = finalized_snapshot_peeled_ty(ctx, ty, pattern.stable_ptr(db))?;
2607
2608 let concrete_enum = try_extract_matches!(long_ty, TypeLongId::Concrete)
2610 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Enum))
2611 .ok_or(())
2612 .or_else(|_| {
2613 ty.check_not_missing(ctx.db)?;
2616 Err(ctx.diagnostics.report(pattern.stable_ptr(db), UnexpectedEnumPattern(ty)))
2617 })?;
2618 if enum_id != concrete_enum.enum_id(ctx.db) {
2620 return Err(ctx.diagnostics.report(
2621 pattern.stable_ptr(db),
2622 WrongEnum { expected_enum: concrete_enum.enum_id(ctx.db), actual_enum: enum_id },
2623 ));
2624 }
2625 Ok((concrete_enum, n_snapshots))
2626}
2627
2628fn create_variable_pattern(
2630 ctx: &mut ComputationContext<'_>,
2631 identifier: ast::TerminalIdentifier,
2632 modifier_list: &[ast::Modifier],
2633 ty: TypeId,
2634 stable_ptr: ast::PatternPtr,
2635 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2636) -> Pattern {
2637 let db = ctx.db;
2638
2639 let var_id = match or_pattern_variables_map.get(&identifier.text(db)) {
2640 Some(var) => var.id,
2641 None => {
2642 LocalVarLongId(ctx.resolver.module_file_id, identifier.stable_ptr(db)).intern(ctx.db)
2643 }
2644 };
2645 let is_mut = match compute_mutability(ctx.diagnostics, db, modifier_list) {
2646 Mutability::Immutable => false,
2647 Mutability::Mutable => true,
2648 Mutability::Reference => {
2649 ctx.diagnostics.report(identifier.stable_ptr(db), ReferenceLocalVariable);
2650 false
2651 }
2652 };
2653 Pattern::Variable(PatternVariable {
2654 name: identifier.text(db),
2655 var: LocalVariable { id: var_id, ty, is_mut },
2656 stable_ptr,
2657 })
2658}
2659
2660fn struct_ctor_expr(
2662 ctx: &mut ComputationContext<'_>,
2663 ctor_syntax: &ast::ExprStructCtorCall,
2664) -> Maybe<Expr> {
2665 let db = ctx.db;
2666 let path = ctor_syntax.path(db);
2667
2668 let ty = resolve_type_ex(
2670 db,
2671 ctx.diagnostics,
2672 &mut ctx.resolver,
2673 &ast::Expr::Path(path.clone()),
2674 ResolutionContext::Statement(&mut ctx.environment),
2675 );
2676 ty.check_not_missing(db)?;
2677
2678 let concrete_struct_id = try_extract_matches!(ty.lookup_intern(ctx.db), TypeLongId::Concrete)
2679 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Struct))
2680 .ok_or_else(|| ctx.diagnostics.report(path.stable_ptr(db), NotAStruct))?;
2681
2682 if ty.is_phantom(db) {
2683 ctx.diagnostics.report(ctor_syntax.stable_ptr(db), CannotCreateInstancesOfPhantomTypes);
2684 }
2685
2686 let members = db.concrete_struct_members(concrete_struct_id)?;
2687 let mut member_exprs: OrderedHashMap<MemberId, Option<ExprId>> = OrderedHashMap::default();
2688 let mut base_struct = None;
2689
2690 for (index, arg) in ctor_syntax.arguments(db).arguments(db).elements(db).into_iter().enumerate()
2691 {
2692 match arg {
2694 ast::StructArg::StructArgSingle(arg) => {
2695 let arg_identifier = arg.identifier(db);
2696 let arg_name = arg_identifier.text(db);
2697
2698 let Some(member) = members.get(&arg_name) else {
2700 ctx.diagnostics.report(arg_identifier.stable_ptr(db), UnknownMember);
2701 continue;
2702 };
2703 check_struct_member_is_visible(
2704 ctx,
2705 member,
2706 arg_identifier.stable_ptr(db).untyped(),
2707 &arg_name,
2708 );
2709
2710 let arg_expr = match arg.arg_expr(db) {
2712 ast::OptionStructArgExpr::Empty(_) => {
2713 let Ok(expr) = resolve_variable_by_name(
2714 ctx,
2715 &arg_identifier,
2716 path.stable_ptr(db).into(),
2717 ) else {
2718 if member_exprs.insert(member.id, None).is_some() {
2720 ctx.diagnostics.report(
2721 arg_identifier.stable_ptr(db),
2722 MemberSpecifiedMoreThanOnce,
2723 );
2724 }
2725 continue;
2726 };
2727 ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) }
2728 }
2729 ast::OptionStructArgExpr::StructArgExpr(arg_expr) => {
2730 compute_expr_semantic(ctx, &arg_expr.expr(db))
2731 }
2732 };
2733
2734 if member_exprs.insert(member.id, Some(arg_expr.id)).is_some() {
2736 ctx.diagnostics
2737 .report(arg_identifier.stable_ptr(db), MemberSpecifiedMoreThanOnce);
2738 }
2739
2740 let inference = &mut ctx.resolver.inference();
2742 if inference
2743 .conform_ty_for_diag(
2744 arg_expr.ty(),
2745 member.ty,
2746 ctx.diagnostics,
2747 || arg_identifier.stable_ptr(db).untyped(),
2748 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
2749 )
2750 .is_err()
2751 {
2752 continue;
2753 }
2754 }
2755 ast::StructArg::StructArgTail(base_struct_syntax) => {
2756 if index != ctor_syntax.arguments(db).arguments(db).elements(db).len() - 1 {
2758 ctx.diagnostics.report(
2759 base_struct_syntax.stable_ptr(db),
2760 StructBaseStructExpressionNotLast,
2761 );
2762 continue;
2763 }
2764 let base_struct_expr =
2765 compute_expr_semantic(ctx, &base_struct_syntax.expression(db));
2766 let inference = &mut ctx.resolver.inference();
2767 if inference
2768 .conform_ty_for_diag(
2769 base_struct_expr.ty(),
2770 ty,
2771 ctx.diagnostics,
2772 || base_struct_syntax.expression(db).stable_ptr(db).untyped(),
2773 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
2774 )
2775 .is_err()
2776 {
2777 continue;
2778 }
2779
2780 base_struct = Some((base_struct_expr.id, base_struct_syntax));
2781 }
2782 };
2783 }
2784
2785 for (member_name, member) in members.iter() {
2787 if !member_exprs.contains_key(&member.id) {
2788 if base_struct.is_some() {
2789 check_struct_member_is_visible(
2790 ctx,
2791 member,
2792 base_struct.clone().unwrap().1.stable_ptr(db).untyped(),
2793 member_name,
2794 );
2795 } else {
2796 ctx.diagnostics
2797 .report(ctor_syntax.stable_ptr(db), MissingMember(member_name.clone()));
2798 }
2799 }
2800 }
2801 if members.len() == member_exprs.len() {
2802 if let Some((_, base_struct_syntax)) = base_struct {
2803 return Err(ctx
2804 .diagnostics
2805 .report(base_struct_syntax.stable_ptr(db), StructBaseStructExpressionNoEffect));
2806 }
2807 }
2808 Ok(Expr::StructCtor(ExprStructCtor {
2809 concrete_struct_id,
2810 members: member_exprs.into_iter().filter_map(|(x, y)| Some((x, y?))).collect(),
2811 base_struct: base_struct.map(|(x, _)| x),
2812 ty: TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)).intern(db),
2813 stable_ptr: ctor_syntax.stable_ptr(db).into(),
2814 }))
2815}
2816
2817fn get_tail_expression(db: &dyn SyntaxGroup, statements: &[ast::Statement]) -> Option<ast::Expr> {
2821 let last = statements.last()?;
2822 let statement_expr = try_extract_matches!(last, ast::Statement::Expr)?;
2823 try_extract_matches!(statement_expr.semicolon(db), ast::OptionTerminalSemicolon::Empty)?;
2824 Some(statement_expr.expr(db))
2825}
2826
2827fn new_literal_expr(
2829 ctx: &mut ComputationContext<'_>,
2830 ty: Option<&str>,
2831 value: BigInt,
2832 stable_ptr: ExprPtr,
2833) -> Maybe<ExprLiteral> {
2834 if let Some(ty_str) = ty {
2835 if ty_str == "NonZero" {
2837 return Err(ctx.diagnostics.report(
2838 stable_ptr.untyped(),
2839 SemanticDiagnosticKind::WrongNumberOfArguments { expected: 1, actual: 0 },
2840 ));
2841 }
2842 let ty = try_get_core_ty_by_name(ctx.db, ty_str.into(), vec![])
2843 .map_err(|err| ctx.diagnostics.report(stable_ptr.untyped(), err))?;
2844 if let Err(err) = validate_literal(ctx.db, ty, &value) {
2845 ctx.diagnostics.report(stable_ptr, SemanticDiagnosticKind::LiteralError(err));
2846 }
2847 return Ok(ExprLiteral { value, ty, stable_ptr });
2848 };
2849 let ty = ctx.resolver.inference().new_type_var(Some(stable_ptr.untyped()));
2850
2851 let trait_id = ctx.db.core_info().numeric_literal_trt;
2853 let generic_args = vec![GenericArgumentId::Type(ty)];
2854 let concrete_trait_id = semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(ctx.db);
2855 let lookup_context = ctx.resolver.impl_lookup_context();
2856 let inference = &mut ctx.resolver.inference();
2857 inference.new_impl_var(concrete_trait_id, Some(stable_ptr.untyped()), lookup_context);
2858
2859 Ok(ExprLiteral { value, ty, stable_ptr })
2860}
2861
2862fn literal_to_semantic(
2864 ctx: &mut ComputationContext<'_>,
2865 literal_syntax: &ast::TerminalLiteralNumber,
2866) -> Maybe<ExprLiteral> {
2867 let db = ctx.db;
2868
2869 let (value, ty) = literal_syntax.numeric_value_and_suffix(db).unwrap_or_default();
2870 let ty = ty.as_ref().map(SmolStr::as_str);
2871
2872 new_literal_expr(ctx, ty, value, literal_syntax.stable_ptr(db).into())
2873}
2874
2875fn short_string_to_semantic(
2877 ctx: &mut ComputationContext<'_>,
2878 short_string_syntax: &ast::TerminalShortString,
2879) -> Maybe<ExprLiteral> {
2880 let db = ctx.db;
2881
2882 let value = short_string_syntax.numeric_value(db).unwrap_or_default();
2883
2884 let suffix = short_string_syntax.suffix(db);
2885 let suffix = suffix.as_ref().map(SmolStr::as_str);
2886
2887 new_literal_expr(ctx, suffix, value, short_string_syntax.stable_ptr(db).into())
2888}
2889
2890fn new_string_literal_expr(
2892 ctx: &mut ComputationContext<'_>,
2893 value: String,
2894 stable_ptr: ExprPtr,
2895) -> Maybe<ExprStringLiteral> {
2896 let ty = ctx.resolver.inference().new_type_var(Some(stable_ptr.untyped()));
2897
2898 let trait_id = ctx.db.core_info().string_literal_trt;
2899 let generic_args = vec![GenericArgumentId::Type(ty)];
2900 let concrete_trait_id = semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(ctx.db);
2901 let lookup_context = ctx.resolver.impl_lookup_context();
2902 let inference = &mut ctx.resolver.inference();
2903 inference.new_impl_var(concrete_trait_id, Some(stable_ptr.untyped()), lookup_context);
2904
2905 Ok(ExprStringLiteral { value, ty, stable_ptr })
2906}
2907
2908fn string_literal_to_semantic(
2910 ctx: &mut ComputationContext<'_>,
2911 string_syntax: &ast::TerminalString,
2912) -> Maybe<ExprStringLiteral> {
2913 let db = ctx.db;
2914 let stable_ptr = string_syntax.stable_ptr(db);
2915
2916 let value = string_syntax.string_value(db).unwrap_or_default();
2917 new_string_literal_expr(ctx, value, stable_ptr.into())
2920}
2921
2922fn expr_as_identifier(
2925 ctx: &mut ComputationContext<'_>,
2926 path: &ast::ExprPath,
2927 db: &dyn SyntaxGroup,
2928) -> Maybe<SmolStr> {
2929 let segments = path.elements(db);
2930 if segments.len() == 1 {
2931 return Ok(segments[0].identifier(db));
2932 }
2933 Err(ctx.diagnostics.report(path.stable_ptr(db), InvalidMemberExpression))
2934}
2935
2936fn dot_expr(
2939 ctx: &mut ComputationContext<'_>,
2940 lexpr: ExprAndId,
2941 rhs_syntax: ast::Expr,
2942 stable_ptr: ast::ExprPtr,
2943) -> Maybe<Expr> {
2944 match rhs_syntax {
2946 ast::Expr::Path(expr) => member_access_expr(ctx, lexpr, expr, stable_ptr),
2947 ast::Expr::FunctionCall(expr) => method_call_expr(ctx, lexpr, expr, stable_ptr),
2948 _ => Err(ctx.diagnostics.report(rhs_syntax.stable_ptr(ctx.db), InvalidMemberExpression)),
2949 }
2950}
2951
2952fn traits_in_context(
2954 ctx: &mut ComputationContext<'_>,
2955) -> Maybe<OrderedHashMap<TraitId, LookupItemId>> {
2956 let mut traits =
2957 ctx.db.module_usable_trait_ids(ctx.resolver.prelude_submodule())?.deref().clone();
2958 traits.extend(
2959 ctx.db
2960 .module_usable_trait_ids(ctx.resolver.module_file_id.0)?
2961 .iter()
2962 .map(|(k, v)| (*k, *v)),
2963 );
2964 Ok(traits)
2965}
2966
2967fn method_call_expr(
2971 ctx: &mut ComputationContext<'_>,
2972 lexpr: ExprAndId,
2973 expr: ast::ExprFunctionCall,
2974 stable_ptr: ast::ExprPtr,
2975) -> Maybe<Expr> {
2976 let db = ctx.db;
2979 let path = expr.path(db);
2980 let Ok([segment]): Result<[_; 1], _> = path.elements(db).try_into() else {
2981 return Err(ctx.diagnostics.report(expr.stable_ptr(db), InvalidMemberExpression));
2982 };
2983 let func_name = segment.identifier(db);
2984 let generic_args_syntax = segment.generic_args(db);
2985
2986 if !ctx.reduce_ty(lexpr.ty()).is_var_free(ctx.db) {
2987 ctx.resolver.inference().solve().ok();
2991 }
2992
2993 let mut candidate_traits = traits_in_context(ctx)?;
2994
2995 for generic_param in &ctx.resolver.data.generic_params {
2997 if generic_param.kind(ctx.db) == GenericKind::Impl {
2998 let Ok(trait_id) = ctx.db.generic_impl_param_trait(*generic_param) else {
2999 continue;
3000 };
3001 candidate_traits
3002 .insert(trait_id, LookupItemId::ModuleItem(ModuleItemId::Trait(trait_id)));
3003 }
3004 }
3005
3006 let module_file_id = ctx.resolver.module_file_id;
3008 let lookup_context = ctx.resolver.impl_lookup_context();
3009 let lexpr_clone = lexpr.clone();
3010 let db = ctx.db;
3011 let (function_id, actual_trait_id, fixed_lexpr, mutability) =
3012 compute_method_function_call_data(
3013 ctx,
3014 candidate_traits.keys().copied().collect_vec().as_slice(),
3015 func_name.clone(),
3016 lexpr,
3017 path.stable_ptr(db).untyped(),
3018 generic_args_syntax,
3019 |ty, method_name, inference_errors| {
3020 let relevant_traits = if !inference_errors.is_empty() {
3021 vec![]
3022 } else {
3023 match_method_to_traits(
3024 db,
3025 ty,
3026 &method_name,
3027 lookup_context.clone(),
3028 module_file_id,
3029 lexpr_clone.stable_ptr().untyped(),
3030 )
3031 };
3032 Some(CannotCallMethod { ty, method_name, inference_errors, relevant_traits })
3033 },
3034 |_, trait_function_id0, trait_function_id1| {
3035 Some(AmbiguousTrait { trait_function_id0, trait_function_id1 })
3036 },
3037 )?;
3038
3039 if let Ok(trait_definition_data) = ctx.db.priv_trait_definition_data(actual_trait_id) {
3040 if let Some(trait_item_info) = trait_definition_data.get_trait_item_info(&func_name) {
3041 ctx.resolver.validate_feature_constraints(
3042 ctx.diagnostics,
3043 &segment.identifier_ast(db),
3044 &trait_item_info,
3045 );
3046 }
3047 }
3048 ctx.resolver.data.used_items.insert(candidate_traits[&actual_trait_id]);
3049 ctx.resolver.data.resolved_items.mark_concrete(
3050 ctx.db,
3051 &segment,
3052 ResolvedConcreteItem::Function(function_id),
3053 );
3054
3055 let mut args_iter = expr.arguments(db).arguments(db).elements(db).into_iter();
3057 let mut named_args = vec![NamedArg(fixed_lexpr, None, mutability)];
3059 let closure_params: OrderedHashMap<TypeId, TypeId> =
3061 concrete_function_closure_params(ctx.db, function_id)?;
3062 for ty in function_parameter_types(ctx, function_id)?.skip(1) {
3063 let Some(arg_syntax) = args_iter.next() else {
3064 break;
3065 };
3066 named_args.push(compute_named_argument_clause(
3067 ctx,
3068 arg_syntax,
3069 closure_params.get(&ty).copied(),
3070 ));
3071 }
3072
3073 if let Some(arg_syntax) = args_iter.next() {
3075 named_args.push(compute_named_argument_clause(ctx, arg_syntax, None));
3076 }
3077
3078 expr_function_call(ctx, function_id, named_args, expr.stable_ptr(db), stable_ptr)
3079}
3080
3081fn member_access_expr(
3083 ctx: &mut ComputationContext<'_>,
3084 lexpr: ExprAndId,
3085 rhs_syntax: ast::ExprPath,
3086 stable_ptr: ast::ExprPtr,
3087) -> Maybe<Expr> {
3088 let db = ctx.db;
3089
3090 let member_name = expr_as_identifier(ctx, &rhs_syntax, db)?;
3092 let (n_snapshots, long_ty) =
3093 finalized_snapshot_peeled_ty(ctx, lexpr.ty(), rhs_syntax.stable_ptr(db))?;
3094
3095 match &long_ty {
3096 TypeLongId::Concrete(_) | TypeLongId::Tuple(_) | TypeLongId::FixedSizeArray { .. } => {
3097 let Some(EnrichedTypeMemberAccess { member, deref_functions }) =
3098 get_enriched_type_member_access(ctx, lexpr.clone(), stable_ptr, &member_name)?
3099 else {
3100 return Err(ctx.diagnostics.report(
3101 rhs_syntax.stable_ptr(db),
3102 NoSuchTypeMember { ty: long_ty.intern(ctx.db), member_name },
3103 ));
3104 };
3105 check_struct_member_is_visible(
3106 ctx,
3107 &member,
3108 rhs_syntax.stable_ptr(db).untyped(),
3109 &member_name,
3110 );
3111 let member_path = match &long_ty {
3112 TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id))
3113 if n_snapshots == 0 && deref_functions.is_empty() =>
3114 {
3115 lexpr.as_member_path().map(|parent| ExprVarMemberPath::Member {
3116 parent: Box::new(parent),
3117 member_id: member.id,
3118 stable_ptr,
3119 concrete_struct_id: *concrete_struct_id,
3120 ty: member.ty,
3121 })
3122 }
3123 _ => None,
3124 };
3125 let mut derefed_expr: ExprAndId = lexpr;
3126 for (deref_function, mutability) in &deref_functions {
3127 let cur_expr = expr_function_call(
3128 ctx,
3129 *deref_function,
3130 vec![NamedArg(derefed_expr, None, *mutability)],
3131 stable_ptr,
3132 stable_ptr,
3133 )
3134 .unwrap();
3135
3136 derefed_expr =
3137 ExprAndId { expr: cur_expr.clone(), id: ctx.arenas.exprs.alloc(cur_expr) };
3138 }
3139 let (_, long_ty) =
3140 finalized_snapshot_peeled_ty(ctx, derefed_expr.ty(), rhs_syntax.stable_ptr(db))?;
3141 let derefed_expr_concrete_struct_id = match long_ty {
3142 TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) => {
3143 concrete_struct_id
3144 }
3145 _ => unreachable!(),
3146 };
3147 let ty = if !deref_functions.is_empty() {
3148 member.ty
3149 } else {
3150 wrap_in_snapshots(ctx.db, member.ty, n_snapshots)
3151 };
3152 Ok(Expr::MemberAccess(ExprMemberAccess {
3153 expr: derefed_expr.id,
3154 concrete_struct_id: derefed_expr_concrete_struct_id,
3155 member: member.id,
3156 ty,
3157 member_path,
3158 n_snapshots,
3159 stable_ptr,
3160 }))
3161 }
3162
3163 TypeLongId::Snapshot(_) => {
3164 Err(ctx.diagnostics.report(rhs_syntax.stable_ptr(db), Unsupported))
3166 }
3167 TypeLongId::Closure(_) => {
3168 Err(ctx.diagnostics.report(rhs_syntax.stable_ptr(db), Unsupported))
3169 }
3170 TypeLongId::ImplType(impl_type_id) => {
3171 unreachable!(
3172 "Impl type should've been reduced {:?}.",
3173 impl_type_id.debug(ctx.db.elongate())
3174 )
3175 }
3176 TypeLongId::Var(_) => Err(ctx.diagnostics.report(
3177 rhs_syntax.stable_ptr(db),
3178 InternalInferenceError(InferenceError::TypeNotInferred(long_ty.intern(ctx.db))),
3179 )),
3180 TypeLongId::GenericParameter(_) | TypeLongId::Coupon(_) => Err(ctx.diagnostics.report(
3181 rhs_syntax.stable_ptr(db),
3182 TypeHasNoMembers { ty: long_ty.intern(ctx.db), member_name },
3183 )),
3184 TypeLongId::Missing(diag_added) => Err(*diag_added),
3185 }
3186}
3187
3188fn get_enriched_type_member_access(
3193 ctx: &mut ComputationContext<'_>,
3194 expr: ExprAndId,
3195 stable_ptr: ast::ExprPtr,
3196 accessed_member_name: &str,
3197) -> Maybe<Option<EnrichedTypeMemberAccess>> {
3198 let mut ty = ctx.reduce_ty(expr.ty());
3199 if !ty.is_var_free(ctx.db) {
3200 ctx.resolver.inference().solve().ok();
3204 ty = ctx.reduce_ty(ty);
3205 }
3206 let base_var = match &expr.expr {
3207 Expr::Var(expr_var) => Some(expr_var.var),
3208 Expr::MemberAccess(ExprMemberAccess { member_path: Some(member_path), .. }) => {
3209 Some(member_path.base_var())
3210 }
3211 _ => None,
3212 };
3213 let is_mut_var = base_var
3214 .filter(|var_id| matches!(ctx.semantic_defs.get(var_id), Some(var) if var.is_mut()))
3215 .is_some();
3216 let key = (ty, is_mut_var);
3217 let mut enriched_members = match ctx.resolver.type_enriched_members.entry(key) {
3218 Entry::Occupied(entry) => {
3219 let e = entry.get();
3220 match e.get_member(accessed_member_name) {
3221 Some(value) => return Ok(Some(value)),
3222 None => {
3223 if e.deref_chain.len() == e.explored_derefs {
3224 return Ok(None);
3226 }
3227 }
3228 }
3229 entry.swap_remove()
3231 }
3232 Entry::Vacant(_) => {
3233 let (_, long_ty) = finalized_snapshot_peeled_ty(ctx, ty, stable_ptr)?;
3234 let members =
3235 if let TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) = long_ty {
3236 let members = ctx.db.concrete_struct_members(concrete_struct_id)?;
3237 if let Some(member) = members.get(accessed_member_name) {
3238 return Ok(Some(EnrichedTypeMemberAccess {
3240 member: member.clone(),
3241 deref_functions: vec![],
3242 }));
3243 }
3244 members.iter().map(|(k, v)| (k.clone(), (v.clone(), 0))).collect()
3245 } else {
3246 Default::default()
3247 };
3248
3249 EnrichedMembers {
3250 members,
3251 deref_chain: ctx.db.deref_chain(ty, is_mut_var)?.derefs,
3252 explored_derefs: 0,
3253 }
3254 }
3255 };
3256 enrich_members(ctx, &mut enriched_members, stable_ptr, accessed_member_name)?;
3257 let e = ctx.resolver.type_enriched_members.entry(key).or_insert(enriched_members);
3258 Ok(e.get_member(accessed_member_name))
3259}
3260
3261fn enrich_members(
3266 ctx: &mut ComputationContext<'_>,
3267 enriched_members: &mut EnrichedMembers,
3268 stable_ptr: ast::ExprPtr,
3269 accessed_member_name: &str,
3270) -> Maybe<()> {
3271 let EnrichedMembers { members: enriched, deref_chain, explored_derefs } = enriched_members;
3272
3273 for deref_info in deref_chain.iter().skip(*explored_derefs).cloned() {
3275 *explored_derefs += 1;
3276 let (_, long_ty) = finalized_snapshot_peeled_ty(ctx, deref_info.target_ty, stable_ptr)?;
3277 if let TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) = long_ty {
3278 let members = ctx.db.concrete_struct_members(concrete_struct_id)?;
3279 for (member_name, member) in members.iter() {
3280 enriched
3282 .entry(member_name.clone())
3283 .or_insert_with(|| (member.clone(), *explored_derefs));
3284 }
3285 if members.contains_key(accessed_member_name) {
3287 break;
3289 }
3290 }
3291 }
3292 Ok(())
3293}
3294
3295fn finalized_snapshot_peeled_ty(
3297 ctx: &mut ComputationContext<'_>,
3298 ty: TypeId,
3299 stable_ptr: impl Into<SyntaxStablePtrId>,
3300) -> Maybe<(usize, TypeLongId)> {
3301 let ty = ctx.reduce_ty(ty);
3302 let (base_snapshots, mut long_ty) = peel_snapshots(ctx.db, ty);
3303 if let TypeLongId::ImplType(impl_type_id) = long_ty {
3304 let inference = &mut ctx.resolver.inference();
3305 let Ok(ty) = inference.reduce_impl_ty(impl_type_id) else {
3306 return Err(ctx
3307 .diagnostics
3308 .report(stable_ptr, InternalInferenceError(InferenceError::TypeNotInferred(ty))));
3309 };
3310 long_ty = ty.lookup_intern(ctx.db);
3311 }
3312 if matches!(long_ty, TypeLongId::Var(_)) {
3313 ctx.resolver.inference().solve().ok();
3315 long_ty = ctx.resolver.inference().rewrite(long_ty).no_err();
3316 }
3317 let (additional_snapshots, long_ty) = peel_snapshots_ex(ctx.db, long_ty);
3318 Ok((base_snapshots + additional_snapshots, long_ty))
3319}
3320
3321fn resolve_expr_path(ctx: &mut ComputationContext<'_>, path: &ast::ExprPath) -> Maybe<Expr> {
3323 let db = ctx.db;
3324 let segments = path.elements(db);
3325 if segments.is_empty() {
3326 return Err(ctx.diagnostics.report(path.stable_ptr(db), Unsupported));
3327 }
3328
3329 if let [PathSegment::Simple(ident_segment)] = &segments[..] {
3331 let identifier = ident_segment.ident(db);
3332 let variable_name = identifier.text(db);
3333 if let Some(res) = get_binded_expr_by_name(ctx, &variable_name, path.stable_ptr(db).into())
3334 {
3335 match res.clone() {
3336 Expr::Var(expr_var) => {
3337 let item = ResolvedGenericItem::Variable(expr_var.var);
3338 ctx.resolver
3339 .data
3340 .resolved_items
3341 .generic
3342 .insert(identifier.stable_ptr(db), item);
3343 }
3344 Expr::Constant(expr_const) => {
3345 let item = ResolvedConcreteItem::Constant(expr_const.const_value_id);
3346 ctx.resolver
3347 .data
3348 .resolved_items
3349 .concrete
3350 .insert(identifier.stable_ptr(db), item);
3351 }
3352 _ => unreachable!(
3353 "get_binded_expr_by_name should only return variables or constants"
3354 ),
3355 };
3356 return Ok(res);
3357 }
3358 }
3359
3360 let resolved_item: ResolvedConcreteItem = ctx.resolver.resolve_concrete_path_ex(
3361 ctx.diagnostics,
3362 path,
3363 NotFoundItemType::Identifier,
3364 ResolutionContext::Statement(&mut ctx.environment),
3365 )?;
3366
3367 match resolved_item {
3368 ResolvedConcreteItem::Constant(const_value_id) => Ok(Expr::Constant(ExprConstant {
3369 const_value_id,
3370 ty: const_value_id.ty(db)?,
3371 stable_ptr: path.stable_ptr(db).into(),
3372 })),
3373
3374 ResolvedConcreteItem::Variant(variant) if variant.ty == unit_ty(db) => {
3375 let stable_ptr = path.stable_ptr(db).into();
3376 let concrete_enum_id = variant.concrete_enum_id;
3377 Ok(semantic::Expr::EnumVariantCtor(semantic::ExprEnumVariantCtor {
3378 variant,
3379 value_expr: unit_expr(ctx, stable_ptr),
3380 ty: TypeLongId::Concrete(ConcreteTypeId::Enum(concrete_enum_id)).intern(db),
3381 stable_ptr,
3382 }))
3383 }
3384 resolved_item => Err(ctx.diagnostics.report(
3385 path.stable_ptr(db),
3386 UnexpectedElement {
3387 expected: vec![ElementKind::Variable, ElementKind::Constant],
3388 actual: (&resolved_item).into(),
3389 },
3390 )),
3391 }
3392}
3393
3394pub fn resolve_variable_by_name(
3398 ctx: &mut ComputationContext<'_>,
3399 identifier: &ast::TerminalIdentifier,
3400 stable_ptr: ast::ExprPtr,
3401) -> Maybe<Expr> {
3402 let db = ctx.db;
3403 let variable_name = identifier.text(db);
3404 let res = get_binded_expr_by_name(ctx, &variable_name, stable_ptr).ok_or_else(|| {
3405 ctx.diagnostics.report(identifier.stable_ptr(db), VariableNotFound(variable_name))
3406 })?;
3407 let item = ResolvedGenericItem::Variable(extract_matches!(&res, Expr::Var).var);
3408 ctx.resolver.data.resolved_items.generic.insert(identifier.stable_ptr(db), item);
3409 Ok(res)
3410}
3411
3412pub fn get_binded_expr_by_name(
3414 ctx: &mut ComputationContext<'_>,
3415 variable_name: &SmolStr,
3416 stable_ptr: ast::ExprPtr,
3417) -> Option<Expr> {
3418 let mut maybe_env = Some(&mut *ctx.environment);
3419 while let Some(env) = maybe_env {
3420 if let Some(var) = env.variables.get(variable_name) {
3421 env.used_variables.insert(var.id());
3422 return match var {
3423 Binding::LocalItem(local_const) => match local_const.kind.clone() {
3424 crate::StatementItemKind::Constant(const_value_id, ty) => {
3425 Some(Expr::Constant(ExprConstant { const_value_id, ty, stable_ptr }))
3426 }
3427 },
3428 Binding::LocalVar(_) | Binding::Param(_) => {
3429 Some(Expr::Var(ExprVar { var: var.id(), ty: var.ty(), stable_ptr }))
3430 }
3431 };
3432 }
3433 maybe_env = env.parent.as_deref_mut();
3434 }
3435 None
3436}
3437
3438fn expr_function_call(
3440 ctx: &mut ComputationContext<'_>,
3441 function_id: FunctionId,
3442 mut named_args: Vec<NamedArg>,
3443 call_ptr: impl Into<SyntaxStablePtrId>,
3444 stable_ptr: ast::ExprPtr,
3445) -> Maybe<Expr> {
3446 let coupon_arg = maybe_pop_coupon_argument(ctx, &mut named_args, function_id);
3447
3448 let signature = ctx.db.concrete_function_signature(function_id)?;
3449 let signature = ctx.resolver.inference().rewrite(signature).unwrap();
3450
3451 if named_args.len() != signature.params.len() {
3453 return Err(ctx.diagnostics.report(
3454 call_ptr,
3455 WrongNumberOfArguments { expected: signature.params.len(), actual: named_args.len() },
3456 ));
3457 }
3458
3459 check_named_arguments(&named_args, &signature, ctx)?;
3461
3462 let mut args = Vec::new();
3463 for (NamedArg(arg, _name, mutability), param) in
3464 named_args.into_iter().zip(signature.params.iter())
3465 {
3466 let arg_ty = arg.ty();
3467 let param_ty = param.ty;
3468 if !arg_ty.is_missing(ctx.db) {
3472 let inference = &mut ctx.resolver.inference();
3473 let _ = inference.conform_ty_for_diag(
3474 arg_ty,
3475 param_ty,
3476 ctx.diagnostics,
3477 || arg.stable_ptr().untyped(),
3478 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
3479 );
3480 }
3481
3482 args.push(if param.mutability == Mutability::Reference {
3483 let Some(ref_arg) = arg.as_member_path() else {
3485 return Err(ctx.diagnostics.report(arg.deref(), RefArgNotAVariable));
3486 };
3487 if !ctx.semantic_defs[&ref_arg.base_var()].is_mut() {
3489 ctx.diagnostics.report(arg.deref(), RefArgNotMutable);
3490 }
3491 if mutability != Mutability::Reference {
3493 ctx.diagnostics.report(arg.deref(), RefArgNotExplicit);
3494 }
3495 ExprFunctionCallArg::Reference(ref_arg)
3496 } else {
3497 if mutability != Mutability::Immutable {
3499 ctx.diagnostics.report(arg.deref(), ImmutableArgWithModifiers);
3500 }
3501 ExprFunctionCallArg::Value(arg.id)
3502 });
3503 }
3504
3505 let expr_function_call = ExprFunctionCall {
3506 function: function_id,
3507 args,
3508 coupon_arg,
3509 ty: signature.return_type,
3510 stable_ptr,
3511 };
3512 if signature.panicable && has_panic_incompatibility(ctx) {
3514 return Err(ctx.diagnostics.report(call_ptr, PanicableFromNonPanicable));
3517 }
3518 Ok(Expr::FunctionCall(expr_function_call))
3519}
3520
3521fn maybe_pop_coupon_argument(
3524 ctx: &mut ComputationContext<'_>,
3525 named_args: &mut Vec<NamedArg>,
3526 function_id: FunctionId,
3527) -> Option<id_arena::Id<Expr>> {
3528 let mut coupon_arg: Option<ExprId> = None;
3529 if let Some(NamedArg(arg, Some(name_terminal), mutability)) = named_args.last() {
3530 let coupons_enabled = are_coupons_enabled(ctx.db, ctx.resolver.module_file_id);
3531 if name_terminal.text(ctx.db) == "__coupon__" && coupons_enabled {
3532 let expected_ty = TypeLongId::Coupon(function_id).intern(ctx.db);
3534 let arg_ty = arg.ty();
3535 if !arg_ty.is_missing(ctx.db) {
3536 let inference = &mut ctx.resolver.inference();
3537 let _ = inference.conform_ty_for_diag(
3538 arg_ty,
3539 expected_ty,
3540 ctx.diagnostics,
3541 || arg.stable_ptr().untyped(),
3542 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
3543 );
3544 }
3545
3546 if *mutability != Mutability::Immutable {
3548 ctx.diagnostics.report(arg.deref(), CouponArgumentNoModifiers);
3549 }
3550
3551 coupon_arg = Some(arg.id);
3552
3553 named_args.pop();
3555 }
3556 }
3557 coupon_arg
3558}
3559
3560fn has_panic_incompatibility(ctx: &mut ComputationContext<'_>) -> bool {
3562 if let Some(signature) = ctx.signature {
3563 !signature.panicable
3565 } else {
3566 false
3567 }
3568}
3569
3570fn check_named_arguments(
3572 named_args: &[NamedArg],
3573 signature: &Signature,
3574 ctx: &mut ComputationContext<'_>,
3575) -> Maybe<()> {
3576 let mut res: Maybe<()> = Ok(());
3577
3578 let mut seen_named_arguments: bool = false;
3581 let mut reported_unnamed_argument_follows_named: bool = false;
3584 for (NamedArg(arg, name_opt, _mutability), param) in
3585 named_args.iter().zip(signature.params.iter())
3586 {
3587 if let Some(name_terminal) = name_opt {
3589 seen_named_arguments = true;
3590 let name = name_terminal.text(ctx.db);
3591 if param.name != name.clone() {
3592 res = Err(ctx.diagnostics.report(
3593 name_terminal.stable_ptr(ctx.db),
3594 NamedArgumentMismatch { expected: param.name.clone(), found: name },
3595 ));
3596 }
3597 } else if seen_named_arguments && !reported_unnamed_argument_follows_named {
3598 reported_unnamed_argument_follows_named = true;
3599 res = Err(ctx.diagnostics.report(arg.deref(), UnnamedArgumentFollowsNamed));
3600 }
3601 }
3602 res
3603}
3604
3605pub fn compute_statement_semantic(
3607 ctx: &mut ComputationContext<'_>,
3608 syntax: ast::Statement,
3609) -> Maybe<StatementId> {
3610 let db = ctx.db;
3611
3612 let crate_id = ctx.resolver.owning_crate_id;
3613
3614 validate_statement_attributes(ctx, &syntax);
3617 let feature_restore = ctx
3618 .resolver
3619 .data
3620 .feature_config
3621 .override_with(extract_item_feature_config(db, crate_id, &syntax, ctx.diagnostics));
3622 let statement = match &syntax {
3623 ast::Statement::Let(let_syntax) => {
3624 let rhs_syntax = &let_syntax.rhs(db);
3625 let (rhs_expr, ty) = match let_syntax.type_clause(db) {
3626 ast::OptionTypeClause::Empty(_) => {
3627 let rhs_expr = compute_expr_semantic(ctx, rhs_syntax);
3628 let inferred_type = rhs_expr.ty();
3629 (rhs_expr, inferred_type)
3630 }
3631 ast::OptionTypeClause::TypeClause(type_clause) => {
3632 let var_type_path = type_clause.ty(db);
3633 let explicit_type = resolve_type_ex(
3634 db,
3635 ctx.diagnostics,
3636 &mut ctx.resolver,
3637 &var_type_path,
3638 ResolutionContext::Statement(&mut ctx.environment),
3639 );
3640
3641 let rhs_expr = compute_expr_semantic(ctx, rhs_syntax);
3642 let inferred_type = ctx.reduce_ty(rhs_expr.ty());
3643 if !inferred_type.is_missing(db) {
3644 let inference = &mut ctx.resolver.inference();
3645 let _ = inference.conform_ty_for_diag(
3646 inferred_type,
3647 explicit_type,
3648 ctx.diagnostics,
3649 || rhs_syntax.stable_ptr(db).untyped(),
3650 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
3651 );
3652 }
3653 (rhs_expr, explicit_type)
3654 }
3655 };
3656 let rhs_expr_id = rhs_expr.id;
3657
3658 let pattern = compute_pattern_semantic(
3659 ctx,
3660 &let_syntax.pattern(db),
3661 ty,
3662 &mut UnorderedHashMap::default(),
3663 );
3664 let variables = pattern.variables(&ctx.arenas.patterns);
3665 for v in variables {
3666 let var_def = Binding::LocalVar(v.var.clone());
3667 if let Some(old_var) =
3668 ctx.environment.variables.insert(v.name.clone(), var_def.clone())
3669 {
3670 if matches!(old_var, Binding::LocalItem(_)) {
3671 return Err(ctx
3672 .diagnostics
3673 .report(v.stable_ptr, MultipleDefinitionforBinding(v.name.clone())));
3674 }
3675 ctx.add_unused_binding_warning(&v.name, &old_var);
3676 }
3677 ctx.semantic_defs.insert(var_def.id(), var_def);
3678 }
3679 semantic::Statement::Let(semantic::StatementLet {
3680 pattern: pattern.id,
3681 expr: rhs_expr_id,
3682 stable_ptr: syntax.stable_ptr(db),
3683 })
3684 }
3685 ast::Statement::Expr(stmt_expr_syntax) => {
3686 let expr_syntax = stmt_expr_syntax.expr(db);
3687 let expr = compute_expr_semantic(ctx, &expr_syntax);
3688 if matches!(stmt_expr_syntax.semicolon(db), ast::OptionTerminalSemicolon::Empty(_))
3689 && !matches!(
3690 expr_syntax,
3691 ast::Expr::Block(_)
3692 | ast::Expr::If(_)
3693 | ast::Expr::Match(_)
3694 | ast::Expr::Loop(_)
3695 | ast::Expr::While(_)
3696 | ast::Expr::For(_)
3697 )
3698 {
3699 ctx.diagnostics.report_after(expr_syntax.stable_ptr(db), MissingSemicolon);
3701 }
3702 let ty: TypeId = expr.ty();
3703 if let TypeLongId::Concrete(concrete) = ty.lookup_intern(db) {
3704 if concrete.is_must_use(db)? {
3705 ctx.diagnostics.report(expr_syntax.stable_ptr(db), UnhandledMustUseType(ty));
3706 }
3707 }
3708 if let Expr::FunctionCall(expr_function_call) = &expr.expr {
3709 let generic_function_id =
3710 expr_function_call.function.lookup_intern(db).function.generic_function;
3711 if generic_function_id.is_must_use(db)? {
3712 ctx.diagnostics.report(expr_syntax.stable_ptr(db), UnhandledMustUseFunction);
3713 }
3714 }
3715 semantic::Statement::Expr(semantic::StatementExpr {
3716 expr: expr.id,
3717 stable_ptr: syntax.stable_ptr(db),
3718 })
3719 }
3720 ast::Statement::Continue(continue_syntax) => {
3721 if !ctx.is_inside_loop() {
3722 return Err(ctx
3723 .diagnostics
3724 .report(continue_syntax.stable_ptr(db), ContinueOnlyAllowedInsideALoop));
3725 }
3726 semantic::Statement::Continue(semantic::StatementContinue {
3727 stable_ptr: syntax.stable_ptr(db),
3728 })
3729 }
3730 ast::Statement::Return(return_syntax) => {
3731 let (expr_option, expr_ty, stable_ptr) = match return_syntax.expr_clause(db) {
3732 ast::OptionExprClause::Empty(empty_clause) => {
3733 (None, unit_ty(db), empty_clause.stable_ptr(db).untyped())
3734 }
3735 ast::OptionExprClause::ExprClause(expr_clause) => {
3736 let expr_syntax = expr_clause.expr(db);
3737 let expr = compute_expr_semantic(ctx, &expr_syntax);
3738 (Some(expr.id), expr.ty(), expr_syntax.stable_ptr(db).untyped())
3739 }
3740 };
3741 let expected_ty = match &ctx.inner_ctx {
3742 None => ctx.get_return_type().ok_or_else(|| {
3743 ctx.diagnostics.report(
3744 return_syntax.stable_ptr(db),
3745 UnsupportedOutsideOfFunction(
3746 UnsupportedOutsideOfFunctionFeatureName::ReturnStatement,
3747 ),
3748 )
3749 })?,
3750 Some(ctx) => ctx.return_type,
3751 };
3752
3753 let expected_ty = ctx.reduce_ty(expected_ty);
3754 let expr_ty = ctx.reduce_ty(expr_ty);
3755 if !expected_ty.is_missing(db) && !expr_ty.is_missing(db) {
3756 let inference = &mut ctx.resolver.inference();
3757 let _ = inference.conform_ty_for_diag(
3758 expr_ty,
3759 expected_ty,
3760 ctx.diagnostics,
3761 || stable_ptr,
3762 |actual_ty, expected_ty| WrongReturnType { expected_ty, actual_ty },
3763 );
3764 }
3765 semantic::Statement::Return(semantic::StatementReturn {
3766 expr_option,
3767 stable_ptr: syntax.stable_ptr(db),
3768 })
3769 }
3770 ast::Statement::Break(break_syntax) => {
3771 let (expr_option, ty, stable_ptr) = match break_syntax.expr_clause(db) {
3772 ast::OptionExprClause::Empty(expr_empty) => {
3773 (None, unit_ty(db), expr_empty.stable_ptr(db).untyped())
3774 }
3775 ast::OptionExprClause::ExprClause(expr_clause) => {
3776 let expr_syntax = expr_clause.expr(db);
3777 let expr = compute_expr_semantic(ctx, &expr_syntax);
3778
3779 (Some(expr.id), expr.ty(), expr.stable_ptr().untyped())
3780 }
3781 };
3782 let ty = ctx.reduce_ty(ty);
3783
3784 if !ctx.is_inside_loop() {
3785 return Err(ctx
3786 .diagnostics
3787 .report(break_syntax.stable_ptr(db), BreakOnlyAllowedInsideALoop));
3788 }
3789
3790 if let Some(inner_ctx) = &mut ctx.inner_ctx {
3791 match &mut inner_ctx.kind {
3792 InnerContextKind::Loop { type_merger, .. } => {
3793 type_merger.try_merge_types(
3794 ctx.db,
3795 ctx.diagnostics,
3796 &mut ctx.resolver.inference(),
3797 ty,
3798 stable_ptr,
3799 );
3800 }
3801 InnerContextKind::While | InnerContextKind::For => {
3802 if expr_option.is_some() {
3803 ctx.diagnostics.report(
3804 break_syntax.stable_ptr(db),
3805 BreakWithValueOnlyAllowedInsideALoop,
3806 );
3807 };
3808 }
3809 InnerContextKind::Closure => unreachable!("Not inside a loop."),
3810 }
3811 }
3812
3813 semantic::Statement::Break(semantic::StatementBreak {
3814 expr_option,
3815 stable_ptr: syntax.stable_ptr(db),
3816 })
3817 }
3818 ast::Statement::Item(stmt_item_syntax) => {
3819 let item_syntax = &stmt_item_syntax.item(db);
3820 match item_syntax {
3821 ast::ModuleItem::Constant(const_syntax) => {
3822 let lhs = const_syntax.type_clause(db).ty(db);
3823 let rhs = const_syntax.value(db);
3824 let rhs_expr = compute_expr_semantic(ctx, &rhs);
3825 let explicit_type = resolve_type_ex(
3826 db,
3827 ctx.diagnostics,
3828 &mut ctx.resolver,
3829 &lhs,
3830 ResolutionContext::Statement(&mut ctx.environment),
3831 );
3832 let rhs_resolved_expr = resolve_const_expr_and_evaluate(
3833 db,
3834 ctx,
3835 &rhs_expr,
3836 stmt_item_syntax.stable_ptr(db).untyped(),
3837 explicit_type,
3838 false,
3839 );
3840 let name_syntax = const_syntax.name(db);
3841 let name = name_syntax.text(db);
3842 let rhs_id = StatementConstLongId(
3843 ctx.resolver.module_file_id,
3844 const_syntax.stable_ptr(db),
3845 );
3846 let var_def = Binding::LocalItem(LocalItem {
3847 id: StatementItemId::Constant(rhs_id.intern(db)),
3848 kind: StatementItemKind::Constant(
3849 db.intern_const_value(rhs_resolved_expr.clone()),
3850 rhs_resolved_expr.ty(db)?,
3851 ),
3852 });
3853 add_item_to_statement_environment(
3854 ctx,
3855 name,
3856 var_def,
3857 name_syntax.stable_ptr(db),
3858 );
3859 }
3860 ast::ModuleItem::Use(use_syntax) => {
3861 for leaf in get_all_path_leaves(db, use_syntax) {
3862 let stable_ptr = leaf.stable_ptr(db);
3863 let segments = get_use_path_segments(db, ast::UsePath::Leaf(leaf))?;
3864 let resolved_item = ctx.resolver.resolve_generic_path(
3865 ctx.diagnostics,
3866 segments,
3867 NotFoundItemType::Identifier,
3868 ResolutionContext::Statement(&mut ctx.environment),
3869 )?;
3870 let var_def_id = StatementItemId::Use(
3871 StatementUseLongId(ctx.resolver.module_file_id, stable_ptr).intern(db),
3872 );
3873 let name = var_def_id.name(db);
3874 match resolved_item {
3875 ResolvedGenericItem::GenericConstant(const_id) => {
3876 let var_def = Binding::LocalItem(LocalItem {
3877 id: var_def_id,
3878 kind: StatementItemKind::Constant(
3879 db.constant_const_value(const_id)?,
3880 db.constant_const_type(const_id)?,
3881 ),
3882 });
3883 add_item_to_statement_environment(ctx, name, var_def, stable_ptr);
3884 }
3885 ResolvedGenericItem::GenericType(generic_type_id) => {
3886 add_type_to_statement_environment(
3887 ctx,
3888 name,
3889 ResolvedGenericItem::GenericType(generic_type_id),
3890 stable_ptr,
3891 );
3892 }
3893 ResolvedGenericItem::Module(_)
3894 | ResolvedGenericItem::GenericFunction(_)
3895 | ResolvedGenericItem::GenericTypeAlias(_)
3896 | ResolvedGenericItem::GenericImplAlias(_)
3897 | ResolvedGenericItem::Variant(_)
3898 | ResolvedGenericItem::Trait(_)
3899 | ResolvedGenericItem::Impl(_)
3900 | ResolvedGenericItem::Variable(_)
3901 | ResolvedGenericItem::TraitItem(_) => {
3902 return Err(ctx
3903 .diagnostics
3904 .report(stable_ptr, UnsupportedUseItemInStatement));
3905 }
3906 }
3907 }
3908 }
3909 ast::ModuleItem::Module(_) => {
3910 unreachable!("Modules are not supported inside a function.")
3911 }
3912 ast::ModuleItem::FreeFunction(_) => {
3913 unreachable!("FreeFunction type not supported.")
3914 }
3915 ast::ModuleItem::ExternFunction(_) => {
3916 unreachable!("ExternFunction type not supported.")
3917 }
3918 ast::ModuleItem::ExternType(_) => unreachable!("ExternType type not supported."),
3919 ast::ModuleItem::Trait(_) => unreachable!("Trait type not supported."),
3920 ast::ModuleItem::Impl(_) => unreachable!("Impl type not supported."),
3921 ast::ModuleItem::ImplAlias(_) => unreachable!("ImplAlias type not supported."),
3922 ast::ModuleItem::Struct(_) => unreachable!("Struct type not supported."),
3923 ast::ModuleItem::Enum(_) => unreachable!("Enum type not supported."),
3924 ast::ModuleItem::TypeAlias(_) => unreachable!("TypeAlias type not supported."),
3925 ast::ModuleItem::InlineMacro(_) => unreachable!("InlineMacro type not supported."),
3926 ast::ModuleItem::HeaderDoc(_) => unreachable!("HeaderDoc type not supported."),
3927 ast::ModuleItem::Missing(_) => unreachable!("Missing type not supported."),
3928 }
3929 semantic::Statement::Item(semantic::StatementItem { stable_ptr: syntax.stable_ptr(db) })
3930 }
3931 ast::Statement::Missing(_) => todo!(),
3932 };
3933 ctx.resolver.data.feature_config.restore(feature_restore);
3934 Ok(ctx.arenas.statements.alloc(statement))
3935}
3936
3937fn add_item_to_statement_environment(
3940 ctx: &mut ComputationContext<'_>,
3941 name: SmolStr,
3942 var_def: Binding,
3943 stable_ptr: impl Into<SyntaxStablePtrId>,
3944) {
3945 if let Some(old_var) = ctx.environment.variables.insert(name.clone(), var_def.clone()) {
3946 ctx.diagnostics.report(
3947 stable_ptr,
3948 match old_var {
3949 Binding::LocalItem(_) => MultipleConstantDefinition(name),
3950 Binding::LocalVar(_) | Binding::Param(_) => MultipleDefinitionforBinding(name),
3951 },
3952 );
3953 }
3954 ctx.semantic_defs.insert(var_def.id(), var_def);
3955}
3956
3957fn add_type_to_statement_environment(
3960 ctx: &mut ComputationContext<'_>,
3961 name: SmolStr,
3962 resolved_generic_item: ResolvedGenericItem,
3963 stable_ptr: impl Into<SyntaxStablePtrId> + std::marker::Copy,
3964) {
3965 if ctx
3966 .environment
3967 .use_items
3968 .insert(
3969 name.clone(),
3970 StatementGenericItemData { resolved_generic_item, stable_ptr: stable_ptr.into() },
3971 )
3972 .is_some()
3973 {
3974 ctx.diagnostics.report(stable_ptr, MultipleGenericItemDefinition(name));
3975 }
3976}
3977
3978fn compute_bool_condition_semantic(
3981 ctx: &mut ComputationContext<'_>,
3982 condition_syntax: &ast::Expr,
3983) -> ExprAndId {
3984 let condition = compute_expr_semantic(ctx, condition_syntax);
3985 let inference = &mut ctx.resolver.inference();
3986 let _ = inference.conform_ty_for_diag(
3987 condition.ty(),
3988 core_bool_ty(ctx.db),
3989 ctx.diagnostics,
3990 || condition.stable_ptr().untyped(),
3991 |condition_ty, _expected_ty| ConditionNotBool(condition_ty),
3992 );
3993 condition
3994}
3995
3996fn check_struct_member_is_visible(
3998 ctx: &mut ComputationContext<'_>,
3999 member: &Member,
4000 stable_ptr: SyntaxStablePtrId,
4001 member_name: &SmolStr,
4002) {
4003 let db = ctx.db;
4004 let containing_module_id = member.id.parent_module(db);
4005 if ctx.resolver.ignore_visibility_checks(containing_module_id) {
4006 return;
4007 }
4008 let user_module_id = ctx.resolver.module_file_id.0;
4009 if !visibility::peek_visible_in(db, member.visibility, containing_module_id, user_module_id) {
4010 ctx.diagnostics.report(stable_ptr, MemberNotVisible(member_name.clone()));
4011 }
4012}
4013
4014fn validate_statement_attributes(ctx: &mut ComputationContext<'_>, syntax: &ast::Statement) {
4017 let allowed_attributes = ctx.db.allowed_statement_attributes();
4018 let mut diagnostics = vec![];
4019 validate_attributes_flat(
4020 ctx.db,
4021 &allowed_attributes,
4022 &OrderedHashSet::default(),
4023 syntax,
4024 &mut diagnostics,
4025 );
4026 for diagnostic in diagnostics {
4028 ctx.diagnostics
4029 .report(diagnostic.stable_ptr, SemanticDiagnosticKind::UnknownStatementAttribute);
4030 }
4031}
4032
4033fn function_parameter_types(
4035 ctx: &mut ComputationContext<'_>,
4036 function: FunctionId,
4037) -> Maybe<impl Iterator<Item = TypeId>> {
4038 let signature = ctx.db.concrete_function_signature(function)?;
4039 let param_types = signature.params.into_iter().map(|param| param.ty);
4040 Ok(param_types)
4041}
4042
4043fn match_method_to_traits(
4047 db: &dyn SemanticGroup,
4048 ty: semantic::TypeId,
4049 method_name: &SmolStr,
4050 lookup_context: ImplLookupContext,
4051 module_file_id: ModuleFileId,
4052 stable_ptr: SyntaxStablePtrId,
4053) -> Vec<String> {
4054 let visible_traits = db
4055 .visible_traits_from_module(module_file_id)
4056 .unwrap_or_else(|| Arc::new(OrderedHashMap::default()));
4057
4058 visible_traits
4059 .iter()
4060 .filter_map(|(trait_id, path)| {
4061 let mut data = InferenceData::new(InferenceId::NoContext);
4062 let mut inference = data.inference(db);
4063 let trait_function =
4064 db.trait_function_by_name(*trait_id, method_name.clone()).ok()??;
4065 let (concrete_trait_id, _) = inference.infer_concrete_trait_by_self(
4066 trait_function,
4067 ty,
4068 &lookup_context,
4069 Some(stable_ptr),
4070 |_| {},
4071 )?;
4072 inference.solve().ok();
4073 match inference.trait_solution_set(
4074 concrete_trait_id,
4075 ImplVarTraitItemMappings::default(),
4076 lookup_context.clone(),
4077 ) {
4078 Ok(SolutionSet::Unique(_) | SolutionSet::Ambiguous(_)) => Some(path.clone()),
4079 _ => None,
4080 }
4081 })
4082 .collect()
4083}