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 if !ctx.reduce_ty(expr.ty()).is_var_free(ctx.db) {
1958 ctx.resolver.inference().solve().ok();
1961 }
1962 let info = ctx.db.core_info();
1963 let candidate_traits = [info.index_trt, info.index_view_trt];
1964 let (function_id, _, fixed_expr, mutability) = compute_method_function_call_data(
1965 ctx,
1966 &candidate_traits[..],
1967 "index".into(),
1968 expr,
1969 syntax.into(),
1970 None,
1971 |ty, _, inference_errors| Some(NoImplementationOfIndexOperator { ty, inference_errors }),
1972 |ty, _, _| Some(MultipleImplementationOfIndexOperator(ty)),
1973 )?;
1974
1975 expr_function_call(
1976 ctx,
1977 function_id,
1978 vec![
1979 NamedArg(fixed_expr, None, mutability),
1980 NamedArg(index_expr, None, Mutability::Immutable),
1981 ],
1982 syntax,
1983 index_expr_syntax.stable_ptr(),
1984 )
1985}
1986
1987#[expect(clippy::too_many_arguments)]
1992fn compute_method_function_call_data(
1993 ctx: &mut ComputationContext<'_>,
1994 candidate_traits: &[TraitId],
1995 func_name: SmolStr,
1996 self_expr: ExprAndId,
1997 method_syntax: SyntaxStablePtrId,
1998 generic_args_syntax: Option<Vec<ast::GenericArg>>,
1999 no_implementation_diagnostic: impl Fn(
2000 TypeId,
2001 SmolStr,
2002 TraitInferenceErrors,
2003 ) -> Option<SemanticDiagnosticKind>,
2004 multiple_trait_diagnostic: fn(
2005 TypeId,
2006 TraitFunctionId,
2007 TraitFunctionId,
2008 ) -> Option<SemanticDiagnosticKind>,
2009) -> Maybe<(FunctionId, TraitId, ExprAndId, Mutability)> {
2010 let expr_ptr = self_expr.stable_ptr();
2011 let self_ty = ctx.reduce_ty(self_expr.ty());
2012 let mut inference_errors = vec![];
2016 let (candidates, mut fixed_expr, fixed_ty) = get_method_function_candidates(
2017 ctx,
2018 candidate_traits,
2019 &func_name,
2020 self_expr,
2021 method_syntax,
2022 expr_ptr,
2023 self_ty,
2024 &mut inference_errors,
2025 )?;
2026
2027 let trait_function_id = match candidates[..] {
2028 [] => {
2029 return Err(no_implementation_diagnostic(
2030 self_ty,
2031 func_name,
2032 TraitInferenceErrors { traits_and_errors: inference_errors },
2033 )
2034 .map(|diag| ctx.diagnostics.report(method_syntax, diag))
2035 .unwrap_or_else(skip_diagnostic));
2036 }
2037 [trait_function_id] => trait_function_id,
2038 [trait_function_id0, trait_function_id1, ..] => {
2039 return Err(multiple_trait_diagnostic(
2040 fixed_ty,
2041 trait_function_id0,
2042 trait_function_id1,
2043 )
2044 .map(|diag| ctx.diagnostics.report(method_syntax, diag))
2045 .unwrap_or_else(skip_diagnostic));
2046 }
2047 };
2048 let (function_id, n_snapshots) =
2049 infer_impl_by_self(ctx, trait_function_id, fixed_ty, method_syntax, generic_args_syntax)?;
2050
2051 let signature = ctx.db.trait_function_signature(trait_function_id).unwrap();
2052 let first_param = signature.params.into_iter().next().unwrap();
2053 for _ in 0..n_snapshots {
2054 let ty = TypeLongId::Snapshot(fixed_expr.ty()).intern(ctx.db);
2055 let expr = Expr::Snapshot(ExprSnapshot { inner: fixed_expr.id, ty, stable_ptr: expr_ptr });
2056 fixed_expr = ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) };
2057 }
2058
2059 Ok((
2060 function_id,
2061 trait_function_id.trait_id(ctx.db.upcast()),
2062 fixed_expr,
2063 first_param.mutability,
2064 ))
2065}
2066
2067#[expect(clippy::too_many_arguments)]
2070fn get_method_function_candidates(
2071 ctx: &mut ComputationContext<'_>,
2072 candidate_traits: &[TraitId],
2073 func_name: &SmolStr,
2074 self_expr: ExprAndId,
2075 method_syntax: SyntaxStablePtrId,
2076 expr_ptr: ExprPtr,
2077 self_ty: TypeId,
2078 inference_errors: &mut Vec<(TraitFunctionId, InferenceError)>,
2079) -> Result<(Vec<TraitFunctionId>, ExprAndId, TypeId), cairo_lang_diagnostics::DiagnosticAdded> {
2080 let mut candidates = filter_candidate_traits(
2081 ctx,
2082 inference_errors,
2083 self_ty,
2084 candidate_traits,
2085 func_name.clone(),
2086 method_syntax,
2087 );
2088 if !candidates.is_empty() {
2089 return Ok((candidates, self_expr, self_ty));
2090 }
2091
2092 let mut fixed_expr = self_expr;
2093 let mut fixed_ty = self_ty;
2094
2095 let base_var = match &fixed_expr.expr {
2096 Expr::Var(expr_var) => Some(expr_var.var),
2097 Expr::MemberAccess(ExprMemberAccess { member_path: Some(member_path), .. }) => {
2098 Some(member_path.base_var())
2099 }
2100 _ => None,
2101 };
2102 let is_mut_var = base_var
2103 .filter(|var_id| matches!(ctx.semantic_defs.get(var_id), Some(var) if var.is_mut()))
2104 .is_some();
2105
2106 let deref_chain = ctx.db.deref_chain(self_ty, is_mut_var)?;
2107
2108 for deref_info in deref_chain.derefs.iter() {
2109 let derefed_expr = expr_function_call(
2110 ctx,
2111 deref_info.function_id,
2112 vec![NamedArg(fixed_expr, None, deref_info.self_mutability)],
2113 method_syntax,
2114 expr_ptr,
2115 )?;
2116
2117 fixed_expr =
2118 ExprAndId { expr: derefed_expr.clone(), id: ctx.arenas.exprs.alloc(derefed_expr) };
2119
2120 candidates = filter_candidate_traits(
2121 ctx,
2122 inference_errors,
2123 deref_info.target_ty,
2124 candidate_traits,
2125 func_name.clone(),
2126 method_syntax,
2127 );
2128 if !candidates.is_empty() {
2129 fixed_ty = deref_info.target_ty;
2130 break;
2131 }
2132 }
2133
2134 Ok((candidates, fixed_expr, fixed_ty))
2135}
2136
2137pub fn compute_pattern_semantic(
2141 ctx: &mut ComputationContext<'_>,
2142 syntax: &ast::Pattern,
2143 ty: TypeId,
2144 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2145) -> PatternAndId {
2146 let pat = maybe_compute_pattern_semantic(ctx, syntax, ty, or_pattern_variables_map);
2147 let pat = pat.unwrap_or_else(|diag_added| {
2148 Pattern::Missing(PatternMissing {
2149 ty: TypeId::missing(ctx.db, diag_added),
2150 stable_ptr: syntax.stable_ptr(),
2151 diag_added,
2152 })
2153 });
2154 let id = ctx.arenas.patterns.alloc(pat.clone());
2155 PatternAndId { pattern: pat, id }
2156}
2157
2158fn maybe_compute_pattern_semantic(
2160 ctx: &mut ComputationContext<'_>,
2161 pattern_syntax: &ast::Pattern,
2162 ty: TypeId,
2163 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2164) -> Maybe<Pattern> {
2165 let syntax_db = ctx.db.upcast();
2167 let ty = ctx.reduce_ty(ty);
2168 let stable_ptr = pattern_syntax.into();
2169 let pattern = match pattern_syntax {
2170 ast::Pattern::Underscore(otherwise_pattern) => {
2171 Pattern::Otherwise(PatternOtherwise { ty, stable_ptr: otherwise_pattern.stable_ptr() })
2172 }
2173 ast::Pattern::Literal(literal_pattern) => {
2174 let literal = literal_to_semantic(ctx, literal_pattern)?;
2175 Pattern::Literal(PatternLiteral {
2176 literal,
2177 stable_ptr: literal_pattern.stable_ptr().into(),
2178 })
2179 }
2180 ast::Pattern::ShortString(short_string_pattern) => {
2181 let literal = short_string_to_semantic(ctx, short_string_pattern)?;
2182 Pattern::Literal(PatternLiteral {
2183 literal,
2184 stable_ptr: short_string_pattern.stable_ptr().into(),
2185 })
2186 }
2187 ast::Pattern::String(string_pattern) => {
2188 let string_literal = string_literal_to_semantic(ctx, string_pattern)?;
2189 Pattern::StringLiteral(PatternStringLiteral {
2190 string_literal,
2191 stable_ptr: string_pattern.stable_ptr().into(),
2192 })
2193 }
2194 ast::Pattern::Enum(enum_pattern) => {
2195 let path = enum_pattern.path(syntax_db);
2196 let item = ctx.resolver.resolve_generic_path(
2197 ctx.diagnostics,
2198 &path,
2199 NotFoundItemType::Identifier,
2200 Some(&mut ctx.environment),
2201 )?;
2202 let generic_variant = try_extract_matches!(item, ResolvedGenericItem::Variant)
2203 .ok_or_else(|| ctx.diagnostics.report(&path, NotAVariant))?;
2204
2205 let (concrete_enum, n_snapshots) = extract_concrete_enum_from_pattern_and_validate(
2206 ctx,
2207 pattern_syntax,
2208 ty,
2209 generic_variant.enum_id,
2210 )?;
2211
2212 let concrete_variant = ctx
2214 .db
2215 .concrete_enum_variant(concrete_enum, &generic_variant)
2216 .map_err(|_| ctx.diagnostics.report(&path, UnknownEnum))?;
2217
2218 let inner_ty = wrap_in_snapshots(ctx.db, concrete_variant.ty, n_snapshots);
2220
2221 let inner_pattern = match enum_pattern.pattern(syntax_db) {
2222 ast::OptionPatternEnumInnerPattern::Empty(_) => None,
2223 ast::OptionPatternEnumInnerPattern::PatternEnumInnerPattern(p) => {
2224 let pattern = compute_pattern_semantic(
2225 ctx,
2226 &p.pattern(syntax_db),
2227 inner_ty,
2228 or_pattern_variables_map,
2229 );
2230 Some(pattern.id)
2231 }
2232 };
2233
2234 Pattern::EnumVariant(PatternEnumVariant {
2235 variant: concrete_variant,
2236 inner_pattern,
2237 ty,
2238 stable_ptr: enum_pattern.stable_ptr().into(),
2239 })
2240 }
2241 ast::Pattern::Path(path) => {
2242 let item_result = ctx.resolver.resolve_generic_path(
2243 &mut Default::default(),
2244 path,
2245 NotFoundItemType::Identifier,
2246 Some(&mut ctx.environment),
2247 );
2248 if let Ok(item) = item_result {
2249 if let Some(generic_variant) =
2250 try_extract_matches!(item, ResolvedGenericItem::Variant)
2251 {
2252 let (concrete_enum, _n_snapshots) =
2253 extract_concrete_enum_from_pattern_and_validate(
2254 ctx,
2255 pattern_syntax,
2256 ty,
2257 generic_variant.enum_id,
2258 )?;
2259 let concrete_variant = ctx
2260 .db
2261 .concrete_enum_variant(concrete_enum, &generic_variant)
2262 .map_err(|_| ctx.diagnostics.report(path, UnknownEnum))?;
2263 return Ok(Pattern::EnumVariant(PatternEnumVariant {
2264 variant: concrete_variant,
2265 inner_pattern: None,
2266 ty,
2267 stable_ptr: path.stable_ptr().into(),
2268 }));
2269 }
2270 }
2271
2272 if path.elements(syntax_db).len() > 1 {
2276 return Err(ctx.diagnostics.report(path, Unsupported));
2277 }
2278 let identifier = path.elements(syntax_db)[0].identifier_ast(syntax_db);
2280 create_variable_pattern(
2281 ctx,
2282 identifier,
2283 &[],
2284 ty,
2285 path.stable_ptr().into(),
2286 or_pattern_variables_map,
2287 )
2288 }
2289 ast::Pattern::Identifier(identifier) => create_variable_pattern(
2290 ctx,
2291 identifier.name(syntax_db),
2292 &identifier.modifiers(syntax_db).elements(syntax_db),
2293 ty,
2294 identifier.stable_ptr().into(),
2295 or_pattern_variables_map,
2296 ),
2297 ast::Pattern::Struct(pattern_struct) => {
2298 let pattern_ty = try_extract_matches!(
2299 ctx.resolver.resolve_concrete_path_ex(
2300 ctx.diagnostics,
2301 &pattern_struct.path(syntax_db),
2302 NotFoundItemType::Type,
2303 Some(&mut ctx.environment)
2304 )?,
2305 ResolvedConcreteItem::Type
2306 )
2307 .ok_or_else(|| ctx.diagnostics.report(&pattern_struct.path(syntax_db), NotAType))?;
2308 let inference = &mut ctx.resolver.inference();
2309 inference.conform_ty(pattern_ty, peel_snapshots(ctx.db, ty).1.intern(ctx.db)).map_err(
2310 |err_set| inference.report_on_pending_error(err_set, ctx.diagnostics, stable_ptr),
2311 )?;
2312 let ty = ctx.reduce_ty(ty);
2313 let (n_snapshots, long_ty) = peel_snapshots(ctx.db, ty);
2315
2316 let concrete_struct_id = try_extract_matches!(long_ty, TypeLongId::Concrete)
2318 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Struct))
2319 .ok_or(())
2320 .or_else(|_| {
2321 ty.check_not_missing(ctx.db)?;
2324 Err(ctx.diagnostics.report(pattern_struct, UnexpectedStructPattern(ty)))
2325 })?;
2326 let pattern_param_asts = pattern_struct.params(syntax_db).elements(syntax_db);
2327 let struct_id = concrete_struct_id.struct_id(ctx.db);
2328 let mut members = ctx.db.concrete_struct_members(concrete_struct_id)?.as_ref().clone();
2329 let mut used_members = UnorderedHashSet::<_>::default();
2330 let mut get_member = |ctx: &mut ComputationContext<'_>,
2331 member_name: SmolStr,
2332 stable_ptr: SyntaxStablePtrId| {
2333 let member = members.swap_remove(&member_name).on_none(|| {
2334 ctx.diagnostics.report(
2335 stable_ptr,
2336 if used_members.contains(&member_name) {
2337 StructMemberRedefinition { struct_id, member_name: member_name.clone() }
2338 } else {
2339 NoSuchStructMember { struct_id, member_name: member_name.clone() }
2340 },
2341 );
2342 })?;
2343 check_struct_member_is_visible(ctx, &member, stable_ptr, &member_name);
2344 used_members.insert(member_name);
2345 Some(member)
2346 };
2347 let mut field_patterns = vec![];
2348 let mut has_tail = false;
2349 for pattern_param_ast in pattern_param_asts {
2350 match pattern_param_ast {
2351 PatternStructParam::Single(single) => {
2352 let name = single.name(syntax_db);
2353 let Some(member) =
2354 get_member(ctx, name.text(syntax_db), name.stable_ptr().untyped())
2355 else {
2356 continue;
2357 };
2358 let ty = wrap_in_snapshots(ctx.db, member.ty, n_snapshots);
2359 let pattern = create_variable_pattern(
2360 ctx,
2361 name,
2362 &single.modifiers(syntax_db).elements(syntax_db),
2363 ty,
2364 single.stable_ptr().into(),
2365 or_pattern_variables_map,
2366 );
2367 field_patterns.push((member, ctx.arenas.patterns.alloc(pattern)));
2368 }
2369 PatternStructParam::WithExpr(with_expr) => {
2370 let name = with_expr.name(syntax_db);
2371 let Some(member) =
2372 get_member(ctx, name.text(syntax_db), name.stable_ptr().untyped())
2373 else {
2374 continue;
2375 };
2376 let ty = wrap_in_snapshots(ctx.db, member.ty, n_snapshots);
2377 let pattern = compute_pattern_semantic(
2378 ctx,
2379 &with_expr.pattern(syntax_db),
2380 ty,
2381 or_pattern_variables_map,
2382 );
2383 field_patterns.push((member, pattern.id));
2384 }
2385 PatternStructParam::Tail(_) => {
2386 has_tail = true;
2387 }
2388 }
2389 }
2390 if !has_tail {
2391 for (member_name, _) in members.iter() {
2392 ctx.diagnostics.report(pattern_struct, MissingMember(member_name.clone()));
2393 }
2394 }
2395 Pattern::Struct(PatternStruct {
2396 concrete_struct_id,
2397 field_patterns,
2398 ty,
2399 n_snapshots,
2400 stable_ptr: pattern_struct.stable_ptr(),
2401 })
2402 }
2403 ast::Pattern::Tuple(_) => maybe_compute_tuple_like_pattern_semantic(
2404 ctx,
2405 pattern_syntax,
2406 ty,
2407 or_pattern_variables_map,
2408 |ty: TypeId| UnexpectedTuplePattern(ty),
2409 |expected, actual| WrongNumberOfTupleElements { expected, actual },
2410 )?,
2411 ast::Pattern::FixedSizeArray(_) => maybe_compute_tuple_like_pattern_semantic(
2412 ctx,
2413 pattern_syntax,
2414 ty,
2415 or_pattern_variables_map,
2416 |ty: TypeId| UnexpectedFixedSizeArrayPattern(ty),
2417 |expected, actual| WrongNumberOfFixedSizeArrayElements { expected, actual },
2418 )?,
2419 ast::Pattern::False(pattern_false) => {
2420 let enum_expr = extract_matches!(
2421 false_literal_expr(ctx, pattern_false.stable_ptr().into()),
2422 Expr::EnumVariantCtor
2423 );
2424
2425 extract_concrete_enum_from_pattern_and_validate(
2426 ctx,
2427 pattern_syntax,
2428 ty,
2429 enum_expr.variant.concrete_enum_id.enum_id(ctx.db),
2430 )?;
2431
2432 Pattern::EnumVariant(PatternEnumVariant {
2433 variant: enum_expr.variant,
2434 stable_ptr: pattern_false.stable_ptr().into(),
2435 ty,
2436 inner_pattern: None,
2437 })
2438 }
2439 ast::Pattern::True(pattern_true) => {
2440 let enum_expr = extract_matches!(
2441 true_literal_expr(ctx, pattern_true.stable_ptr().into()),
2442 Expr::EnumVariantCtor
2443 );
2444 extract_concrete_enum_from_pattern_and_validate(
2445 ctx,
2446 pattern_syntax,
2447 ty,
2448 enum_expr.variant.concrete_enum_id.enum_id(ctx.db),
2449 )?;
2450
2451 Pattern::EnumVariant(PatternEnumVariant {
2452 variant: enum_expr.variant,
2453 stable_ptr: pattern_true.stable_ptr().into(),
2454 ty,
2455 inner_pattern: None,
2456 })
2457 }
2458 };
2459 let inference = &mut ctx.resolver.inference();
2460 inference.conform_ty(pattern.ty(), ty).map_err(|err_set| {
2461 inference.report_on_pending_error(err_set, ctx.diagnostics, stable_ptr)
2462 })?;
2463 Ok(pattern)
2464}
2465
2466fn maybe_compute_tuple_like_pattern_semantic(
2469 ctx: &mut ComputationContext<'_>,
2470 pattern_syntax: &ast::Pattern,
2471 ty: TypeId,
2472 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2473 unexpected_pattern: fn(TypeId) -> SemanticDiagnosticKind,
2474 wrong_number_of_elements: fn(usize, usize) -> SemanticDiagnosticKind,
2475) -> Maybe<Pattern> {
2476 let (n_snapshots, long_ty) = finalized_snapshot_peeled_ty(ctx, ty, pattern_syntax)?;
2477 match (pattern_syntax, &long_ty) {
2479 (ast::Pattern::Tuple(_), TypeLongId::Tuple(_) | TypeLongId::Var(_))
2480 | (
2481 ast::Pattern::FixedSizeArray(_),
2482 TypeLongId::FixedSizeArray { .. } | TypeLongId::Var(_),
2483 ) => {}
2484 _ => {
2485 return Err(ctx.diagnostics.report(pattern_syntax, unexpected_pattern(ty)));
2486 }
2487 };
2488 let patterns_syntax = match pattern_syntax {
2489 ast::Pattern::Tuple(pattern_tuple) => {
2490 pattern_tuple.patterns(ctx.db.upcast()).elements(ctx.db.upcast())
2491 }
2492 ast::Pattern::FixedSizeArray(pattern_fixed_size_array) => {
2493 pattern_fixed_size_array.patterns(ctx.db.upcast()).elements(ctx.db.upcast())
2494 }
2495 _ => unreachable!(),
2496 };
2497 let inner_tys = match long_ty {
2498 TypeLongId::Tuple(inner_tys) => inner_tys,
2499 TypeLongId::FixedSizeArray { type_id: inner_ty, size } => {
2500 let size = if let ConstValue::Int(value, _) = size.lookup_intern(ctx.db) {
2501 value.to_usize().expect("Fixed sized array size must always be usize.")
2502 } else {
2503 let inference = &mut ctx.resolver.inference();
2504 let expected_size =
2505 ConstValue::Int(patterns_syntax.len().into(), get_usize_ty(ctx.db))
2506 .intern(ctx.db);
2507 if let Err(err) = inference.conform_const(size, expected_size) {
2508 let _ = inference.report_on_pending_error(
2509 err,
2510 ctx.diagnostics,
2511 pattern_syntax.stable_ptr().untyped(),
2512 );
2513 }
2514 patterns_syntax.len()
2515 };
2516
2517 [inner_ty].repeat(size)
2518 }
2519 TypeLongId::Var(_) => {
2520 let inference = &mut ctx.resolver.inference();
2521 let (inner_tys, tuple_like_ty) = if matches!(pattern_syntax, ast::Pattern::Tuple(_)) {
2522 let inner_tys: Vec<_> = patterns_syntax
2523 .iter()
2524 .map(|e| inference.new_type_var(Some(e.stable_ptr().untyped())))
2525 .collect();
2526 (inner_tys.clone(), TypeLongId::Tuple(inner_tys))
2527 } else {
2528 let var = inference.new_type_var(Some(pattern_syntax.stable_ptr().untyped()));
2529 (
2530 vec![var; patterns_syntax.len()],
2531 TypeLongId::FixedSizeArray {
2532 type_id: var,
2533 size: ConstValue::Int(patterns_syntax.len().into(), get_usize_ty(ctx.db))
2534 .intern(ctx.db),
2535 },
2536 )
2537 };
2538 match inference.conform_ty(ty, tuple_like_ty.intern(ctx.db)) {
2539 Ok(_) => {}
2540 Err(_) => unreachable!("As the type is a var, conforming should always succeed."),
2541 }
2542 inner_tys
2543 }
2544 _ => unreachable!(),
2545 };
2546 let size = inner_tys.len();
2547 if size != patterns_syntax.len() {
2548 return Err(ctx
2549 .diagnostics
2550 .report(pattern_syntax, wrong_number_of_elements(size, patterns_syntax.len())));
2551 }
2552 let pattern_options = zip_eq(patterns_syntax, inner_tys).map(|(pattern_ast, ty)| {
2553 let ty = wrap_in_snapshots(ctx.db, ty, n_snapshots);
2554 let pattern = compute_pattern_semantic(ctx, &pattern_ast, ty, or_pattern_variables_map);
2555 Ok(pattern.id)
2556 });
2557 let field_patterns: Vec<_> = pattern_options.collect::<Maybe<_>>()?;
2559 Ok(match pattern_syntax {
2560 ast::Pattern::Tuple(syntax) => {
2561 Pattern::Tuple(PatternTuple { field_patterns, ty, stable_ptr: syntax.stable_ptr() })
2562 }
2563 ast::Pattern::FixedSizeArray(syntax) => Pattern::FixedSizeArray(PatternFixedSizeArray {
2564 elements_patterns: field_patterns,
2565 ty,
2566 stable_ptr: syntax.stable_ptr(),
2567 }),
2568 _ => unreachable!(),
2569 })
2570}
2571
2572fn extract_concrete_enum_from_pattern_and_validate(
2574 ctx: &mut ComputationContext<'_>,
2575 pattern: &ast::Pattern,
2576 ty: TypeId,
2577 enum_id: EnumId,
2578) -> Maybe<(ConcreteEnumId, usize)> {
2579 let (n_snapshots, long_ty) = finalized_snapshot_peeled_ty(ctx, ty, pattern)?;
2581
2582 let concrete_enum = try_extract_matches!(long_ty, TypeLongId::Concrete)
2584 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Enum))
2585 .ok_or(())
2586 .or_else(|_| {
2587 ty.check_not_missing(ctx.db)?;
2590 Err(ctx.diagnostics.report(pattern, UnexpectedEnumPattern(ty)))
2591 })?;
2592 if enum_id != concrete_enum.enum_id(ctx.db) {
2594 return Err(ctx.diagnostics.report(
2595 pattern,
2596 WrongEnum { expected_enum: concrete_enum.enum_id(ctx.db), actual_enum: enum_id },
2597 ));
2598 }
2599 Ok((concrete_enum, n_snapshots))
2600}
2601
2602fn create_variable_pattern(
2604 ctx: &mut ComputationContext<'_>,
2605 identifier: ast::TerminalIdentifier,
2606 modifier_list: &[ast::Modifier],
2607 ty: TypeId,
2608 stable_ptr: ast::PatternPtr,
2609 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2610) -> Pattern {
2611 let syntax_db = ctx.db.upcast();
2612
2613 let var_id = match or_pattern_variables_map.get(&identifier.text(syntax_db)) {
2614 Some(var) => var.id,
2615 None => LocalVarLongId(ctx.resolver.module_file_id, identifier.stable_ptr()).intern(ctx.db),
2616 };
2617 let is_mut = match compute_mutability(ctx.diagnostics, syntax_db, modifier_list) {
2618 Mutability::Immutable => false,
2619 Mutability::Mutable => true,
2620 Mutability::Reference => {
2621 ctx.diagnostics.report(&identifier, ReferenceLocalVariable);
2622 false
2623 }
2624 };
2625 Pattern::Variable(PatternVariable {
2626 name: identifier.text(syntax_db),
2627 var: LocalVariable { id: var_id, ty, is_mut },
2628 stable_ptr,
2629 })
2630}
2631
2632fn struct_ctor_expr(
2634 ctx: &mut ComputationContext<'_>,
2635 ctor_syntax: &ast::ExprStructCtorCall,
2636) -> Maybe<Expr> {
2637 let db = ctx.db;
2638 let syntax_db = db.upcast();
2639 let path = ctor_syntax.path(syntax_db);
2640
2641 let ty = resolve_type_with_environment(
2643 db,
2644 ctx.diagnostics,
2645 &mut ctx.resolver,
2646 &ast::Expr::Path(path.clone()),
2647 Some(&mut ctx.environment),
2648 );
2649 ty.check_not_missing(db)?;
2650
2651 let concrete_struct_id = try_extract_matches!(ty.lookup_intern(ctx.db), TypeLongId::Concrete)
2652 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Struct))
2653 .ok_or_else(|| ctx.diagnostics.report(&path, NotAStruct))?;
2654
2655 if ty.is_phantom(db) {
2656 ctx.diagnostics.report(ctor_syntax, CannotCreateInstancesOfPhantomTypes);
2657 }
2658
2659 let members = db.concrete_struct_members(concrete_struct_id)?;
2660 let mut member_exprs: OrderedHashMap<MemberId, Option<ExprId>> = OrderedHashMap::default();
2661 let mut base_struct = None;
2662
2663 for (index, arg) in ctor_syntax
2664 .arguments(syntax_db)
2665 .arguments(syntax_db)
2666 .elements(syntax_db)
2667 .into_iter()
2668 .enumerate()
2669 {
2670 match arg {
2672 ast::StructArg::StructArgSingle(arg) => {
2673 let arg_identifier = arg.identifier(syntax_db);
2674 let arg_name = arg_identifier.text(syntax_db);
2675
2676 let Some(member) = members.get(&arg_name) else {
2678 ctx.diagnostics.report(&arg_identifier, UnknownMember);
2679 continue;
2680 };
2681 check_struct_member_is_visible(
2682 ctx,
2683 member,
2684 arg_identifier.stable_ptr().untyped(),
2685 &arg_name,
2686 );
2687
2688 let arg_expr = match arg.arg_expr(syntax_db) {
2690 ast::OptionStructArgExpr::Empty(_) => {
2691 let Ok(expr) = resolve_variable_by_name(
2692 ctx,
2693 &arg_identifier,
2694 path.stable_ptr().into(),
2695 ) else {
2696 if member_exprs.insert(member.id, None).is_some() {
2698 ctx.diagnostics
2699 .report(&arg_identifier, MemberSpecifiedMoreThanOnce);
2700 }
2701 continue;
2702 };
2703 ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) }
2704 }
2705 ast::OptionStructArgExpr::StructArgExpr(arg_expr) => {
2706 compute_expr_semantic(ctx, &arg_expr.expr(syntax_db))
2707 }
2708 };
2709
2710 if member_exprs.insert(member.id, Some(arg_expr.id)).is_some() {
2712 ctx.diagnostics.report(&arg_identifier, MemberSpecifiedMoreThanOnce);
2713 }
2714
2715 let inference = &mut ctx.resolver.inference();
2717 if inference
2718 .conform_ty_for_diag(
2719 arg_expr.ty(),
2720 member.ty,
2721 ctx.diagnostics,
2722 || arg_identifier.stable_ptr().untyped(),
2723 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
2724 )
2725 .is_err()
2726 {
2727 continue;
2728 }
2729 }
2730 ast::StructArg::StructArgTail(base_struct_syntax) => {
2731 if index
2733 != ctor_syntax
2734 .arguments(syntax_db)
2735 .arguments(syntax_db)
2736 .elements(syntax_db)
2737 .len()
2738 - 1
2739 {
2740 ctx.diagnostics.report(&base_struct_syntax, StructBaseStructExpressionNotLast);
2741 continue;
2742 }
2743 let base_struct_expr =
2744 compute_expr_semantic(ctx, &base_struct_syntax.expression(syntax_db));
2745 let inference = &mut ctx.resolver.inference();
2746 if inference
2747 .conform_ty_for_diag(
2748 base_struct_expr.ty(),
2749 ty,
2750 ctx.diagnostics,
2751 || base_struct_syntax.expression(syntax_db).stable_ptr().untyped(),
2752 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
2753 )
2754 .is_err()
2755 {
2756 continue;
2757 }
2758
2759 base_struct = Some((base_struct_expr.id, base_struct_syntax));
2760 }
2761 };
2762 }
2763
2764 for (member_name, member) in members.iter() {
2766 if !member_exprs.contains_key(&member.id) {
2767 if base_struct.is_some() {
2768 check_struct_member_is_visible(
2769 ctx,
2770 member,
2771 base_struct.clone().unwrap().1.stable_ptr().untyped(),
2772 member_name,
2773 );
2774 } else {
2775 ctx.diagnostics.report(ctor_syntax, MissingMember(member_name.clone()));
2776 }
2777 }
2778 }
2779 if members.len() == member_exprs.len() {
2780 if let Some((_, base_struct_syntax)) = base_struct {
2781 return Err(ctx
2782 .diagnostics
2783 .report(&base_struct_syntax, StructBaseStructExpressionNoEffect));
2784 }
2785 }
2786 Ok(Expr::StructCtor(ExprStructCtor {
2787 concrete_struct_id,
2788 members: member_exprs.into_iter().filter_map(|(x, y)| Some((x, y?))).collect(),
2789 base_struct: base_struct.map(|(x, _)| x),
2790 ty: TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)).intern(db),
2791 stable_ptr: ctor_syntax.stable_ptr().into(),
2792 }))
2793}
2794
2795fn get_tail_expression(
2799 syntax_db: &dyn SyntaxGroup,
2800 statements: &[ast::Statement],
2801) -> Option<ast::Expr> {
2802 let last = statements.last()?;
2803 let statement_expr = try_extract_matches!(last, ast::Statement::Expr)?;
2804 try_extract_matches!(statement_expr.semicolon(syntax_db), ast::OptionTerminalSemicolon::Empty)?;
2805 Some(statement_expr.expr(syntax_db))
2806}
2807
2808fn new_literal_expr(
2810 ctx: &mut ComputationContext<'_>,
2811 ty: Option<&str>,
2812 value: BigInt,
2813 stable_ptr: ExprPtr,
2814) -> Maybe<ExprLiteral> {
2815 if let Some(ty_str) = ty {
2816 if ty_str == "NonZero" {
2818 return Err(ctx.diagnostics.report(
2819 stable_ptr.untyped(),
2820 SemanticDiagnosticKind::WrongNumberOfArguments { expected: 1, actual: 0 },
2821 ));
2822 }
2823 let ty = try_get_core_ty_by_name(ctx.db, ty_str.into(), vec![])
2824 .map_err(|err| ctx.diagnostics.report(stable_ptr.untyped(), err))?;
2825 if let Err(err) = validate_literal(ctx.db, ty, &value) {
2826 ctx.diagnostics.report(stable_ptr, SemanticDiagnosticKind::LiteralError(err));
2827 }
2828 return Ok(ExprLiteral { value, ty, stable_ptr });
2829 };
2830 let ty = ctx.resolver.inference().new_type_var(Some(stable_ptr.untyped()));
2831
2832 let trait_id = ctx.db.core_info().numeric_literal_trt;
2834 let generic_args = vec![GenericArgumentId::Type(ty)];
2835 let concrete_trait_id = semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(ctx.db);
2836 let lookup_context = ctx.resolver.impl_lookup_context();
2837 let inference = &mut ctx.resolver.inference();
2838 inference.new_impl_var(concrete_trait_id, Some(stable_ptr.untyped()), lookup_context);
2839
2840 Ok(ExprLiteral { value, ty, stable_ptr })
2841}
2842
2843fn literal_to_semantic(
2845 ctx: &mut ComputationContext<'_>,
2846 literal_syntax: &ast::TerminalLiteralNumber,
2847) -> Maybe<ExprLiteral> {
2848 let db = ctx.db;
2849 let syntax_db = db.upcast();
2850
2851 let (value, ty) = literal_syntax.numeric_value_and_suffix(syntax_db).unwrap_or_default();
2852 let ty = ty.as_ref().map(SmolStr::as_str);
2853
2854 new_literal_expr(ctx, ty, value, literal_syntax.stable_ptr().into())
2855}
2856
2857fn short_string_to_semantic(
2859 ctx: &mut ComputationContext<'_>,
2860 short_string_syntax: &ast::TerminalShortString,
2861) -> Maybe<ExprLiteral> {
2862 let db = ctx.db;
2863 let syntax_db = db.upcast();
2864
2865 let value = short_string_syntax.numeric_value(syntax_db).unwrap_or_default();
2866
2867 let suffix = short_string_syntax.suffix(syntax_db);
2868 let suffix = suffix.as_ref().map(SmolStr::as_str);
2869
2870 new_literal_expr(ctx, suffix, value, short_string_syntax.stable_ptr().into())
2871}
2872
2873fn new_string_literal_expr(
2875 ctx: &mut ComputationContext<'_>,
2876 value: String,
2877 stable_ptr: ExprPtr,
2878) -> Maybe<ExprStringLiteral> {
2879 let ty = ctx.resolver.inference().new_type_var(Some(stable_ptr.untyped()));
2880
2881 let trait_id = ctx.db.core_info().string_literal_trt;
2882 let generic_args = vec![GenericArgumentId::Type(ty)];
2883 let concrete_trait_id = semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(ctx.db);
2884 let lookup_context = ctx.resolver.impl_lookup_context();
2885 let inference = &mut ctx.resolver.inference();
2886 inference.new_impl_var(concrete_trait_id, Some(stable_ptr.untyped()), lookup_context);
2887
2888 Ok(ExprStringLiteral { value, ty, stable_ptr })
2889}
2890
2891fn string_literal_to_semantic(
2893 ctx: &mut ComputationContext<'_>,
2894 string_syntax: &ast::TerminalString,
2895) -> Maybe<ExprStringLiteral> {
2896 let db = ctx.db;
2897 let syntax_db = db.upcast();
2898 let stable_ptr = string_syntax.stable_ptr();
2899
2900 let value = string_syntax.string_value(syntax_db).unwrap_or_default();
2901 new_string_literal_expr(ctx, value, stable_ptr.into())
2904}
2905
2906fn expr_as_identifier(
2909 ctx: &mut ComputationContext<'_>,
2910 path: &ast::ExprPath,
2911 syntax_db: &dyn SyntaxGroup,
2912) -> Maybe<SmolStr> {
2913 let segments = path.elements(syntax_db);
2914 if segments.len() == 1 {
2915 return Ok(segments[0].identifier(syntax_db));
2916 }
2917 Err(ctx.diagnostics.report(path, InvalidMemberExpression))
2918}
2919
2920fn dot_expr(
2923 ctx: &mut ComputationContext<'_>,
2924 lexpr: ExprAndId,
2925 rhs_syntax: ast::Expr,
2926 stable_ptr: ast::ExprPtr,
2927) -> Maybe<Expr> {
2928 match rhs_syntax {
2930 ast::Expr::Path(expr) => member_access_expr(ctx, lexpr, expr, stable_ptr),
2931 ast::Expr::FunctionCall(expr) => method_call_expr(ctx, lexpr, expr, stable_ptr),
2932 _ => Err(ctx.diagnostics.report(&rhs_syntax, InvalidMemberExpression)),
2933 }
2934}
2935
2936fn traits_in_context(
2938 ctx: &mut ComputationContext<'_>,
2939) -> Maybe<OrderedHashMap<TraitId, LookupItemId>> {
2940 let mut traits =
2941 ctx.db.module_usable_trait_ids(ctx.resolver.prelude_submodule())?.deref().clone();
2942 traits.extend(
2943 ctx.db
2944 .module_usable_trait_ids(ctx.resolver.module_file_id.0)?
2945 .iter()
2946 .map(|(k, v)| (*k, *v)),
2947 );
2948 Ok(traits)
2949}
2950
2951fn method_call_expr(
2955 ctx: &mut ComputationContext<'_>,
2956 lexpr: ExprAndId,
2957 expr: ast::ExprFunctionCall,
2958 stable_ptr: ast::ExprPtr,
2959) -> Maybe<Expr> {
2960 let syntax_db = ctx.db.upcast();
2963 let path = expr.path(syntax_db);
2964 let Ok([segment]): Result<[_; 1], _> = path.elements(syntax_db).try_into() else {
2965 return Err(ctx.diagnostics.report(&expr, InvalidMemberExpression));
2966 };
2967 let func_name = segment.identifier(syntax_db);
2968 let generic_args_syntax = segment.generic_args(syntax_db);
2969
2970 if !ctx.reduce_ty(lexpr.ty()).is_var_free(ctx.db) {
2971 ctx.resolver.inference().solve().ok();
2975 }
2976
2977 let mut candidate_traits = traits_in_context(ctx)?;
2978
2979 for generic_param in &ctx.resolver.data.generic_params {
2981 if generic_param.kind(ctx.db.upcast()) == GenericKind::Impl {
2982 let Ok(trait_id) = ctx.db.generic_impl_param_trait(*generic_param) else {
2983 continue;
2984 };
2985 candidate_traits
2986 .insert(trait_id, LookupItemId::ModuleItem(ModuleItemId::Trait(trait_id)));
2987 }
2988 }
2989
2990 let module_file_id = ctx.resolver.module_file_id;
2992 let lookup_context = ctx.resolver.impl_lookup_context();
2993 let lexpr_clone = lexpr.clone();
2994 let db = ctx.db;
2995 let (function_id, actual_trait_id, fixed_lexpr, mutability) =
2996 compute_method_function_call_data(
2997 ctx,
2998 candidate_traits.keys().copied().collect_vec().as_slice(),
2999 func_name.clone(),
3000 lexpr,
3001 path.stable_ptr().untyped(),
3002 generic_args_syntax,
3003 |ty, method_name, inference_errors| {
3004 let relevant_traits = if !inference_errors.is_empty() {
3005 vec![]
3006 } else {
3007 match_method_to_traits(
3008 db,
3009 ty,
3010 &method_name,
3011 lookup_context.clone(),
3012 module_file_id,
3013 lexpr_clone.stable_ptr().untyped(),
3014 )
3015 };
3016 Some(CannotCallMethod { ty, method_name, inference_errors, relevant_traits })
3017 },
3018 |_, trait_function_id0, trait_function_id1| {
3019 Some(AmbiguousTrait { trait_function_id0, trait_function_id1 })
3020 },
3021 )?;
3022
3023 if let Ok(trait_definition_data) = ctx.db.priv_trait_definition_data(actual_trait_id) {
3024 if let Some(trait_item_info) = trait_definition_data.get_trait_item_info(&func_name) {
3025 ctx.resolver.validate_feature_constraints(
3026 ctx.diagnostics,
3027 &segment.identifier_ast(db.upcast()),
3028 &trait_item_info,
3029 );
3030 }
3031 }
3032 ctx.resolver.data.used_items.insert(candidate_traits[&actual_trait_id]);
3033 ctx.resolver.data.resolved_items.mark_concrete(
3034 ctx.db,
3035 &segment,
3036 ResolvedConcreteItem::Function(function_id),
3037 );
3038
3039 let mut args_iter =
3041 expr.arguments(syntax_db).arguments(syntax_db).elements(syntax_db).into_iter();
3042 let mut named_args = vec![NamedArg(fixed_lexpr, None, mutability)];
3044 let closure_params: OrderedHashMap<TypeId, TypeId> =
3046 concrete_function_closure_params(ctx.db, function_id)?;
3047 for ty in function_parameter_types(ctx, function_id)?.skip(1) {
3048 let Some(arg_syntax) = args_iter.next() else {
3049 break;
3050 };
3051 named_args.push(compute_named_argument_clause(
3052 ctx,
3053 arg_syntax,
3054 closure_params.get(&ty).copied(),
3055 ));
3056 }
3057
3058 if let Some(arg_syntax) = args_iter.next() {
3060 named_args.push(compute_named_argument_clause(ctx, arg_syntax, None));
3061 }
3062
3063 expr_function_call(ctx, function_id, named_args, &expr, stable_ptr)
3064}
3065
3066fn member_access_expr(
3068 ctx: &mut ComputationContext<'_>,
3069 lexpr: ExprAndId,
3070 rhs_syntax: ast::ExprPath,
3071 stable_ptr: ast::ExprPtr,
3072) -> Maybe<Expr> {
3073 let syntax_db = ctx.db.upcast();
3074
3075 let member_name = expr_as_identifier(ctx, &rhs_syntax, syntax_db)?;
3077 let (n_snapshots, long_ty) = finalized_snapshot_peeled_ty(ctx, lexpr.ty(), &rhs_syntax)?;
3078
3079 match &long_ty {
3080 TypeLongId::Concrete(_) | TypeLongId::Tuple(_) | TypeLongId::FixedSizeArray { .. } => {
3081 let Some(EnrichedTypeMemberAccess { member, deref_functions }) =
3082 get_enriched_type_member_access(ctx, lexpr.clone(), stable_ptr, &member_name)?
3083 else {
3084 return Err(ctx.diagnostics.report(
3085 &rhs_syntax,
3086 NoSuchTypeMember { ty: long_ty.intern(ctx.db), member_name },
3087 ));
3088 };
3089 check_struct_member_is_visible(
3090 ctx,
3091 &member,
3092 rhs_syntax.stable_ptr().untyped(),
3093 &member_name,
3094 );
3095 let member_path = match &long_ty {
3096 TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id))
3097 if n_snapshots == 0 && deref_functions.is_empty() =>
3098 {
3099 lexpr.as_member_path().map(|parent| ExprVarMemberPath::Member {
3100 parent: Box::new(parent),
3101 member_id: member.id,
3102 stable_ptr,
3103 concrete_struct_id: *concrete_struct_id,
3104 ty: member.ty,
3105 })
3106 }
3107 _ => None,
3108 };
3109 let mut derefed_expr: ExprAndId = lexpr;
3110 for (deref_function, mutability) in &deref_functions {
3111 let cur_expr = expr_function_call(
3112 ctx,
3113 *deref_function,
3114 vec![NamedArg(derefed_expr, None, *mutability)],
3115 stable_ptr,
3116 stable_ptr,
3117 )
3118 .unwrap();
3119
3120 derefed_expr =
3121 ExprAndId { expr: cur_expr.clone(), id: ctx.arenas.exprs.alloc(cur_expr) };
3122 }
3123 let (_, long_ty) = finalized_snapshot_peeled_ty(ctx, derefed_expr.ty(), &rhs_syntax)?;
3124 let derefed_expr_concrete_struct_id = match long_ty {
3125 TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) => {
3126 concrete_struct_id
3127 }
3128 _ => unreachable!(),
3129 };
3130 let ty = if !deref_functions.is_empty() {
3131 member.ty
3132 } else {
3133 wrap_in_snapshots(ctx.db, member.ty, n_snapshots)
3134 };
3135 Ok(Expr::MemberAccess(ExprMemberAccess {
3136 expr: derefed_expr.id,
3137 concrete_struct_id: derefed_expr_concrete_struct_id,
3138 member: member.id,
3139 ty,
3140 member_path,
3141 n_snapshots,
3142 stable_ptr,
3143 }))
3144 }
3145
3146 TypeLongId::Snapshot(_) => {
3147 Err(ctx.diagnostics.report(&rhs_syntax, Unsupported))
3149 }
3150 TypeLongId::Closure(_) => Err(ctx.diagnostics.report(&rhs_syntax, Unsupported)),
3151 TypeLongId::ImplType(impl_type_id) => {
3152 unreachable!(
3153 "Impl type should've been reduced {:?}.",
3154 impl_type_id.debug(ctx.db.elongate())
3155 )
3156 }
3157 TypeLongId::Var(_) => Err(ctx.diagnostics.report(
3158 &rhs_syntax,
3159 InternalInferenceError(InferenceError::TypeNotInferred(long_ty.intern(ctx.db))),
3160 )),
3161 TypeLongId::GenericParameter(_) | TypeLongId::Coupon(_) => Err(ctx
3162 .diagnostics
3163 .report(&rhs_syntax, TypeHasNoMembers { ty: long_ty.intern(ctx.db), member_name })),
3164 TypeLongId::Missing(diag_added) => Err(*diag_added),
3165 }
3166}
3167
3168fn get_enriched_type_member_access(
3173 ctx: &mut ComputationContext<'_>,
3174 expr: ExprAndId,
3175 stable_ptr: ast::ExprPtr,
3176 accessed_member_name: &str,
3177) -> Maybe<Option<EnrichedTypeMemberAccess>> {
3178 let mut ty = ctx.reduce_ty(expr.ty());
3179 if !ty.is_var_free(ctx.db) {
3180 ctx.resolver.inference().solve().ok();
3184 ty = ctx.reduce_ty(ty);
3185 }
3186 let base_var = match &expr.expr {
3187 Expr::Var(expr_var) => Some(expr_var.var),
3188 Expr::MemberAccess(ExprMemberAccess { member_path: Some(member_path), .. }) => {
3189 Some(member_path.base_var())
3190 }
3191 _ => None,
3192 };
3193 let is_mut_var = base_var
3194 .filter(|var_id| matches!(ctx.semantic_defs.get(var_id), Some(var) if var.is_mut()))
3195 .is_some();
3196 let key = (ty, is_mut_var);
3197 let mut enriched_members = match ctx.resolver.type_enriched_members.entry(key) {
3198 Entry::Occupied(entry) => {
3199 let e = entry.get();
3200 match e.get_member(accessed_member_name) {
3201 Some(value) => return Ok(Some(value)),
3202 None => {
3203 if e.deref_chain.len() == e.explored_derefs {
3204 return Ok(None);
3206 }
3207 }
3208 }
3209 entry.swap_remove()
3211 }
3212 Entry::Vacant(_) => {
3213 let (_, long_ty) = finalized_snapshot_peeled_ty(ctx, ty, stable_ptr)?;
3214 let members =
3215 if let TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) = long_ty {
3216 let members = ctx.db.concrete_struct_members(concrete_struct_id)?;
3217 if let Some(member) = members.get(accessed_member_name) {
3218 return Ok(Some(EnrichedTypeMemberAccess {
3220 member: member.clone(),
3221 deref_functions: vec![],
3222 }));
3223 }
3224 members.iter().map(|(k, v)| (k.clone(), (v.clone(), 0))).collect()
3225 } else {
3226 Default::default()
3227 };
3228
3229 EnrichedMembers {
3230 members,
3231 deref_chain: ctx.db.deref_chain(ty, is_mut_var)?.derefs,
3232 explored_derefs: 0,
3233 }
3234 }
3235 };
3236 enrich_members(ctx, &mut enriched_members, stable_ptr, accessed_member_name)?;
3237 let e = ctx.resolver.type_enriched_members.entry(key).or_insert(enriched_members);
3238 Ok(e.get_member(accessed_member_name))
3239}
3240
3241fn enrich_members(
3246 ctx: &mut ComputationContext<'_>,
3247 enriched_members: &mut EnrichedMembers,
3248 stable_ptr: ast::ExprPtr,
3249 accessed_member_name: &str,
3250) -> Maybe<()> {
3251 let EnrichedMembers { members: enriched, deref_chain, explored_derefs } = enriched_members;
3252
3253 for deref_info in deref_chain.iter().skip(*explored_derefs).cloned() {
3255 *explored_derefs += 1;
3256 let (_, long_ty) = finalized_snapshot_peeled_ty(ctx, deref_info.target_ty, stable_ptr)?;
3257 if let TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) = long_ty {
3258 let members = ctx.db.concrete_struct_members(concrete_struct_id)?;
3259 for (member_name, member) in members.iter() {
3260 enriched
3262 .entry(member_name.clone())
3263 .or_insert_with(|| (member.clone(), *explored_derefs));
3264 }
3265 if members.contains_key(accessed_member_name) {
3267 break;
3269 }
3270 }
3271 }
3272 Ok(())
3273}
3274
3275fn finalized_snapshot_peeled_ty(
3277 ctx: &mut ComputationContext<'_>,
3278 ty: TypeId,
3279 stable_ptr: impl Into<SyntaxStablePtrId>,
3280) -> Maybe<(usize, TypeLongId)> {
3281 let ty = ctx.reduce_ty(ty);
3282 let (base_snapshots, mut long_ty) = peel_snapshots(ctx.db, ty);
3283 if let TypeLongId::ImplType(impl_type_id) = long_ty {
3284 let inference = &mut ctx.resolver.inference();
3285 let Ok(ty) = inference.reduce_impl_ty(impl_type_id) else {
3286 return Err(ctx
3287 .diagnostics
3288 .report(stable_ptr, InternalInferenceError(InferenceError::TypeNotInferred(ty))));
3289 };
3290 long_ty = ty.lookup_intern(ctx.db);
3291 }
3292 if matches!(long_ty, TypeLongId::Var(_)) {
3293 ctx.resolver.inference().solve().ok();
3295 long_ty = ctx.resolver.inference().rewrite(long_ty).no_err();
3296 }
3297 let (additional_snapshots, long_ty) = peel_snapshots_ex(ctx.db, long_ty);
3298 Ok((base_snapshots + additional_snapshots, long_ty))
3299}
3300
3301fn resolve_expr_path(ctx: &mut ComputationContext<'_>, path: &ast::ExprPath) -> Maybe<Expr> {
3303 let db = ctx.db;
3304 let syntax_db = db.upcast();
3305 let segments = path.elements(syntax_db);
3306 if segments.is_empty() {
3307 return Err(ctx.diagnostics.report(path, Unsupported));
3308 }
3309
3310 if let [PathSegment::Simple(ident_segment)] = &segments[..] {
3312 let identifier = ident_segment.ident(syntax_db);
3313 let variable_name = identifier.text(ctx.db.upcast());
3314 if let Some(res) = get_binded_expr_by_name(ctx, &variable_name, path.stable_ptr().into()) {
3315 match res.clone() {
3316 Expr::Var(expr_var) => {
3317 let item = ResolvedGenericItem::Variable(expr_var.var);
3318 ctx.resolver.data.resolved_items.generic.insert(identifier.stable_ptr(), item);
3319 }
3320 Expr::Constant(expr_const) => {
3321 let item = ResolvedConcreteItem::Constant(expr_const.const_value_id);
3322 ctx.resolver.data.resolved_items.concrete.insert(identifier.stable_ptr(), item);
3323 }
3324 _ => unreachable!(
3325 "get_binded_expr_by_name should only return variables or constants"
3326 ),
3327 };
3328 return Ok(res);
3329 }
3330 }
3331
3332 let resolved_item: ResolvedConcreteItem = ctx.resolver.resolve_concrete_path_ex(
3333 ctx.diagnostics,
3334 path,
3335 NotFoundItemType::Identifier,
3336 Some(&mut ctx.environment),
3337 )?;
3338
3339 match resolved_item {
3340 ResolvedConcreteItem::Constant(const_value_id) => Ok(Expr::Constant(ExprConstant {
3341 const_value_id,
3342 ty: const_value_id.ty(db)?,
3343 stable_ptr: path.stable_ptr().into(),
3344 })),
3345
3346 ResolvedConcreteItem::Variant(variant) if variant.ty == unit_ty(db) => {
3347 let stable_ptr = path.stable_ptr().into();
3348 let concrete_enum_id = variant.concrete_enum_id;
3349 Ok(semantic::Expr::EnumVariantCtor(semantic::ExprEnumVariantCtor {
3350 variant,
3351 value_expr: unit_expr(ctx, stable_ptr),
3352 ty: TypeLongId::Concrete(ConcreteTypeId::Enum(concrete_enum_id)).intern(db),
3353 stable_ptr,
3354 }))
3355 }
3356 resolved_item => Err(ctx.diagnostics.report(
3357 path,
3358 UnexpectedElement {
3359 expected: vec![ElementKind::Variable, ElementKind::Constant],
3360 actual: (&resolved_item).into(),
3361 },
3362 )),
3363 }
3364}
3365
3366pub fn resolve_variable_by_name(
3370 ctx: &mut ComputationContext<'_>,
3371 identifier: &ast::TerminalIdentifier,
3372 stable_ptr: ast::ExprPtr,
3373) -> Maybe<Expr> {
3374 let variable_name = identifier.text(ctx.db.upcast());
3375 let res = get_binded_expr_by_name(ctx, &variable_name, stable_ptr)
3376 .ok_or_else(|| ctx.diagnostics.report(identifier, VariableNotFound(variable_name)))?;
3377 let item = ResolvedGenericItem::Variable(extract_matches!(&res, Expr::Var).var);
3378 ctx.resolver.data.resolved_items.generic.insert(identifier.stable_ptr(), item);
3379 Ok(res)
3380}
3381
3382pub fn get_binded_expr_by_name(
3384 ctx: &mut ComputationContext<'_>,
3385 variable_name: &SmolStr,
3386 stable_ptr: ast::ExprPtr,
3387) -> Option<Expr> {
3388 let mut maybe_env = Some(&mut *ctx.environment);
3389 while let Some(env) = maybe_env {
3390 if let Some(var) = env.variables.get(variable_name) {
3391 env.used_variables.insert(var.id());
3392 return match var {
3393 Binding::LocalItem(local_const) => match local_const.kind.clone() {
3394 crate::StatementItemKind::Constant(const_value_id, ty) => {
3395 Some(Expr::Constant(ExprConstant { const_value_id, ty, stable_ptr }))
3396 }
3397 },
3398 Binding::LocalVar(_) | Binding::Param(_) => {
3399 Some(Expr::Var(ExprVar { var: var.id(), ty: var.ty(), stable_ptr }))
3400 }
3401 };
3402 }
3403 maybe_env = env.parent.as_deref_mut();
3404 }
3405 None
3406}
3407
3408fn expr_function_call(
3410 ctx: &mut ComputationContext<'_>,
3411 function_id: FunctionId,
3412 mut named_args: Vec<NamedArg>,
3413 call_ptr: impl Into<SyntaxStablePtrId>,
3414 stable_ptr: ast::ExprPtr,
3415) -> Maybe<Expr> {
3416 let coupon_arg = maybe_pop_coupon_argument(ctx, &mut named_args, function_id);
3417
3418 let signature = ctx.db.concrete_function_signature(function_id)?;
3419 let signature = ctx.resolver.inference().rewrite(signature).unwrap();
3420
3421 if named_args.len() != signature.params.len() {
3423 return Err(ctx.diagnostics.report(
3424 call_ptr,
3425 WrongNumberOfArguments { expected: signature.params.len(), actual: named_args.len() },
3426 ));
3427 }
3428
3429 check_named_arguments(&named_args, &signature, ctx)?;
3431
3432 let mut args = Vec::new();
3433 for (NamedArg(arg, _name, mutability), param) in
3434 named_args.into_iter().zip(signature.params.iter())
3435 {
3436 let arg_ty = arg.ty();
3437 let param_ty = param.ty;
3438 if !arg_ty.is_missing(ctx.db) {
3442 let inference = &mut ctx.resolver.inference();
3443 let _ = inference.conform_ty_for_diag(
3444 arg_ty,
3445 param_ty,
3446 ctx.diagnostics,
3447 || arg.stable_ptr().untyped(),
3448 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
3449 );
3450 }
3451
3452 args.push(if param.mutability == Mutability::Reference {
3453 let Some(ref_arg) = arg.as_member_path() else {
3455 return Err(ctx.diagnostics.report(arg.deref(), RefArgNotAVariable));
3456 };
3457 if !ctx.semantic_defs[&ref_arg.base_var()].is_mut() {
3459 ctx.diagnostics.report(arg.deref(), RefArgNotMutable);
3460 }
3461 if mutability != Mutability::Reference {
3463 ctx.diagnostics.report(arg.deref(), RefArgNotExplicit);
3464 }
3465 ExprFunctionCallArg::Reference(ref_arg)
3466 } else {
3467 if mutability != Mutability::Immutable {
3469 ctx.diagnostics.report(arg.deref(), ImmutableArgWithModifiers);
3470 }
3471 ExprFunctionCallArg::Value(arg.id)
3472 });
3473 }
3474
3475 let expr_function_call = ExprFunctionCall {
3476 function: function_id,
3477 args,
3478 coupon_arg,
3479 ty: signature.return_type,
3480 stable_ptr,
3481 };
3482 if signature.panicable && has_panic_incompatibility(ctx) {
3484 return Err(ctx.diagnostics.report(call_ptr, PanicableFromNonPanicable));
3487 }
3488 Ok(Expr::FunctionCall(expr_function_call))
3489}
3490
3491fn maybe_pop_coupon_argument(
3494 ctx: &mut ComputationContext<'_>,
3495 named_args: &mut Vec<NamedArg>,
3496 function_id: FunctionId,
3497) -> Option<id_arena::Id<Expr>> {
3498 let mut coupon_arg: Option<ExprId> = None;
3499 if let Some(NamedArg(arg, Some(name_terminal), mutability)) = named_args.last() {
3500 let coupons_enabled = are_coupons_enabled(ctx.db, ctx.resolver.module_file_id);
3501 if name_terminal.text(ctx.db.upcast()) == "__coupon__" && coupons_enabled {
3502 let expected_ty = TypeLongId::Coupon(function_id).intern(ctx.db);
3504 let arg_ty = arg.ty();
3505 if !arg_ty.is_missing(ctx.db) {
3506 let inference = &mut ctx.resolver.inference();
3507 let _ = inference.conform_ty_for_diag(
3508 arg_ty,
3509 expected_ty,
3510 ctx.diagnostics,
3511 || arg.stable_ptr().untyped(),
3512 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
3513 );
3514 }
3515
3516 if *mutability != Mutability::Immutable {
3518 ctx.diagnostics.report(arg.deref(), CouponArgumentNoModifiers);
3519 }
3520
3521 coupon_arg = Some(arg.id);
3522
3523 named_args.pop();
3525 }
3526 }
3527 coupon_arg
3528}
3529
3530fn has_panic_incompatibility(ctx: &mut ComputationContext<'_>) -> bool {
3532 if let Some(signature) = ctx.signature {
3533 !signature.panicable
3535 } else {
3536 false
3537 }
3538}
3539
3540fn check_named_arguments(
3542 named_args: &[NamedArg],
3543 signature: &Signature,
3544 ctx: &mut ComputationContext<'_>,
3545) -> Maybe<()> {
3546 let mut res: Maybe<()> = Ok(());
3547
3548 let mut seen_named_arguments: bool = false;
3551 let mut reported_unnamed_argument_follows_named: bool = false;
3554 for (NamedArg(arg, name_opt, _mutability), param) in
3555 named_args.iter().zip(signature.params.iter())
3556 {
3557 if let Some(name_terminal) = name_opt {
3559 seen_named_arguments = true;
3560 let name = name_terminal.text(ctx.db.upcast());
3561 if param.name != name.clone() {
3562 res = Err(ctx.diagnostics.report(
3563 name_terminal,
3564 NamedArgumentMismatch { expected: param.name.clone(), found: name },
3565 ));
3566 }
3567 } else if seen_named_arguments && !reported_unnamed_argument_follows_named {
3568 reported_unnamed_argument_follows_named = true;
3569 res = Err(ctx.diagnostics.report(arg.deref(), UnnamedArgumentFollowsNamed));
3570 }
3571 }
3572 res
3573}
3574
3575pub fn compute_statement_semantic(
3577 ctx: &mut ComputationContext<'_>,
3578 syntax: ast::Statement,
3579) -> Maybe<StatementId> {
3580 let db = ctx.db;
3581 let syntax_db = db.upcast();
3582
3583 let crate_id = ctx.resolver.owning_crate_id;
3584
3585 validate_statement_attributes(ctx, &syntax);
3588 let feature_restore = ctx
3589 .resolver
3590 .data
3591 .feature_config
3592 .override_with(extract_item_feature_config(db, crate_id, &syntax, ctx.diagnostics));
3593 let statement = match &syntax {
3594 ast::Statement::Let(let_syntax) => {
3595 let rhs_syntax = &let_syntax.rhs(syntax_db);
3596 let (rhs_expr, ty) = match let_syntax.type_clause(syntax_db) {
3597 ast::OptionTypeClause::Empty(_) => {
3598 let rhs_expr = compute_expr_semantic(ctx, rhs_syntax);
3599 let inferred_type = rhs_expr.ty();
3600 (rhs_expr, inferred_type)
3601 }
3602 ast::OptionTypeClause::TypeClause(type_clause) => {
3603 let var_type_path = type_clause.ty(syntax_db);
3604 let explicit_type = resolve_type_with_environment(
3605 db,
3606 ctx.diagnostics,
3607 &mut ctx.resolver,
3608 &var_type_path,
3609 Some(&mut ctx.environment),
3610 );
3611
3612 let rhs_expr = compute_expr_semantic(ctx, rhs_syntax);
3613 let inferred_type = ctx.reduce_ty(rhs_expr.ty());
3614 if !inferred_type.is_missing(db) {
3615 let inference = &mut ctx.resolver.inference();
3616 let _ = inference.conform_ty_for_diag(
3617 inferred_type,
3618 explicit_type,
3619 ctx.diagnostics,
3620 || rhs_syntax.into(),
3621 |actual_ty, expected_ty| WrongArgumentType { expected_ty, actual_ty },
3622 );
3623 }
3624 (rhs_expr, explicit_type)
3625 }
3626 };
3627 let rhs_expr_id = rhs_expr.id;
3628
3629 let pattern = compute_pattern_semantic(
3630 ctx,
3631 &let_syntax.pattern(syntax_db),
3632 ty,
3633 &mut UnorderedHashMap::default(),
3634 );
3635 let variables = pattern.variables(&ctx.arenas.patterns);
3636 for v in variables {
3637 let var_def = Binding::LocalVar(v.var.clone());
3638 if let Some(old_var) =
3639 ctx.environment.variables.insert(v.name.clone(), var_def.clone())
3640 {
3641 if matches!(old_var, Binding::LocalItem(_)) {
3642 return Err(ctx
3643 .diagnostics
3644 .report(v.stable_ptr, MultipleDefinitionforBinding(v.name.clone())));
3645 }
3646 ctx.add_unused_binding_warning(&v.name, &old_var);
3647 }
3648 ctx.semantic_defs.insert(var_def.id(), var_def);
3649 }
3650 semantic::Statement::Let(semantic::StatementLet {
3651 pattern: pattern.id,
3652 expr: rhs_expr_id,
3653 stable_ptr: syntax.stable_ptr(),
3654 })
3655 }
3656 ast::Statement::Expr(stmt_expr_syntax) => {
3657 let expr_syntax = stmt_expr_syntax.expr(syntax_db);
3658 let expr = compute_expr_semantic(ctx, &expr_syntax);
3659 if matches!(
3660 stmt_expr_syntax.semicolon(syntax_db),
3661 ast::OptionTerminalSemicolon::Empty(_)
3662 ) && !matches!(
3663 expr_syntax,
3664 ast::Expr::Block(_)
3665 | ast::Expr::If(_)
3666 | ast::Expr::Match(_)
3667 | ast::Expr::Loop(_)
3668 | ast::Expr::While(_)
3669 | ast::Expr::For(_)
3670 ) {
3671 ctx.diagnostics.report_after(&expr_syntax, MissingSemicolon);
3673 }
3674 let ty: TypeId = expr.ty();
3675 if let TypeLongId::Concrete(concrete) = ty.lookup_intern(db) {
3676 if concrete.is_must_use(db)? {
3677 ctx.diagnostics.report(&expr_syntax, UnhandledMustUseType(ty));
3678 }
3679 }
3680 if let Expr::FunctionCall(expr_function_call) = &expr.expr {
3681 let generic_function_id =
3682 expr_function_call.function.lookup_intern(db).function.generic_function;
3683 if generic_function_id.is_must_use(db)? {
3684 ctx.diagnostics.report(&expr_syntax, UnhandledMustUseFunction);
3685 }
3686 }
3687 semantic::Statement::Expr(semantic::StatementExpr {
3688 expr: expr.id,
3689 stable_ptr: syntax.stable_ptr(),
3690 })
3691 }
3692 ast::Statement::Continue(continue_syntax) => {
3693 if !ctx.is_inside_loop() {
3694 return Err(ctx
3695 .diagnostics
3696 .report(continue_syntax, ContinueOnlyAllowedInsideALoop));
3697 }
3698 semantic::Statement::Continue(semantic::StatementContinue {
3699 stable_ptr: syntax.stable_ptr(),
3700 })
3701 }
3702 ast::Statement::Return(return_syntax) => {
3703 let (expr_option, expr_ty, stable_ptr) = match return_syntax.expr_clause(syntax_db) {
3704 ast::OptionExprClause::Empty(empty_clause) => {
3705 (None, unit_ty(db), empty_clause.stable_ptr().untyped())
3706 }
3707 ast::OptionExprClause::ExprClause(expr_clause) => {
3708 let expr_syntax = expr_clause.expr(syntax_db);
3709 let expr = compute_expr_semantic(ctx, &expr_syntax);
3710 (Some(expr.id), expr.ty(), expr_syntax.stable_ptr().untyped())
3711 }
3712 };
3713 let expected_ty = match &ctx.inner_ctx {
3714 None => ctx.get_return_type().ok_or_else(|| {
3715 ctx.diagnostics.report(
3716 return_syntax,
3717 UnsupportedOutsideOfFunction(
3718 UnsupportedOutsideOfFunctionFeatureName::ReturnStatement,
3719 ),
3720 )
3721 })?,
3722 Some(ctx) => ctx.return_type,
3723 };
3724
3725 let expected_ty = ctx.reduce_ty(expected_ty);
3726 let expr_ty = ctx.reduce_ty(expr_ty);
3727 if !expected_ty.is_missing(db) && !expr_ty.is_missing(db) {
3728 let inference = &mut ctx.resolver.inference();
3729 let _ = inference.conform_ty_for_diag(
3730 expr_ty,
3731 expected_ty,
3732 ctx.diagnostics,
3733 || stable_ptr,
3734 |actual_ty, expected_ty| WrongReturnType { expected_ty, actual_ty },
3735 );
3736 }
3737 semantic::Statement::Return(semantic::StatementReturn {
3738 expr_option,
3739 stable_ptr: syntax.stable_ptr(),
3740 })
3741 }
3742 ast::Statement::Break(break_syntax) => {
3743 let (expr_option, ty, stable_ptr) = match break_syntax.expr_clause(syntax_db) {
3744 ast::OptionExprClause::Empty(expr_empty) => {
3745 (None, unit_ty(db), expr_empty.stable_ptr().untyped())
3746 }
3747 ast::OptionExprClause::ExprClause(expr_clause) => {
3748 let expr_syntax = expr_clause.expr(syntax_db);
3749 let expr = compute_expr_semantic(ctx, &expr_syntax);
3750
3751 (Some(expr.id), expr.ty(), expr.stable_ptr().untyped())
3752 }
3753 };
3754 let ty = ctx.reduce_ty(ty);
3755
3756 if !ctx.is_inside_loop() {
3757 return Err(ctx.diagnostics.report(break_syntax, BreakOnlyAllowedInsideALoop));
3758 }
3759
3760 if let Some(inner_ctx) = &mut ctx.inner_ctx {
3761 match &mut inner_ctx.kind {
3762 InnerContextKind::Loop { type_merger, .. } => {
3763 type_merger.try_merge_types(
3764 ctx.db,
3765 ctx.diagnostics,
3766 &mut ctx.resolver.inference(),
3767 ty,
3768 stable_ptr,
3769 );
3770 }
3771 InnerContextKind::While | InnerContextKind::For => {
3772 if expr_option.is_some() {
3773 ctx.diagnostics
3774 .report(break_syntax, BreakWithValueOnlyAllowedInsideALoop);
3775 };
3776 }
3777 InnerContextKind::Closure => unreachable!("Not inside a loop."),
3778 }
3779 }
3780
3781 semantic::Statement::Break(semantic::StatementBreak {
3782 expr_option,
3783 stable_ptr: syntax.stable_ptr(),
3784 })
3785 }
3786 ast::Statement::Item(stmt_item_syntax) => {
3787 let item_syntax = &stmt_item_syntax.item(syntax_db);
3788 match item_syntax {
3789 ast::ModuleItem::Constant(const_syntax) => {
3790 let lhs = const_syntax.type_clause(db.upcast()).ty(db.upcast());
3791 let rhs = const_syntax.value(db.upcast());
3792 let rhs_expr = compute_expr_semantic(ctx, &rhs);
3793 let explicit_type = resolve_type_with_environment(
3794 db,
3795 ctx.diagnostics,
3796 &mut ctx.resolver,
3797 &lhs,
3798 Some(&mut ctx.environment),
3799 );
3800 let rhs_resolved_expr = resolve_const_expr_and_evaluate(
3801 db,
3802 ctx,
3803 &rhs_expr,
3804 stmt_item_syntax.stable_ptr().untyped(),
3805 explicit_type,
3806 false,
3807 );
3808 let name_syntax = const_syntax.name(syntax_db);
3809 let name = name_syntax.text(db.upcast());
3810 let rhs_id = StatementConstLongId(
3811 ctx.resolver.module_file_id,
3812 const_syntax.stable_ptr(),
3813 );
3814 let var_def = Binding::LocalItem(LocalItem {
3815 id: StatementItemId::Constant(rhs_id.intern(db)),
3816 kind: StatementItemKind::Constant(
3817 db.intern_const_value(rhs_resolved_expr.clone()),
3818 rhs_resolved_expr.ty(db.upcast())?,
3819 ),
3820 });
3821 add_item_to_statement_environment(ctx, name, var_def, &name_syntax);
3822 }
3823 ast::ModuleItem::Use(use_syntax) => {
3824 for leaf in get_all_path_leaves(syntax_db, use_syntax) {
3825 let stable_ptr = leaf.stable_ptr();
3826 let segments = get_use_path_segments(syntax_db, ast::UsePath::Leaf(leaf))?;
3827 let resolved_item = ctx.resolver.resolve_generic_path(
3828 ctx.diagnostics,
3829 segments,
3830 NotFoundItemType::Identifier,
3831 Some(&mut ctx.environment),
3832 )?;
3833 let var_def_id = StatementItemId::Use(
3834 StatementUseLongId(ctx.resolver.module_file_id, stable_ptr).intern(db),
3835 );
3836 let name = var_def_id.name(db.upcast());
3837 match resolved_item {
3838 ResolvedGenericItem::GenericConstant(const_id) => {
3839 let var_def = Binding::LocalItem(LocalItem {
3840 id: var_def_id,
3841 kind: StatementItemKind::Constant(
3842 db.constant_const_value(const_id)?,
3843 db.constant_const_type(const_id)?,
3844 ),
3845 });
3846 add_item_to_statement_environment(ctx, name, var_def, stable_ptr);
3847 }
3848 ResolvedGenericItem::GenericType(generic_type_id) => {
3849 add_type_to_statement_environment(
3850 ctx,
3851 name,
3852 ResolvedGenericItem::GenericType(generic_type_id),
3853 stable_ptr,
3854 );
3855 }
3856 ResolvedGenericItem::Module(_)
3857 | ResolvedGenericItem::GenericFunction(_)
3858 | ResolvedGenericItem::GenericTypeAlias(_)
3859 | ResolvedGenericItem::GenericImplAlias(_)
3860 | ResolvedGenericItem::Variant(_)
3861 | ResolvedGenericItem::Trait(_)
3862 | ResolvedGenericItem::Impl(_)
3863 | ResolvedGenericItem::Variable(_) => {
3864 return Err(ctx
3865 .diagnostics
3866 .report(stable_ptr, UnsupportedUseItemInStatement));
3867 }
3868 }
3869 }
3870 }
3871 ast::ModuleItem::Module(_) => {
3872 unreachable!("Modules are not supported inside a function.")
3873 }
3874 ast::ModuleItem::FreeFunction(_) => {
3875 unreachable!("FreeFunction type not supported.")
3876 }
3877 ast::ModuleItem::ExternFunction(_) => {
3878 unreachable!("ExternFunction type not supported.")
3879 }
3880 ast::ModuleItem::ExternType(_) => unreachable!("ExternType type not supported."),
3881 ast::ModuleItem::Trait(_) => unreachable!("Trait type not supported."),
3882 ast::ModuleItem::Impl(_) => unreachable!("Impl type not supported."),
3883 ast::ModuleItem::ImplAlias(_) => unreachable!("ImplAlias type not supported."),
3884 ast::ModuleItem::Struct(_) => unreachable!("Struct type not supported."),
3885 ast::ModuleItem::Enum(_) => unreachable!("Enum type not supported."),
3886 ast::ModuleItem::TypeAlias(_) => unreachable!("TypeAlias type not supported."),
3887 ast::ModuleItem::InlineMacro(_) => unreachable!("InlineMacro type not supported."),
3888 ast::ModuleItem::HeaderDoc(_) => unreachable!("HeaderDoc type not supported."),
3889 ast::ModuleItem::Missing(_) => unreachable!("Missing type not supported."),
3890 }
3891 semantic::Statement::Item(semantic::StatementItem { stable_ptr: syntax.stable_ptr() })
3892 }
3893 ast::Statement::Missing(_) => todo!(),
3894 };
3895 ctx.resolver.data.feature_config.restore(feature_restore);
3896 Ok(ctx.arenas.statements.alloc(statement))
3897}
3898
3899fn add_item_to_statement_environment(
3902 ctx: &mut ComputationContext<'_>,
3903 name: SmolStr,
3904 var_def: Binding,
3905 stable_ptr: impl Into<SyntaxStablePtrId>,
3906) {
3907 if let Some(old_var) = ctx.environment.variables.insert(name.clone(), var_def.clone()) {
3908 ctx.diagnostics.report(
3909 stable_ptr,
3910 match old_var {
3911 Binding::LocalItem(_) => MultipleConstantDefinition(name),
3912 Binding::LocalVar(_) | Binding::Param(_) => MultipleDefinitionforBinding(name),
3913 },
3914 );
3915 }
3916 ctx.semantic_defs.insert(var_def.id(), var_def);
3917}
3918
3919fn add_type_to_statement_environment(
3922 ctx: &mut ComputationContext<'_>,
3923 name: SmolStr,
3924 resolved_generic_item: ResolvedGenericItem,
3925 stable_ptr: impl Into<SyntaxStablePtrId> + std::marker::Copy,
3926) {
3927 if ctx
3928 .environment
3929 .use_items
3930 .insert(
3931 name.clone(),
3932 StatementGenericItemData { resolved_generic_item, stable_ptr: stable_ptr.into() },
3933 )
3934 .is_some()
3935 {
3936 ctx.diagnostics.report(stable_ptr, MultipleGenericItemDefinition(name));
3937 }
3938}
3939
3940fn compute_bool_condition_semantic(
3943 ctx: &mut ComputationContext<'_>,
3944 condition_syntax: &ast::Expr,
3945) -> ExprAndId {
3946 let condition = compute_expr_semantic(ctx, condition_syntax);
3947 let inference = &mut ctx.resolver.inference();
3948 let _ = inference.conform_ty_for_diag(
3949 condition.ty(),
3950 core_bool_ty(ctx.db),
3951 ctx.diagnostics,
3952 || condition.stable_ptr().untyped(),
3953 |condition_ty, _expected_ty| ConditionNotBool(condition_ty),
3954 );
3955 condition
3956}
3957
3958fn check_struct_member_is_visible(
3960 ctx: &mut ComputationContext<'_>,
3961 member: &Member,
3962 stable_ptr: SyntaxStablePtrId,
3963 member_name: &SmolStr,
3964) {
3965 let db = ctx.db.upcast();
3966 let containing_module_id = member.id.parent_module(db);
3967 if ctx.resolver.ignore_visibility_checks(containing_module_id) {
3968 return;
3969 }
3970 let user_module_id = ctx.resolver.module_file_id.0;
3971 if !visibility::peek_visible_in(db, member.visibility, containing_module_id, user_module_id) {
3972 ctx.diagnostics.report(stable_ptr, MemberNotVisible(member_name.clone()));
3973 }
3974}
3975
3976fn validate_statement_attributes(ctx: &mut ComputationContext<'_>, syntax: &ast::Statement) {
3979 let allowed_attributes = ctx.db.allowed_statement_attributes();
3980 let mut diagnostics = vec![];
3981 validate_attributes_flat(
3982 ctx.db.upcast(),
3983 &allowed_attributes,
3984 &OrderedHashSet::default(),
3985 syntax,
3986 &mut diagnostics,
3987 );
3988 for diagnostic in diagnostics {
3990 ctx.diagnostics
3991 .report(diagnostic.stable_ptr, SemanticDiagnosticKind::UnknownStatementAttribute);
3992 }
3993}
3994
3995fn function_parameter_types(
3997 ctx: &mut ComputationContext<'_>,
3998 function: FunctionId,
3999) -> Maybe<impl Iterator<Item = TypeId>> {
4000 let signature = ctx.db.concrete_function_signature(function)?;
4001 let param_types = signature.params.into_iter().map(|param| param.ty);
4002 Ok(param_types)
4003}
4004
4005fn match_method_to_traits(
4009 db: &dyn SemanticGroup,
4010 ty: semantic::TypeId,
4011 method_name: &SmolStr,
4012 lookup_context: ImplLookupContext,
4013 module_file_id: ModuleFileId,
4014 stable_ptr: SyntaxStablePtrId,
4015) -> Vec<String> {
4016 let visible_traits = db
4017 .visible_traits_from_module(module_file_id)
4018 .unwrap_or_else(|| Arc::new(OrderedHashMap::default()));
4019
4020 visible_traits
4021 .iter()
4022 .filter_map(|(trait_id, path)| {
4023 let mut data = InferenceData::new(InferenceId::NoContext);
4024 let mut inference = data.inference(db);
4025 let trait_function =
4026 db.trait_function_by_name(*trait_id, method_name.clone()).ok()??;
4027 let (concrete_trait_id, _) = inference.infer_concrete_trait_by_self(
4028 trait_function,
4029 ty,
4030 &lookup_context,
4031 Some(stable_ptr),
4032 |_| {},
4033 )?;
4034 inference.solve().ok();
4035 match inference.trait_solution_set(
4036 concrete_trait_id,
4037 ImplVarTraitItemMappings::default(),
4038 lookup_context.clone(),
4039 ) {
4040 Ok(SolutionSet::Unique(_) | SolutionSet::Ambiguous(_)) => Some(path.clone()),
4041 _ => None,
4042 }
4043 })
4044 .collect()
4045}