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