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