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::{ImplLongId, 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, ImplTypeId, 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, ConcreteTraitLongId, GenericArgumentId, GenericParam, LocalItem, Member,
87 Mutability, Parameter, 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 for (concrete_trait_type_id, ty1) in imp.type_constraints {
1055 let trait_ty = concrete_trait_type_id.trait_type(ctx.db);
1056 let impl_type = ImplTypeId::new(
1057 ImplLongId::GenericParameter(*param).intern(ctx.db),
1058 trait_ty,
1059 ctx.db,
1060 );
1061 let ty0 = inference.impl_type_assignment(impl_type);
1062 inference.conform_ty(ty0, ty1).ok();
1063 }
1064 let ConcreteTraitLongId { trait_id, generic_args } =
1065 concrete_trait_id.lookup_intern(ctx.db);
1066 if crate::corelib::fn_traits(ctx.db).contains(&trait_id) {
1067 ctx.are_closures_in_context = true;
1068 }
1069 if trait_id != get_core_trait(ctx.db, CoreTraitContext::MetaProgramming, "TypeEqual".into())
1070 {
1071 continue;
1072 }
1073 let [GenericArgumentId::Type(ty0), GenericArgumentId::Type(ty1)] = generic_args.as_slice()
1074 else {
1075 unreachable!("TypeEqual should have 2 arguments");
1076 };
1077 let ty0 = if let TypeLongId::ImplType(impl_type) = ty0.lookup_intern(ctx.db) {
1078 inference.impl_type_assignment(impl_type)
1079 } else {
1080 *ty0
1081 };
1082 let ty1 = if let TypeLongId::ImplType(impl_type) = ty1.lookup_intern(ctx.db) {
1083 inference.impl_type_assignment(impl_type)
1084 } else {
1085 *ty1
1086 };
1087 inference.conform_ty(ty0, ty1).ok();
1088 }
1089 inference.finalize_impl_type_bounds();
1090
1091 let return_type = ctx.reduce_ty(return_type);
1092 let res = compute_expr_block_semantic(ctx, syntax)?;
1093 let res_ty = ctx.reduce_ty(res.ty());
1094 let res = ctx.arenas.exprs.alloc(res);
1095 let inference = &mut ctx.resolver.inference();
1096 if let Err((err_set, actual_ty, expected_ty)) =
1097 inference.conform_ty_for_diag(res_ty, return_type)
1098 {
1099 let diag_added = ctx.diagnostics.report(
1100 ctx.signature
1101 .map(|s| match s.stable_ptr.lookup(ctx.db.upcast()).ret_ty(ctx.db.upcast()) {
1102 OptionReturnTypeClause::Empty(_) => syntax.stable_ptr().untyped(),
1103 OptionReturnTypeClause::ReturnTypeClause(return_type_clause) => {
1104 return_type_clause.ty(ctx.db.upcast()).stable_ptr().untyped()
1105 }
1106 })
1107 .unwrap_or_else(|| syntax.stable_ptr().untyped()),
1108 WrongReturnType { expected_ty, actual_ty },
1109 );
1110 inference.consume_reported_error(err_set, diag_added);
1111 }
1112
1113 inference.finalize(ctx.diagnostics, syntax.into());
1115
1116 ctx.apply_inference_rewriter();
1117
1118 Ok(res)
1119}
1120
1121pub fn compute_expr_block_semantic(
1123 ctx: &mut ComputationContext<'_>,
1124 syntax: &ast::ExprBlock,
1125) -> Maybe<Expr> {
1126 let db = ctx.db;
1127 let syntax_db = db.upcast();
1128
1129 ctx.run_in_subscope(|new_ctx| {
1130 let mut statements = syntax.statements(syntax_db).elements(syntax_db);
1131 let tail = get_tail_expression(syntax_db, statements.as_slice());
1134 if tail.is_some() {
1135 statements.pop();
1136 }
1137
1138 let statements_semantic: Vec<_> = statements
1140 .into_iter()
1141 .filter_map(|statement_syntax| {
1142 compute_statement_semantic(new_ctx, statement_syntax).to_option()
1143 })
1144 .collect();
1145
1146 let tail_semantic_expr = tail.map(|tail_expr| compute_expr_semantic(new_ctx, &tail_expr));
1148 let ty = if let Some(t) = &tail_semantic_expr {
1149 t.ty()
1150 } else if let Some(statement) = statements_semantic.last() {
1151 if let Statement::Return(_) | Statement::Break(_) =
1152 &new_ctx.arenas.statements[*statement]
1153 {
1154 never_ty(new_ctx.db)
1155 } else {
1156 unit_ty(db)
1157 }
1158 } else {
1159 unit_ty(db)
1160 };
1161 Ok(Expr::Block(ExprBlock {
1162 statements: statements_semantic,
1163 tail: tail_semantic_expr.map(|expr| expr.id),
1164 ty,
1165 stable_ptr: syntax.stable_ptr().into(),
1166 }))
1167 })
1168}
1169
1170#[derive(Debug, Clone)]
1172struct FlowMergeTypeHelper {
1173 multi_arm_expr_kind: MultiArmExprKind,
1174 never_type: TypeId,
1175 final_type: Option<TypeId>,
1176 had_merge_error: bool,
1178}
1179impl FlowMergeTypeHelper {
1180 fn new(db: &dyn SemanticGroup, multi_arm_expr_kind: MultiArmExprKind) -> Self {
1181 Self {
1182 multi_arm_expr_kind,
1183 never_type: never_ty(db),
1184 final_type: None,
1185 had_merge_error: false,
1186 }
1187 }
1188
1189 fn try_merge_types(
1193 &mut self,
1194 db: &dyn SemanticGroup,
1195 diagnostics: &mut SemanticDiagnostics,
1196 inference: &mut Inference<'_>,
1197 ty: TypeId,
1198 stable_ptr: SyntaxStablePtrId,
1199 ) -> bool {
1200 if self.had_merge_error {
1201 return false;
1202 }
1203
1204 if ty != self.never_type && !ty.is_missing(db) {
1205 if let Some(pending) = &self.final_type {
1206 if let Err(err_set) = inference.conform_ty(ty, *pending) {
1207 let diag_added = diagnostics.report(stable_ptr, IncompatibleArms {
1208 multi_arm_expr_kind: self.multi_arm_expr_kind,
1209 pending_ty: *pending,
1210 different_ty: ty,
1211 });
1212 inference.consume_reported_error(err_set, diag_added);
1213 self.had_merge_error = true;
1214 return false;
1215 }
1216 } else {
1217 self.final_type = Some(ty);
1218 }
1219 }
1220 true
1221 }
1222
1223 fn get_final_type(self) -> TypeId {
1225 self.final_type.unwrap_or(self.never_type)
1226 }
1227}
1228
1229fn compute_arm_semantic(
1231 ctx: &mut ComputationContext<'_>,
1232 expr: &Expr,
1233 arm_expr_syntax: ast::Expr,
1234 patterns_syntax: &PatternListOr,
1235 is_while_let_arm: bool,
1237) -> (Vec<PatternAndId>, ExprAndId) {
1238 let db = ctx.db;
1239 let syntax_db = db.upcast();
1240 ctx.run_in_subscope(|new_ctx| {
1241 let mut arm_patterns_variables: UnorderedHashMap<SmolStr, LocalVariable> =
1245 UnorderedHashMap::default();
1246 let patterns: Vec<_> = patterns_syntax
1247 .elements(syntax_db)
1248 .iter()
1249 .map(|pattern_syntax| {
1250 let pattern: PatternAndId = compute_pattern_semantic(
1251 new_ctx,
1252 pattern_syntax,
1253 expr.ty(),
1254 &mut arm_patterns_variables,
1255 );
1256 let variables = pattern.variables(&new_ctx.arenas.patterns);
1257 for variable in variables {
1258 match arm_patterns_variables.entry(variable.name.clone()) {
1259 std::collections::hash_map::Entry::Occupied(entry) => {
1260 let get_location = || variable.stable_ptr.lookup(db.upcast());
1261 let var = entry.get();
1262
1263 let expected_ty = new_ctx.reduce_ty(var.ty);
1264 let actual_ty = new_ctx.reduce_ty(variable.var.ty);
1265
1266 let mut has_inference_error = false;
1267 if !variable.var.ty.is_missing(new_ctx.db) {
1268 let inference = &mut new_ctx.resolver.inference();
1269 if let Err((err_set, actual_ty, expected_ty)) =
1270 inference.conform_ty_for_diag(actual_ty, expected_ty)
1271 {
1272 let diag_added =
1273 new_ctx.diagnostics.report(&get_location(), WrongType {
1274 expected_ty,
1275 actual_ty,
1276 });
1277 inference.consume_reported_error(err_set, diag_added);
1278 has_inference_error = true;
1279 }
1280 };
1281 if !has_inference_error && var.is_mut != variable.var.is_mut {
1282 new_ctx.diagnostics.report(&get_location(), InconsistentBinding);
1283 }
1284 }
1285 std::collections::hash_map::Entry::Vacant(entry) => {
1286 entry.insert(variable.var.clone());
1287 }
1288 }
1289 }
1290 pattern
1291 })
1292 .collect();
1293
1294 for (pattern_syntax, pattern) in
1295 patterns_syntax.elements(syntax_db).iter().zip(patterns.iter())
1296 {
1297 let variables = pattern.variables(&new_ctx.arenas.patterns);
1298
1299 if variables.len() != arm_patterns_variables.len() {
1300 new_ctx.diagnostics.report(pattern_syntax, MissingVariableInPattern);
1301 }
1302
1303 for v in variables {
1304 let var_def = Binding::LocalVar(v.var.clone());
1305 new_ctx.environment.variables.insert(v.name.clone(), var_def.clone());
1308 new_ctx.semantic_defs.insert(var_def.id(), var_def);
1309 }
1310 }
1311 let arm_expr = if is_while_let_arm {
1312 let ast::Expr::Block(arm_expr_syntax) = arm_expr_syntax else {
1313 unreachable!("Expected a block expression for a loop arm.");
1314 };
1315 let (id, _) = compute_loop_body_semantic(new_ctx, arm_expr_syntax, InnerContext::While);
1316 let expr = new_ctx.arenas.exprs[id].clone();
1317 ExprAndId { expr, id }
1318 } else {
1319 compute_expr_semantic(new_ctx, &arm_expr_syntax)
1320 };
1321 (patterns, arm_expr)
1322 })
1323}
1324
1325fn compute_expr_match_semantic(
1327 ctx: &mut ComputationContext<'_>,
1328 syntax: &ast::ExprMatch,
1329) -> Maybe<Expr> {
1330 let db = ctx.db;
1332 let syntax_db = db.upcast();
1333
1334 let syntax_arms = syntax.arms(syntax_db).elements(syntax_db);
1335 let expr = compute_expr_semantic(ctx, &syntax.expr(syntax_db));
1336 let patterns_and_exprs: Vec<_> = syntax_arms
1339 .iter()
1340 .map(|syntax_arm| {
1341 compute_arm_semantic(
1342 ctx,
1343 &expr,
1344 syntax_arm.expression(syntax_db),
1345 &syntax_arm.patterns(syntax_db),
1346 false,
1347 )
1348 })
1349 .collect();
1350 let mut helper = FlowMergeTypeHelper::new(ctx.db, MultiArmExprKind::Match);
1352 for (_, expr) in patterns_and_exprs.iter() {
1353 let expr_ty = ctx.reduce_ty(expr.ty());
1354 if !helper.try_merge_types(
1355 ctx.db,
1356 ctx.diagnostics,
1357 &mut ctx.resolver.inference(),
1358 expr_ty,
1359 expr.stable_ptr().untyped(),
1360 ) {
1361 break;
1362 };
1363 }
1364 let semantic_arms = patterns_and_exprs
1366 .into_iter()
1367 .map(|(patterns, arm_expr)| MatchArm {
1368 patterns: patterns.iter().map(|pattern| pattern.id).collect(),
1369 expression: arm_expr.id,
1370 })
1371 .collect();
1372 Ok(Expr::Match(ExprMatch {
1373 matched_expr: expr.id,
1374 arms: semantic_arms,
1375 ty: helper.get_final_type(),
1376 stable_ptr: syntax.stable_ptr().into(),
1377 }))
1378}
1379
1380fn compute_expr_if_semantic(ctx: &mut ComputationContext<'_>, syntax: &ast::ExprIf) -> Maybe<Expr> {
1382 let syntax_db = ctx.db.upcast();
1383 let (condition, if_block) = match &syntax.condition(syntax_db) {
1384 ast::Condition::Let(condition) => {
1385 let expr = compute_expr_semantic(ctx, &condition.expr(syntax_db));
1386 if let Expr::LogicalOperator(_) = expr.expr {
1387 ctx.diagnostics
1388 .report(&condition.expr(syntax_db), LogicalOperatorNotAllowedInIfLet);
1389 }
1390
1391 let (patterns, if_block) = compute_arm_semantic(
1392 ctx,
1393 &expr,
1394 ast::Expr::Block(syntax.if_block(syntax_db)),
1395 &condition.patterns(syntax_db),
1396 false,
1397 );
1398 (Condition::Let(expr.id, patterns.iter().map(|pattern| pattern.id).collect()), if_block)
1399 }
1400 ast::Condition::Expr(expr) => {
1401 let if_block = compute_expr_block_semantic(ctx, &syntax.if_block(syntax_db))?;
1402 (
1403 Condition::BoolExpr(compute_bool_condition_semantic(ctx, &expr.expr(syntax_db)).id),
1404 ExprAndId { expr: if_block.clone(), id: ctx.arenas.exprs.alloc(if_block) },
1405 )
1406 }
1407 };
1408
1409 let (else_block_opt, else_block_ty) = match syntax.else_clause(syntax_db) {
1410 ast::OptionElseClause::Empty(_) => (None, unit_ty(ctx.db)),
1411 ast::OptionElseClause::ElseClause(else_clause) => {
1412 match else_clause.else_block_or_if(syntax_db) {
1413 BlockOrIf::Block(block) => {
1414 let else_block = compute_expr_block_semantic(ctx, &block)?;
1415 (Some(else_block.clone()), else_block.ty())
1416 }
1417 BlockOrIf::If(expr_if) => {
1418 let else_if = compute_expr_if_semantic(ctx, &expr_if)?;
1419 (Some(else_if.clone()), else_if.ty())
1420 }
1421 }
1422 }
1423 };
1424
1425 let mut helper = FlowMergeTypeHelper::new(ctx.db, MultiArmExprKind::If);
1426 let if_block_ty = ctx.reduce_ty(if_block.ty());
1427 let else_block_ty = ctx.reduce_ty(else_block_ty);
1428 let inference = &mut ctx.resolver.inference();
1429 let _ = helper.try_merge_types(ctx.db, ctx.diagnostics, inference, if_block_ty, syntax.into())
1430 && helper.try_merge_types(ctx.db, ctx.diagnostics, inference, else_block_ty, syntax.into());
1431 Ok(Expr::If(ExprIf {
1432 condition,
1433 if_block: if_block.id,
1434 else_block: else_block_opt.map(|else_block| ctx.arenas.exprs.alloc(else_block)),
1435 ty: helper.get_final_type(),
1436 stable_ptr: syntax.stable_ptr().into(),
1437 }))
1438}
1439
1440fn compute_expr_loop_semantic(
1442 ctx: &mut ComputationContext<'_>,
1443 syntax: &ast::ExprLoop,
1444) -> Maybe<Expr> {
1445 let db = ctx.db;
1446 let syntax_db = db.upcast();
1447
1448 let (body, inner_ctx) =
1449 compute_loop_body_semantic(ctx, syntax.body(syntax_db), InnerContext::Loop {
1450 type_merger: FlowMergeTypeHelper::new(db, MultiArmExprKind::Loop),
1451 });
1452 Ok(Expr::Loop(ExprLoop {
1453 body,
1454 ty: match inner_ctx {
1455 InnerContext::Loop { type_merger, .. } => type_merger.get_final_type(),
1456 _ => unreachable!("Expected loop context"),
1457 },
1458 stable_ptr: syntax.stable_ptr().into(),
1459 }))
1460}
1461
1462fn compute_expr_while_semantic(
1464 ctx: &mut ComputationContext<'_>,
1465 syntax: &ast::ExprWhile,
1466) -> Maybe<Expr> {
1467 let db = ctx.db;
1468 let syntax_db = db.upcast();
1469
1470 let (condition, body) = match &syntax.condition(syntax_db) {
1471 ast::Condition::Let(condition) => {
1472 let expr = compute_expr_semantic(ctx, &condition.expr(syntax_db));
1473 if let Expr::LogicalOperator(_) = expr.expr {
1474 ctx.diagnostics
1475 .report(&condition.expr(syntax_db), LogicalOperatorNotAllowedInWhileLet);
1476 }
1477
1478 let (patterns, body) = compute_arm_semantic(
1479 ctx,
1480 &expr,
1481 ast::Expr::Block(syntax.body(syntax_db)),
1482 &condition.patterns(syntax_db),
1483 true,
1484 );
1485 (Condition::Let(expr.id, patterns.iter().map(|pattern| pattern.id).collect()), body.id)
1486 }
1487 ast::Condition::Expr(expr) => {
1488 let (body, _inner_ctx) =
1489 compute_loop_body_semantic(ctx, syntax.body(syntax_db), InnerContext::While);
1490 (
1491 Condition::BoolExpr(compute_bool_condition_semantic(ctx, &expr.expr(syntax_db)).id),
1492 body,
1493 )
1494 }
1495 };
1496
1497 Ok(Expr::While(ExprWhile {
1498 condition,
1499 body,
1500 ty: unit_ty(ctx.db),
1501 stable_ptr: syntax.stable_ptr().into(),
1502 }))
1503}
1504
1505fn compute_expr_for_semantic(
1507 ctx: &mut ComputationContext<'_>,
1508 syntax: &ast::ExprFor,
1509) -> Maybe<Expr> {
1510 let db = ctx.db;
1511 let syntax_db = db.upcast();
1512 let expr_ptr = syntax.expr(syntax_db).stable_ptr();
1513
1514 let expr = compute_expr_semantic(ctx, &syntax.expr(syntax_db));
1515 let expr_id = expr.id;
1516
1517 let into_iterator_trait =
1518 get_core_trait(ctx.db, CoreTraitContext::Iterator, "IntoIterator".into());
1519
1520 let (into_iterator_function_id, _, fixed_into_iter_var, into_iter_mutability) =
1521 compute_method_function_call_data(
1522 ctx,
1523 &[into_iterator_trait],
1524 "into_iter".into(),
1525 expr,
1526 expr_ptr.into(),
1527 None,
1528 |ty, _, inference_errors| {
1529 Some(NoImplementationOfTrait {
1530 ty,
1531 inference_errors,
1532 trait_name: "IntoIterator".into(),
1533 })
1534 },
1535 |_, _, _| {
1536 unreachable!(
1537 "There is one explicit trait, IntoIterator trait. No implementations of the \
1538 trait, caused by both lack of implementation or multiple implementations of \
1539 the trait, are handled in NoImplementationOfTrait function."
1540 )
1541 },
1542 )?;
1543 let into_iter_call = expr_function_call(
1544 ctx,
1545 into_iterator_function_id,
1546 vec![NamedArg(fixed_into_iter_var, None, into_iter_mutability)],
1547 expr_ptr,
1548 expr_ptr,
1549 )?;
1550
1551 let into_iter_variable =
1552 LocalVarLongId(ctx.resolver.module_file_id, syntax.identifier(syntax_db).stable_ptr())
1553 .intern(ctx.db);
1554
1555 let into_iter_expr = Expr::Var(ExprVar {
1556 var: VarId::Local(into_iter_variable),
1557 ty: into_iter_call.ty(),
1558 stable_ptr: into_iter_call.stable_ptr(),
1559 });
1560 let into_iter_member_path = ExprVarMemberPath::Var(ExprVar {
1561 var: VarId::Local(into_iter_variable),
1562 ty: into_iter_call.ty(),
1563 stable_ptr: into_iter_call.stable_ptr(),
1564 });
1565 let into_iter_expr_id = ctx.arenas.exprs.alloc(into_iter_expr.clone());
1566
1567 let iterator_trait = get_core_trait(ctx.db, CoreTraitContext::Iterator, "Iterator".into());
1568
1569 let (next_function_id, _, _, _) = compute_method_function_call_data(
1570 ctx,
1571 &[iterator_trait],
1572 "next".into(),
1573 ExprAndId { expr: into_iter_expr, id: into_iter_expr_id },
1574 expr_ptr.into(),
1575 None,
1576 |ty, _, inference_errors| {
1577 Some(NoImplementationOfTrait { ty, inference_errors, trait_name: "Iterator".into() })
1578 },
1579 |_, _, _| {
1580 unreachable!(
1581 "There is one explicit trait, Iterator trait. No implementations of the trait, \
1582 caused by both lack of implementation or multiple implementations of the trait, \
1583 are handled in NoImplementationOfTrait function."
1584 )
1585 },
1586 )?;
1587
1588 let next_success_variant =
1589 match db.concrete_function_signature(next_function_id)?.return_type.lookup_intern(db) {
1590 TypeLongId::Concrete(semantic::ConcreteTypeId::Enum(enm)) => {
1591 assert_eq!(enm.enum_id(db.upcast()).name(db.upcast()), "Option");
1592 db.concrete_enum_variants(enm).unwrap().into_iter().next().unwrap()
1593 }
1594 _ => unreachable!(),
1595 };
1596 let (body_id, pattern) = ctx.run_in_subscope(|new_ctx| {
1597 let inner_pattern = compute_pattern_semantic(
1598 new_ctx,
1599 &syntax.pattern(syntax_db),
1600 next_success_variant.ty,
1601 &mut UnorderedHashMap::default(),
1602 );
1603 let variables = inner_pattern.variables(&new_ctx.arenas.patterns);
1604 for v in variables {
1605 let var_def = Binding::LocalVar(v.var.clone());
1606 new_ctx.environment.variables.insert(v.name.clone(), var_def.clone());
1607 new_ctx.semantic_defs.insert(var_def.id(), var_def);
1608 }
1609 let (body, _inner_ctx) =
1610 compute_loop_body_semantic(new_ctx, syntax.body(syntax_db), InnerContext::For);
1611 (body, new_ctx.arenas.patterns.alloc(inner_pattern.pattern))
1612 });
1613 Ok(Expr::For(ExprFor {
1614 into_iter: into_iterator_function_id,
1615 into_iter_member_path,
1616 next_function_id,
1617 expr_id,
1618 pattern,
1619 body: body_id,
1620 ty: unit_ty(ctx.db),
1621 stable_ptr: syntax.stable_ptr().into(),
1622 }))
1623}
1624
1625fn compute_loop_body_semantic(
1627 ctx: &mut ComputationContext<'_>,
1628 syntax: ast::ExprBlock,
1629 inner_ctx: InnerContext,
1630) -> (ExprId, InnerContext) {
1631 let db = ctx.db;
1632 let syntax_db = db.upcast();
1633
1634 ctx.run_in_subscope(|new_ctx| {
1635 let old_inner_ctx = std::mem::replace(&mut new_ctx.inner_ctx, Some(inner_ctx));
1636
1637 let mut statements = syntax.statements(syntax_db).elements(syntax_db);
1638 let tail = get_tail_expression(syntax_db, statements.as_slice());
1640 if tail.is_some() {
1641 statements.pop();
1642 }
1643
1644 let statements_semantic: Vec<_> = statements
1646 .into_iter()
1647 .filter_map(|statement_syntax| {
1648 compute_statement_semantic(new_ctx, statement_syntax).to_option()
1649 })
1650 .collect();
1651 let tail = tail.map(|tail| compute_expr_semantic(new_ctx, &tail));
1652 if let Some(tail) = &tail {
1653 if !tail.ty().is_missing(db) && !tail.ty().is_unit(db) && tail.ty() != never_ty(db) {
1654 new_ctx.diagnostics.report(tail.deref(), TailExpressionNotAllowedInLoop);
1655 }
1656 }
1657
1658 let inner_ctx = std::mem::replace(&mut new_ctx.inner_ctx, old_inner_ctx).unwrap();
1659 let body = new_ctx.arenas.exprs.alloc(Expr::Block(ExprBlock {
1660 statements: statements_semantic,
1661 tail: tail.map(|tail| tail.id),
1662 ty: unit_ty(db),
1663 stable_ptr: syntax.stable_ptr().into(),
1664 }));
1665
1666 (body, inner_ctx)
1667 })
1668}
1669
1670fn compute_expr_closure_semantic(
1672 ctx: &mut ComputationContext<'_>,
1673 syntax: &ast::ExprClosure,
1674) -> Maybe<Expr> {
1675 ctx.are_closures_in_context = true;
1676 let syntax_db = ctx.db.upcast();
1677 let (params, ret_ty, body) = ctx.run_in_subscope(|new_ctx| {
1678 let params = if let ClosureParamWrapper::NAry(params) = syntax.wrapper(syntax_db) {
1679 function_signature_params(
1680 new_ctx.diagnostics,
1681 new_ctx.db,
1682 &mut new_ctx.resolver,
1683 ¶ms.params(syntax_db).elements(syntax_db),
1684 None,
1685 &mut new_ctx.environment,
1686 )
1687 .into_iter()
1688 .collect()
1689 } else {
1690 vec![]
1691 };
1692 let return_type = match syntax.ret_ty(syntax_db) {
1693 OptionReturnTypeClause::ReturnTypeClause(ty_syntax) => resolve_type_with_environment(
1694 new_ctx.db,
1695 new_ctx.diagnostics,
1696 &mut new_ctx.resolver,
1697 &ty_syntax.ty(syntax_db),
1698 Some(&mut new_ctx.environment),
1699 ),
1700 OptionReturnTypeClause::Empty(missing) => {
1701 new_ctx.resolver.inference().new_type_var(Some(missing.stable_ptr().untyped()))
1702 }
1703 };
1704 let old_inner_ctx =
1705 std::mem::replace(&mut new_ctx.inner_ctx, Some(InnerContext::Closure { return_type }));
1706 let body = match syntax.expr(syntax_db) {
1707 ast::Expr::Block(syntax) => compute_closure_body_semantic(new_ctx, syntax),
1708 _ => compute_expr_semantic(new_ctx, &syntax.expr(syntax_db)).id,
1709 };
1710 std::mem::replace(&mut new_ctx.inner_ctx, old_inner_ctx).unwrap();
1711 let mut inference = new_ctx.resolver.inference();
1712 if let Err((err_set, actual_ty, expected_ty)) =
1713 inference.conform_ty_for_diag(new_ctx.arenas.exprs[body].ty(), return_type)
1714 {
1715 let diag_added = new_ctx.diagnostics.report(
1716 match syntax.ret_ty(ctx.db.upcast()).stable_ptr().lookup(ctx.db.upcast()) {
1717 OptionReturnTypeClause::Empty(_) => syntax.expr(syntax_db).stable_ptr(),
1718 OptionReturnTypeClause::ReturnTypeClause(return_type_clause) => {
1719 return_type_clause.ty(ctx.db.upcast()).stable_ptr()
1720 }
1721 },
1722 WrongReturnType { expected_ty, actual_ty },
1723 );
1724 inference.consume_reported_error(err_set, diag_added);
1725 }
1726 (params, return_type, body)
1727 });
1728 let parent_function = match ctx.function_id {
1729 ContextFunction::Global => Maybe::Err(ctx.diagnostics.report(syntax, ClosureInGlobalScope)),
1730 ContextFunction::Function(function_id) => function_id,
1731 };
1732 if matches!(ctx.function_id, ContextFunction::Global) {
1733 ctx.diagnostics.report(syntax, ClosureInGlobalScope);
1734 }
1735
1736 let mut usages = Usages { usages: Default::default() };
1737 let usage = usages.handle_closure(&ctx.arenas, ¶ms, body);
1738 let mut reported = UnorderedHashSet::<_>::default();
1739 for (captured_var, expr) in
1741 chain!(usage.usage.iter(), usage.snap_usage.iter(), usage.changes.iter())
1742 {
1743 let Some(var) = ctx.semantic_defs.get(&captured_var.base_var()) else {
1744 continue;
1746 };
1747
1748 if var.is_mut() && reported.insert(expr.stable_ptr()) {
1749 ctx.diagnostics.report(expr.stable_ptr(), MutableCapturedVariable);
1750 }
1751 }
1752
1753 let captured_types = chain!(
1754 usage.snap_usage.values().map(|item| wrap_in_snapshots(ctx.db, item.ty(), 1)),
1755 chain!(usage.usage.values(), usage.changes.values()).map(|item| item.ty())
1756 )
1757 .sorted_by_key(|ty| ty.as_intern_id())
1758 .dedup()
1759 .collect_vec();
1760
1761 let ty = TypeLongId::Closure(ClosureTypeLongId {
1762 param_tys: params.iter().map(|param| param.ty).collect(),
1763 ret_ty,
1764 captured_types,
1765 parent_function,
1766 wrapper_location: StableLocation::new(syntax.wrapper(syntax_db).stable_ptr().into()),
1767 })
1768 .intern(ctx.db);
1769
1770 Ok(Expr::ExprClosure(ExprClosure { body, params, stable_ptr: syntax.stable_ptr().into(), ty }))
1771}
1772
1773fn compute_closure_body_semantic(
1775 ctx: &mut ComputationContext<'_>,
1776 syntax: ast::ExprBlock,
1777) -> ExprId {
1778 let syntax_db = ctx.db.upcast();
1779
1780 let mut statements = syntax.statements(syntax_db).elements(syntax_db);
1781 let tail = get_tail_expression(syntax_db, statements.as_slice());
1783 if tail.is_some() {
1784 statements.pop();
1785 }
1786
1787 let statements_semantic: Vec<_> = statements
1789 .into_iter()
1790 .filter_map(|statement_syntax| {
1791 compute_statement_semantic(ctx, statement_syntax).to_option()
1792 })
1793 .collect();
1794 let tail_semantic_expr = tail.map(|tail_expr| compute_expr_semantic(ctx, &tail_expr));
1796 let ty = if let Some(t) = &tail_semantic_expr {
1797 t.ty()
1798 } else if let Some(statement) = statements_semantic.last() {
1799 if let Statement::Return(_) | Statement::Break(_) = &ctx.arenas.statements[*statement] {
1800 never_ty(ctx.db)
1801 } else {
1802 unit_ty(ctx.db)
1803 }
1804 } else {
1805 unit_ty(ctx.db)
1806 };
1807 ctx.arenas.exprs.alloc(Expr::Block(ExprBlock {
1808 statements: statements_semantic,
1809 tail: tail_semantic_expr.map(|expr| expr.id),
1810 ty,
1811 stable_ptr: syntax.stable_ptr().into(),
1812 }))
1813}
1814
1815fn compute_expr_error_propagate_semantic(
1817 ctx: &mut ComputationContext<'_>,
1818 syntax: &ast::ExprErrorPropagate,
1819) -> Maybe<Expr> {
1820 let syntax_db = ctx.db.upcast();
1821
1822 let return_type = match ctx.inner_ctx {
1823 Some(InnerContext::Closure { return_type }) => return_type,
1824 None | Some(InnerContext::Loop { .. } | InnerContext::While | InnerContext::For) => {
1825 ctx.get_signature(
1826 syntax.into(),
1827 UnsupportedOutsideOfFunctionFeatureName::ErrorPropagate,
1828 )?
1829 .return_type
1830 }
1831 };
1832
1833 let func_err_prop_ty = unwrap_error_propagation_type(ctx.db, return_type)
1834 .ok_or_else(|| ctx.diagnostics.report(syntax, ReturnTypeNotErrorPropagateType))?;
1835
1836 let inner_expr = match &func_err_prop_ty {
1838 crate::corelib::ErrorPropagationType::Option { .. } => {
1839 compute_expr_semantic(ctx, &syntax.expr(syntax_db))
1840 }
1841 crate::corelib::ErrorPropagationType::Result { .. } => {
1842 compute_expr_semantic(ctx, &syntax.expr(syntax_db))
1843 }
1844 };
1845 let func_err_variant = func_err_prop_ty.err_variant();
1846
1847 let inner_expr_ty = ctx.reduce_ty(inner_expr.ty());
1848 inner_expr_ty.check_not_missing(ctx.db)?;
1849 let inner_expr_err_prop_ty =
1850 unwrap_error_propagation_type(ctx.db, inner_expr_ty).ok_or_else(|| {
1851 ctx.diagnostics.report(syntax, ErrorPropagateOnNonErrorType(inner_expr_ty))
1852 })?;
1853 let inner_expr_err_variant = inner_expr_err_prop_ty.err_variant();
1854
1855 if ctx.is_inside_loop() {
1857 ctx.diagnostics.report(syntax, SemanticDiagnosticKind::ErrorPropagateNotAllowedInsideALoop);
1858 }
1859
1860 let conformed_err_variant_ty =
1861 ctx.resolver.inference().conform_ty(func_err_variant.ty, inner_expr_err_variant.ty);
1862 let err_variant_ty = match conformed_err_variant_ty {
1865 Ok(ty) => ty,
1866 Err(err_set) => {
1867 ctx.resolver.inference().consume_error_without_reporting(err_set);
1868 inner_expr_err_variant.ty
1869 }
1870 };
1871 if func_err_variant.ty != err_variant_ty
1873 || func_err_variant.concrete_enum_id.enum_id(ctx.db)
1874 != inner_expr_err_variant.concrete_enum_id.enum_id(ctx.db)
1875 {
1876 ctx.diagnostics.report(syntax, IncompatibleErrorPropagateType {
1877 return_ty: return_type,
1878 err_ty: inner_expr_err_variant.ty,
1879 });
1880 }
1881 Ok(Expr::PropagateError(ExprPropagateError {
1882 inner: inner_expr.id,
1883 ok_variant: inner_expr_err_prop_ty.ok_variant().clone(),
1884 err_variant: inner_expr_err_variant.clone(),
1885 func_err_variant: func_err_variant.clone(),
1886 stable_ptr: syntax.stable_ptr().into(),
1887 }))
1888}
1889
1890fn compute_expr_indexed_semantic(
1892 ctx: &mut ComputationContext<'_>,
1893 syntax: &ast::ExprIndexed,
1894) -> Maybe<Expr> {
1895 let syntax_db = ctx.db.upcast();
1896 let expr = compute_expr_semantic(ctx, &syntax.expr(syntax_db));
1897 let index_expr_syntax = &syntax.index_expr(syntax_db);
1898 let index_expr = compute_expr_semantic(ctx, index_expr_syntax);
1899 ctx.resolver.inference().solve().ok();
1902 let candidate_traits: Vec<_> = ["Index", "IndexView"]
1903 .iter()
1904 .map(|trait_name| get_core_trait(ctx.db, CoreTraitContext::Ops, (*trait_name).into()))
1905 .collect();
1906 let (function_id, _, fixed_expr, mutability) = compute_method_function_call_data(
1907 ctx,
1908 &candidate_traits[..],
1909 "index".into(),
1910 expr,
1911 syntax.into(),
1912 None,
1913 |ty, _, inference_errors| Some(NoImplementationOfIndexOperator { ty, inference_errors }),
1914 |ty, _, _| Some(MultipleImplementationOfIndexOperator(ty)),
1915 )?;
1916
1917 expr_function_call(
1918 ctx,
1919 function_id,
1920 vec![
1921 NamedArg(fixed_expr, None, mutability),
1922 NamedArg(index_expr, None, Mutability::Immutable),
1923 ],
1924 syntax,
1925 index_expr_syntax.stable_ptr(),
1926 )
1927}
1928
1929#[expect(clippy::too_many_arguments)]
1934fn compute_method_function_call_data(
1935 ctx: &mut ComputationContext<'_>,
1936 candidate_traits: &[TraitId],
1937 func_name: SmolStr,
1938 self_expr: ExprAndId,
1939 method_syntax: SyntaxStablePtrId,
1940 generic_args_syntax: Option<Vec<ast::GenericArg>>,
1941 no_implementation_diagnostic: impl Fn(
1942 TypeId,
1943 SmolStr,
1944 TraitInferenceErrors,
1945 ) -> Option<SemanticDiagnosticKind>,
1946 multiple_trait_diagnostic: fn(
1947 TypeId,
1948 TraitFunctionId,
1949 TraitFunctionId,
1950 ) -> Option<SemanticDiagnosticKind>,
1951) -> Maybe<(FunctionId, TraitId, ExprAndId, Mutability)> {
1952 let self_ty = ctx.reduce_ty(self_expr.ty());
1953 let mut inference_errors = vec![];
1957 let candidates = filter_candidate_traits(
1958 ctx,
1959 &mut inference_errors,
1960 self_ty,
1961 candidate_traits,
1962 func_name.clone(),
1963 self_expr.stable_ptr().untyped(),
1964 );
1965 let trait_function_id = match candidates[..] {
1966 [] => {
1967 return Err(no_implementation_diagnostic(self_ty, func_name, TraitInferenceErrors {
1968 traits_and_errors: inference_errors,
1969 })
1970 .map(|diag| ctx.diagnostics.report(method_syntax, diag))
1971 .unwrap_or_else(skip_diagnostic));
1972 }
1973 [trait_function_id] => trait_function_id,
1974 [trait_function_id0, trait_function_id1, ..] => {
1975 return Err(multiple_trait_diagnostic(self_ty, trait_function_id0, trait_function_id1)
1976 .map(|diag| ctx.diagnostics.report(method_syntax, diag))
1977 .unwrap_or_else(skip_diagnostic));
1978 }
1979 };
1980 let (function_id, n_snapshots) =
1981 infer_impl_by_self(ctx, trait_function_id, self_ty, method_syntax, generic_args_syntax)?;
1982
1983 let signature = ctx.db.trait_function_signature(trait_function_id).unwrap();
1984 let first_param = signature.params.into_iter().next().unwrap();
1985 let mut fixed_expr = self_expr.clone();
1986 for _ in 0..n_snapshots {
1987 let ty = TypeLongId::Snapshot(fixed_expr.ty()).intern(ctx.db);
1988 let expr = Expr::Snapshot(ExprSnapshot {
1989 inner: fixed_expr.id,
1990 ty,
1991 stable_ptr: self_expr.stable_ptr(),
1992 });
1993 fixed_expr = ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) };
1994 }
1995
1996 Ok((
1997 function_id,
1998 trait_function_id.trait_id(ctx.db.upcast()),
1999 fixed_expr,
2000 first_param.mutability,
2001 ))
2002}
2003
2004pub fn compute_pattern_semantic(
2008 ctx: &mut ComputationContext<'_>,
2009 syntax: &ast::Pattern,
2010 ty: TypeId,
2011 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2012) -> PatternAndId {
2013 let pat = maybe_compute_pattern_semantic(ctx, syntax, ty, or_pattern_variables_map);
2014 let pat = pat.unwrap_or_else(|diag_added| {
2015 Pattern::Missing(PatternMissing {
2016 ty: TypeId::missing(ctx.db, diag_added),
2017 stable_ptr: syntax.stable_ptr(),
2018 diag_added,
2019 })
2020 });
2021 let id = ctx.arenas.patterns.alloc(pat.clone());
2022 PatternAndId { pattern: pat, id }
2023}
2024
2025fn maybe_compute_pattern_semantic(
2027 ctx: &mut ComputationContext<'_>,
2028 pattern_syntax: &ast::Pattern,
2029 ty: TypeId,
2030 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2031) -> Maybe<Pattern> {
2032 let syntax_db = ctx.db.upcast();
2034 let ty = ctx.reduce_ty(ty);
2035 let stable_ptr = pattern_syntax.into();
2036 let pattern = match pattern_syntax {
2037 ast::Pattern::Underscore(otherwise_pattern) => {
2038 Pattern::Otherwise(PatternOtherwise { ty, stable_ptr: otherwise_pattern.stable_ptr() })
2039 }
2040 ast::Pattern::Literal(literal_pattern) => {
2041 let literal = literal_to_semantic(ctx, literal_pattern)?;
2042 Pattern::Literal(PatternLiteral {
2043 literal,
2044 stable_ptr: literal_pattern.stable_ptr().into(),
2045 })
2046 }
2047 ast::Pattern::ShortString(short_string_pattern) => {
2048 let literal = short_string_to_semantic(ctx, short_string_pattern)?;
2049 Pattern::Literal(PatternLiteral {
2050 literal,
2051 stable_ptr: short_string_pattern.stable_ptr().into(),
2052 })
2053 }
2054 ast::Pattern::String(string_pattern) => {
2055 let string_literal = string_literal_to_semantic(ctx, string_pattern)?;
2056 Pattern::StringLiteral(PatternStringLiteral {
2057 string_literal,
2058 stable_ptr: string_pattern.stable_ptr().into(),
2059 })
2060 }
2061 ast::Pattern::Enum(enum_pattern) => {
2062 let path = enum_pattern.path(syntax_db);
2063 let item = ctx.resolver.resolve_generic_path(
2064 ctx.diagnostics,
2065 &path,
2066 NotFoundItemType::Identifier,
2067 Some(&mut ctx.environment),
2068 )?;
2069 let generic_variant = try_extract_matches!(item, ResolvedGenericItem::Variant)
2070 .ok_or_else(|| ctx.diagnostics.report(&path, NotAVariant))?;
2071
2072 let (concrete_enum, n_snapshots) = extract_concrete_enum_from_pattern_and_validate(
2073 ctx,
2074 pattern_syntax,
2075 ty,
2076 generic_variant.enum_id,
2077 )?;
2078
2079 let concrete_variant = ctx
2081 .db
2082 .concrete_enum_variant(concrete_enum, &generic_variant)
2083 .map_err(|_| ctx.diagnostics.report(&path, UnknownEnum))?;
2084
2085 let inner_ty = wrap_in_snapshots(ctx.db, concrete_variant.ty, n_snapshots);
2087
2088 let inner_pattern = match enum_pattern.pattern(syntax_db) {
2089 ast::OptionPatternEnumInnerPattern::Empty(_) => None,
2090 ast::OptionPatternEnumInnerPattern::PatternEnumInnerPattern(p) => {
2091 let pattern = compute_pattern_semantic(
2092 ctx,
2093 &p.pattern(syntax_db),
2094 inner_ty,
2095 or_pattern_variables_map,
2096 );
2097 Some(pattern.id)
2098 }
2099 };
2100
2101 Pattern::EnumVariant(PatternEnumVariant {
2102 variant: concrete_variant,
2103 inner_pattern,
2104 ty,
2105 stable_ptr: enum_pattern.stable_ptr().into(),
2106 })
2107 }
2108 ast::Pattern::Path(path) => {
2109 if path.elements(syntax_db).len() > 1 {
2112 return Err(ctx.diagnostics.report(path, Unsupported));
2113 }
2114 let identifier = path.elements(syntax_db)[0].identifier_ast(syntax_db);
2116 create_variable_pattern(
2117 ctx,
2118 identifier,
2119 &[],
2120 ty,
2121 path.stable_ptr().into(),
2122 or_pattern_variables_map,
2123 )
2124 }
2125 ast::Pattern::Identifier(identifier) => create_variable_pattern(
2126 ctx,
2127 identifier.name(syntax_db),
2128 &identifier.modifiers(syntax_db).elements(syntax_db),
2129 ty,
2130 identifier.stable_ptr().into(),
2131 or_pattern_variables_map,
2132 ),
2133 ast::Pattern::Struct(pattern_struct) => {
2134 let pattern_ty = try_extract_matches!(
2135 ctx.resolver.resolve_concrete_path_ex(
2136 ctx.diagnostics,
2137 &pattern_struct.path(syntax_db),
2138 NotFoundItemType::Type,
2139 Some(&mut ctx.environment)
2140 )?,
2141 ResolvedConcreteItem::Type
2142 )
2143 .ok_or_else(|| ctx.diagnostics.report(&pattern_struct.path(syntax_db), NotAType))?;
2144 let inference = &mut ctx.resolver.inference();
2145 inference.conform_ty(pattern_ty, peel_snapshots(ctx.db, ty).1.intern(ctx.db)).map_err(
2146 |err_set| inference.report_on_pending_error(err_set, ctx.diagnostics, stable_ptr),
2147 )?;
2148 let ty = ctx.reduce_ty(ty);
2149 let (n_snapshots, long_ty) = peel_snapshots(ctx.db, ty);
2151
2152 let concrete_struct_id = try_extract_matches!(long_ty, TypeLongId::Concrete)
2154 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Struct))
2155 .ok_or(())
2156 .or_else(|_| {
2157 ty.check_not_missing(ctx.db)?;
2160 Err(ctx.diagnostics.report(pattern_struct, UnexpectedStructPattern(ty)))
2161 })?;
2162 let pattern_param_asts = pattern_struct.params(syntax_db).elements(syntax_db);
2163 let struct_id = concrete_struct_id.struct_id(ctx.db);
2164 let mut members = ctx.db.concrete_struct_members(concrete_struct_id)?.as_ref().clone();
2165 let mut used_members = UnorderedHashSet::<_>::default();
2166 let mut get_member = |ctx: &mut ComputationContext<'_>,
2167 member_name: SmolStr,
2168 stable_ptr: SyntaxStablePtrId| {
2169 let member = members.swap_remove(&member_name).on_none(|| {
2170 ctx.diagnostics.report(
2171 stable_ptr,
2172 if used_members.contains(&member_name) {
2173 StructMemberRedefinition { struct_id, member_name: member_name.clone() }
2174 } else {
2175 NoSuchStructMember { struct_id, member_name: member_name.clone() }
2176 },
2177 );
2178 })?;
2179 check_struct_member_is_visible(ctx, &member, stable_ptr, &member_name);
2180 used_members.insert(member_name);
2181 Some(member)
2182 };
2183 let mut field_patterns = vec![];
2184 let mut has_tail = false;
2185 for pattern_param_ast in pattern_param_asts {
2186 match pattern_param_ast {
2187 PatternStructParam::Single(single) => {
2188 let name = single.name(syntax_db);
2189 let Some(member) =
2190 get_member(ctx, name.text(syntax_db), name.stable_ptr().untyped())
2191 else {
2192 continue;
2193 };
2194 let ty = wrap_in_snapshots(ctx.db, member.ty, n_snapshots);
2195 let pattern = create_variable_pattern(
2196 ctx,
2197 name,
2198 &single.modifiers(syntax_db).elements(syntax_db),
2199 ty,
2200 single.stable_ptr().into(),
2201 or_pattern_variables_map,
2202 );
2203 field_patterns.push((member, ctx.arenas.patterns.alloc(pattern)));
2204 }
2205 PatternStructParam::WithExpr(with_expr) => {
2206 let name = with_expr.name(syntax_db);
2207 let Some(member) =
2208 get_member(ctx, name.text(syntax_db), name.stable_ptr().untyped())
2209 else {
2210 continue;
2211 };
2212 let ty = wrap_in_snapshots(ctx.db, member.ty, n_snapshots);
2213 let pattern = compute_pattern_semantic(
2214 ctx,
2215 &with_expr.pattern(syntax_db),
2216 ty,
2217 or_pattern_variables_map,
2218 );
2219 field_patterns.push((member, pattern.id));
2220 }
2221 PatternStructParam::Tail(_) => {
2222 has_tail = true;
2223 }
2224 }
2225 }
2226 if !has_tail {
2227 for (member_name, _) in members.iter() {
2228 ctx.diagnostics.report(pattern_struct, MissingMember(member_name.clone()));
2229 }
2230 }
2231 Pattern::Struct(PatternStruct {
2232 concrete_struct_id,
2233 field_patterns,
2234 ty,
2235 n_snapshots,
2236 stable_ptr: pattern_struct.stable_ptr(),
2237 })
2238 }
2239 ast::Pattern::Tuple(_) => maybe_compute_tuple_like_pattern_semantic(
2240 ctx,
2241 pattern_syntax,
2242 ty,
2243 or_pattern_variables_map,
2244 |ty: TypeId| UnexpectedTuplePattern(ty),
2245 |expected, actual| WrongNumberOfTupleElements { expected, actual },
2246 )?,
2247 ast::Pattern::FixedSizeArray(_) => maybe_compute_tuple_like_pattern_semantic(
2248 ctx,
2249 pattern_syntax,
2250 ty,
2251 or_pattern_variables_map,
2252 |ty: TypeId| UnexpectedFixedSizeArrayPattern(ty),
2253 |expected, actual| WrongNumberOfFixedSizeArrayElements { expected, actual },
2254 )?,
2255 ast::Pattern::False(pattern_false) => {
2256 let enum_expr = extract_matches!(
2257 false_literal_expr(ctx, pattern_false.stable_ptr().into()),
2258 Expr::EnumVariantCtor
2259 );
2260
2261 extract_concrete_enum_from_pattern_and_validate(
2262 ctx,
2263 pattern_syntax,
2264 ty,
2265 enum_expr.variant.concrete_enum_id.enum_id(ctx.db),
2266 )?;
2267
2268 Pattern::EnumVariant(PatternEnumVariant {
2269 variant: enum_expr.variant,
2270 stable_ptr: pattern_false.stable_ptr().into(),
2271 ty,
2272 inner_pattern: None,
2273 })
2274 }
2275 ast::Pattern::True(pattern_true) => {
2276 let enum_expr = extract_matches!(
2277 true_literal_expr(ctx, pattern_true.stable_ptr().into()),
2278 Expr::EnumVariantCtor
2279 );
2280 extract_concrete_enum_from_pattern_and_validate(
2281 ctx,
2282 pattern_syntax,
2283 ty,
2284 enum_expr.variant.concrete_enum_id.enum_id(ctx.db),
2285 )?;
2286
2287 Pattern::EnumVariant(PatternEnumVariant {
2288 variant: enum_expr.variant,
2289 stable_ptr: pattern_true.stable_ptr().into(),
2290 ty,
2291 inner_pattern: None,
2292 })
2293 }
2294 };
2295 let inference = &mut ctx.resolver.inference();
2296 inference.conform_ty(pattern.ty(), ty).map_err(|err_set| {
2297 inference.report_on_pending_error(err_set, ctx.diagnostics, stable_ptr)
2298 })?;
2299 Ok(pattern)
2300}
2301
2302fn maybe_compute_tuple_like_pattern_semantic(
2305 ctx: &mut ComputationContext<'_>,
2306 pattern_syntax: &ast::Pattern,
2307 ty: TypeId,
2308 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2309 unexpected_pattern: fn(TypeId) -> SemanticDiagnosticKind,
2310 wrong_number_of_elements: fn(usize, usize) -> SemanticDiagnosticKind,
2311) -> Maybe<Pattern> {
2312 let (n_snapshots, long_ty) = finalized_snapshot_peeled_ty(ctx, ty, pattern_syntax)?;
2313 match (pattern_syntax, &long_ty) {
2315 (ast::Pattern::Tuple(_), TypeLongId::Tuple(_))
2316 | (ast::Pattern::FixedSizeArray(_), TypeLongId::FixedSizeArray { .. }) => {}
2317 _ => {
2318 return Err(ctx.diagnostics.report(pattern_syntax, unexpected_pattern(ty)));
2319 }
2320 };
2321 let inner_tys = match long_ty {
2322 TypeLongId::Tuple(inner_tys) => inner_tys,
2323 TypeLongId::FixedSizeArray { type_id: inner_ty, size } => {
2324 let size = size
2325 .lookup_intern(ctx.db)
2326 .into_int()
2327 .expect("Expected ConstValue::Int for size")
2328 .to_usize()
2329 .unwrap();
2330 [inner_ty].repeat(size)
2331 }
2332 _ => unreachable!(),
2333 };
2334 let patterns_syntax = match pattern_syntax {
2335 ast::Pattern::Tuple(pattern_tuple) => {
2336 pattern_tuple.patterns(ctx.db.upcast()).elements(ctx.db.upcast())
2337 }
2338 ast::Pattern::FixedSizeArray(pattern_fixed_size_array) => {
2339 pattern_fixed_size_array.patterns(ctx.db.upcast()).elements(ctx.db.upcast())
2340 }
2341 _ => unreachable!(),
2342 };
2343 let size = inner_tys.len();
2344 if size != patterns_syntax.len() {
2345 return Err(ctx
2346 .diagnostics
2347 .report(pattern_syntax, wrong_number_of_elements(size, patterns_syntax.len())));
2348 }
2349 let pattern_options = zip_eq(patterns_syntax, inner_tys).map(|(pattern_ast, ty)| {
2350 let ty = wrap_in_snapshots(ctx.db, ty, n_snapshots);
2351 let pattern = compute_pattern_semantic(ctx, &pattern_ast, ty, or_pattern_variables_map);
2352 Ok(pattern.id)
2353 });
2354 let field_patterns: Vec<_> = pattern_options.collect::<Maybe<_>>()?;
2356 Ok(match pattern_syntax {
2357 ast::Pattern::Tuple(syntax) => {
2358 Pattern::Tuple(PatternTuple { field_patterns, ty, stable_ptr: syntax.stable_ptr() })
2359 }
2360 ast::Pattern::FixedSizeArray(syntax) => Pattern::FixedSizeArray(PatternFixedSizeArray {
2361 elements_patterns: field_patterns,
2362 ty,
2363 stable_ptr: syntax.stable_ptr(),
2364 }),
2365 _ => unreachable!(),
2366 })
2367}
2368
2369fn extract_concrete_enum_from_pattern_and_validate(
2371 ctx: &mut ComputationContext<'_>,
2372 pattern: &ast::Pattern,
2373 ty: TypeId,
2374 enum_id: EnumId,
2375) -> Maybe<(ConcreteEnumId, usize)> {
2376 let (n_snapshots, long_ty) = finalized_snapshot_peeled_ty(ctx, ty, pattern)?;
2378
2379 let concrete_enum = try_extract_matches!(long_ty, TypeLongId::Concrete)
2381 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Enum))
2382 .ok_or(())
2383 .or_else(|_| {
2384 ty.check_not_missing(ctx.db)?;
2387 Err(ctx.diagnostics.report(pattern, UnexpectedEnumPattern(ty)))
2388 })?;
2389 if enum_id != concrete_enum.enum_id(ctx.db) {
2391 return Err(ctx.diagnostics.report(pattern, WrongEnum {
2392 expected_enum: concrete_enum.enum_id(ctx.db),
2393 actual_enum: enum_id,
2394 }));
2395 }
2396 Ok((concrete_enum, n_snapshots))
2397}
2398
2399fn create_variable_pattern(
2401 ctx: &mut ComputationContext<'_>,
2402 identifier: ast::TerminalIdentifier,
2403 modifier_list: &[ast::Modifier],
2404 ty: TypeId,
2405 stable_ptr: ast::PatternPtr,
2406 or_pattern_variables_map: &mut UnorderedHashMap<SmolStr, LocalVariable>,
2407) -> Pattern {
2408 let syntax_db = ctx.db.upcast();
2409
2410 let var_id = match or_pattern_variables_map.get(&identifier.text(syntax_db)) {
2411 Some(var) => var.id,
2412 None => LocalVarLongId(ctx.resolver.module_file_id, identifier.stable_ptr()).intern(ctx.db),
2413 };
2414 let is_mut = match compute_mutability(ctx.diagnostics, syntax_db, modifier_list) {
2415 Mutability::Immutable => false,
2416 Mutability::Mutable => true,
2417 Mutability::Reference => {
2418 ctx.diagnostics.report(&identifier, ReferenceLocalVariable);
2419 false
2420 }
2421 };
2422 Pattern::Variable(PatternVariable {
2423 name: identifier.text(syntax_db),
2424 var: LocalVariable { id: var_id, ty, is_mut },
2425 stable_ptr,
2426 })
2427}
2428
2429fn struct_ctor_expr(
2431 ctx: &mut ComputationContext<'_>,
2432 ctor_syntax: &ast::ExprStructCtorCall,
2433) -> Maybe<Expr> {
2434 let db = ctx.db;
2435 let syntax_db = db.upcast();
2436 let path = ctor_syntax.path(syntax_db);
2437
2438 let ty = resolve_type_with_environment(
2440 db,
2441 ctx.diagnostics,
2442 &mut ctx.resolver,
2443 &ast::Expr::Path(path.clone()),
2444 Some(&mut ctx.environment),
2445 );
2446 ty.check_not_missing(db)?;
2447
2448 let concrete_struct_id = try_extract_matches!(ty.lookup_intern(ctx.db), TypeLongId::Concrete)
2449 .and_then(|c| try_extract_matches!(c, ConcreteTypeId::Struct))
2450 .ok_or_else(|| ctx.diagnostics.report(&path, NotAStruct))?;
2451
2452 if ty.is_phantom(db) {
2453 ctx.diagnostics.report(ctor_syntax, CannotCreateInstancesOfPhantomTypes);
2454 }
2455
2456 let members = db.concrete_struct_members(concrete_struct_id)?;
2457 let mut member_exprs: OrderedHashMap<MemberId, Option<ExprId>> = OrderedHashMap::default();
2458 let mut base_struct = None;
2459
2460 for (index, arg) in ctor_syntax
2461 .arguments(syntax_db)
2462 .arguments(syntax_db)
2463 .elements(syntax_db)
2464 .into_iter()
2465 .enumerate()
2466 {
2467 match arg {
2469 ast::StructArg::StructArgSingle(arg) => {
2470 let arg_identifier = arg.identifier(syntax_db);
2471 let arg_name = arg_identifier.text(syntax_db);
2472
2473 let Some(member) = members.get(&arg_name) else {
2475 ctx.diagnostics.report(&arg_identifier, UnknownMember);
2476 continue;
2477 };
2478 check_struct_member_is_visible(
2479 ctx,
2480 member,
2481 arg_identifier.stable_ptr().untyped(),
2482 &arg_name,
2483 );
2484
2485 let arg_expr = match arg.arg_expr(syntax_db) {
2487 ast::OptionStructArgExpr::Empty(_) => {
2488 let Ok(expr) = resolve_variable_by_name(
2489 ctx,
2490 &arg_identifier,
2491 path.stable_ptr().into(),
2492 ) else {
2493 if member_exprs.insert(member.id, None).is_some() {
2495 ctx.diagnostics
2496 .report(&arg_identifier, MemberSpecifiedMoreThanOnce);
2497 }
2498 continue;
2499 };
2500 ExprAndId { expr: expr.clone(), id: ctx.arenas.exprs.alloc(expr) }
2501 }
2502 ast::OptionStructArgExpr::StructArgExpr(arg_expr) => {
2503 compute_expr_semantic(ctx, &arg_expr.expr(syntax_db))
2504 }
2505 };
2506
2507 if member_exprs.insert(member.id, Some(arg_expr.id)).is_some() {
2509 ctx.diagnostics.report(&arg_identifier, MemberSpecifiedMoreThanOnce);
2510 }
2511
2512 let inference = &mut ctx.resolver.inference();
2514 if let Err((err_set, actual_ty, expected_ty)) =
2515 inference.conform_ty_for_diag(arg_expr.ty(), member.ty)
2516 {
2517 if !expected_ty.is_missing(db) {
2518 let diag_added = ctx
2519 .diagnostics
2520 .report(&arg_identifier, WrongArgumentType { expected_ty, actual_ty });
2521 inference.consume_reported_error(err_set, diag_added);
2522 }
2523 continue;
2524 }
2525 }
2526 ast::StructArg::StructArgTail(base_struct_syntax) => {
2527 if index
2529 != ctor_syntax
2530 .arguments(syntax_db)
2531 .arguments(syntax_db)
2532 .elements(syntax_db)
2533 .len()
2534 - 1
2535 {
2536 ctx.diagnostics.report(&base_struct_syntax, StructBaseStructExpressionNotLast);
2537 continue;
2538 }
2539 let base_struct_expr =
2540 compute_expr_semantic(ctx, &base_struct_syntax.expression(syntax_db));
2541 let inference = &mut ctx.resolver.inference();
2542 if let Err((err_set, actual_ty, expected_ty)) =
2543 inference.conform_ty_for_diag(base_struct_expr.ty(), ty)
2544 {
2545 let diag_added = ctx.diagnostics.report(
2546 &base_struct_syntax.expression(syntax_db),
2547 WrongArgumentType { expected_ty, actual_ty },
2548 );
2549 inference.consume_reported_error(err_set, diag_added);
2550 continue;
2551 }
2552
2553 base_struct = Some((base_struct_expr.id, base_struct_syntax));
2554 }
2555 };
2556 }
2557
2558 for (member_name, member) in members.iter() {
2560 if !member_exprs.contains_key(&member.id) {
2561 if base_struct.is_some() {
2562 check_struct_member_is_visible(
2563 ctx,
2564 member,
2565 base_struct.clone().unwrap().1.stable_ptr().untyped(),
2566 member_name,
2567 );
2568 } else {
2569 ctx.diagnostics.report(ctor_syntax, MissingMember(member_name.clone()));
2570 }
2571 }
2572 }
2573 if members.len() == member_exprs.len() {
2574 if let Some((_, base_struct_syntax)) = base_struct {
2575 return Err(ctx
2576 .diagnostics
2577 .report(&base_struct_syntax, StructBaseStructExpressionNoEffect));
2578 }
2579 }
2580 Ok(Expr::StructCtor(ExprStructCtor {
2581 concrete_struct_id,
2582 members: member_exprs.into_iter().filter_map(|(x, y)| Some((x, y?))).collect(),
2583 base_struct: base_struct.map(|(x, _)| x),
2584 ty: TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)).intern(db),
2585 stable_ptr: ctor_syntax.stable_ptr().into(),
2586 }))
2587}
2588
2589fn get_tail_expression(
2593 syntax_db: &dyn SyntaxGroup,
2594 statements: &[ast::Statement],
2595) -> Option<ast::Expr> {
2596 let last = statements.last()?;
2597 let statement_expr = try_extract_matches!(last, ast::Statement::Expr)?;
2598 try_extract_matches!(statement_expr.semicolon(syntax_db), ast::OptionTerminalSemicolon::Empty)?;
2599 Some(statement_expr.expr(syntax_db))
2600}
2601
2602fn new_literal_expr(
2604 ctx: &mut ComputationContext<'_>,
2605 ty: Option<&str>,
2606 value: BigInt,
2607 stable_ptr: ExprPtr,
2608) -> Maybe<ExprLiteral> {
2609 let ty = if let Some(ty_str) = ty {
2610 if ty_str == "NonZero" {
2612 return Err(ctx.diagnostics.report(
2613 stable_ptr.untyped(),
2614 SemanticDiagnosticKind::WrongNumberOfArguments { expected: 1, actual: 0 },
2615 ));
2616 }
2617 try_get_core_ty_by_name(ctx.db, ty_str.into(), vec![])
2618 .map_err(|err| ctx.diagnostics.report(stable_ptr.untyped(), err))?
2619 } else {
2620 ctx.resolver.inference().new_type_var(Some(stable_ptr.untyped()))
2621 };
2622
2623 let trait_id = numeric_literal_trait(ctx.db);
2625 let generic_args = vec![GenericArgumentId::Type(ty)];
2626 let concrete_trait_id = semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(ctx.db);
2627 let lookup_context = ctx.resolver.impl_lookup_context();
2628 let inference = &mut ctx.resolver.inference();
2629 inference.new_impl_var(concrete_trait_id, Some(stable_ptr.untyped()), lookup_context);
2630
2631 Ok(ExprLiteral { value, ty, stable_ptr })
2632}
2633
2634fn literal_to_semantic(
2636 ctx: &mut ComputationContext<'_>,
2637 literal_syntax: &ast::TerminalLiteralNumber,
2638) -> Maybe<ExprLiteral> {
2639 let db = ctx.db;
2640 let syntax_db = db.upcast();
2641
2642 let (value, ty) = literal_syntax.numeric_value_and_suffix(syntax_db).unwrap_or_default();
2643 let ty = ty.as_ref().map(SmolStr::as_str);
2644
2645 new_literal_expr(ctx, ty, value, literal_syntax.stable_ptr().into())
2646}
2647
2648fn short_string_to_semantic(
2650 ctx: &mut ComputationContext<'_>,
2651 short_string_syntax: &ast::TerminalShortString,
2652) -> Maybe<ExprLiteral> {
2653 let db = ctx.db;
2654 let syntax_db = db.upcast();
2655
2656 let value = short_string_syntax.numeric_value(syntax_db).unwrap_or_default();
2657
2658 let suffix = short_string_syntax.suffix(syntax_db);
2659 let suffix = suffix.as_ref().map(SmolStr::as_str);
2660
2661 new_literal_expr(ctx, suffix, value, short_string_syntax.stable_ptr().into())
2662}
2663
2664fn new_string_literal_expr(
2666 ctx: &mut ComputationContext<'_>,
2667 value: String,
2668 stable_ptr: ExprPtr,
2669) -> Maybe<ExprStringLiteral> {
2670 let ty = ctx.resolver.inference().new_type_var(Some(stable_ptr.untyped()));
2671
2672 let trait_id = get_core_trait(ctx.db, CoreTraitContext::TopLevel, "StringLiteral".into());
2674 let generic_args = vec![GenericArgumentId::Type(ty)];
2675 let concrete_trait_id = semantic::ConcreteTraitLongId { trait_id, generic_args }.intern(ctx.db);
2676 let lookup_context = ctx.resolver.impl_lookup_context();
2677 let inference = &mut ctx.resolver.inference();
2678 inference.new_impl_var(concrete_trait_id, Some(stable_ptr.untyped()), lookup_context);
2679
2680 Ok(ExprStringLiteral { value, ty, stable_ptr })
2681}
2682
2683fn string_literal_to_semantic(
2685 ctx: &mut ComputationContext<'_>,
2686 string_syntax: &ast::TerminalString,
2687) -> Maybe<ExprStringLiteral> {
2688 let db = ctx.db;
2689 let syntax_db = db.upcast();
2690 let stable_ptr = string_syntax.stable_ptr();
2691
2692 let value = string_syntax.string_value(syntax_db).unwrap_or_default();
2693 new_string_literal_expr(ctx, value, stable_ptr.into())
2696}
2697
2698fn expr_as_identifier(
2701 ctx: &mut ComputationContext<'_>,
2702 path: &ast::ExprPath,
2703 syntax_db: &dyn SyntaxGroup,
2704) -> Maybe<SmolStr> {
2705 let segments = path.elements(syntax_db);
2706 if segments.len() == 1 {
2707 return Ok(segments[0].identifier(syntax_db));
2708 }
2709 Err(ctx.diagnostics.report(path, InvalidMemberExpression))
2710}
2711
2712fn dot_expr(
2715 ctx: &mut ComputationContext<'_>,
2716 lexpr: ExprAndId,
2717 rhs_syntax: ast::Expr,
2718 stable_ptr: ast::ExprPtr,
2719) -> Maybe<Expr> {
2720 match rhs_syntax {
2722 ast::Expr::Path(expr) => member_access_expr(ctx, lexpr, expr, stable_ptr),
2723 ast::Expr::FunctionCall(expr) => method_call_expr(ctx, lexpr, expr, stable_ptr),
2724 _ => Err(ctx.diagnostics.report(&rhs_syntax, InvalidMemberExpression)),
2725 }
2726}
2727
2728fn traits_in_context(
2730 ctx: &mut ComputationContext<'_>,
2731) -> Maybe<OrderedHashMap<TraitId, LookupItemId>> {
2732 let mut traits =
2733 ctx.db.module_usable_trait_ids(ctx.resolver.prelude_submodule())?.deref().clone();
2734 traits.extend(
2735 ctx.db
2736 .module_usable_trait_ids(ctx.resolver.module_file_id.0)?
2737 .iter()
2738 .map(|(k, v)| (*k, *v)),
2739 );
2740 Ok(traits)
2741}
2742
2743fn method_call_expr(
2747 ctx: &mut ComputationContext<'_>,
2748 lexpr: ExprAndId,
2749 expr: ast::ExprFunctionCall,
2750 stable_ptr: ast::ExprPtr,
2751) -> Maybe<Expr> {
2752 let syntax_db = ctx.db.upcast();
2755 let path = expr.path(syntax_db);
2756 let Ok([segment]): Result<[_; 1], _> = path.elements(syntax_db).try_into() else {
2757 return Err(ctx.diagnostics.report(&expr, InvalidMemberExpression));
2758 };
2759 let func_name = segment.identifier(syntax_db);
2760 let generic_args_syntax = segment.generic_args(syntax_db);
2761 ctx.resolver.inference().solve().ok();
2763
2764 let mut candidate_traits = traits_in_context(ctx)?;
2765
2766 for generic_param in &ctx.resolver.data.generic_params {
2768 if generic_param.kind(ctx.db.upcast()) == GenericKind::Impl {
2769 let Ok(trait_id) = ctx.db.generic_impl_param_trait(*generic_param) else {
2770 continue;
2771 };
2772 candidate_traits
2773 .insert(trait_id, LookupItemId::ModuleItem(ModuleItemId::Trait(trait_id)));
2774 }
2775 }
2776
2777 let (function_id, actual_trait_id, fixed_lexpr, mutability) =
2778 compute_method_function_call_data(
2779 ctx,
2780 candidate_traits.keys().copied().collect_vec().as_slice(),
2781 func_name,
2782 lexpr,
2783 path.stable_ptr().untyped(),
2784 generic_args_syntax,
2785 |ty, method_name, inference_errors| {
2786 Some(CannotCallMethod { ty, method_name, inference_errors })
2787 },
2788 |_, trait_function_id0, trait_function_id1| {
2789 Some(AmbiguousTrait { trait_function_id0, trait_function_id1 })
2790 },
2791 )?;
2792 ctx.resolver.data.used_items.insert(candidate_traits[&actual_trait_id]);
2793
2794 ctx.resolver.data.resolved_items.mark_concrete(
2795 ctx.db,
2796 &segment,
2797 ResolvedConcreteItem::Function(function_id),
2798 );
2799
2800 let mut args_iter =
2802 expr.arguments(syntax_db).arguments(syntax_db).elements(syntax_db).into_iter();
2803 let mut named_args = vec![NamedArg(fixed_lexpr, None, mutability)];
2805 for _ in function_parameter_types(ctx, function_id)?.skip(1) {
2807 let Some(arg_syntax) = args_iter.next() else {
2808 break;
2809 };
2810 named_args.push(compute_named_argument_clause(ctx, arg_syntax));
2811 }
2812
2813 if let Some(arg_syntax) = args_iter.next() {
2815 named_args.push(compute_named_argument_clause(ctx, arg_syntax));
2816 }
2817
2818 expr_function_call(ctx, function_id, named_args, &expr, stable_ptr)
2819}
2820
2821fn member_access_expr(
2823 ctx: &mut ComputationContext<'_>,
2824 lexpr: ExprAndId,
2825 rhs_syntax: ast::ExprPath,
2826 stable_ptr: ast::ExprPtr,
2827) -> Maybe<Expr> {
2828 let syntax_db = ctx.db.upcast();
2829
2830 let member_name = expr_as_identifier(ctx, &rhs_syntax, syntax_db)?;
2832 let (n_snapshots, long_ty) = finalized_snapshot_peeled_ty(ctx, lexpr.ty(), &rhs_syntax)?;
2833
2834 match &long_ty {
2835 TypeLongId::Concrete(_) | TypeLongId::Tuple(_) | TypeLongId::FixedSizeArray { .. } => {
2836 let Some(EnrichedTypeMemberAccess { member, deref_functions }) =
2837 get_enriched_type_member_access(ctx, lexpr.clone(), stable_ptr, &member_name)?
2838 else {
2839 return Err(ctx.diagnostics.report(&rhs_syntax, NoSuchTypeMember {
2840 ty: long_ty.intern(ctx.db),
2841 member_name,
2842 }));
2843 };
2844 check_struct_member_is_visible(
2845 ctx,
2846 &member,
2847 rhs_syntax.stable_ptr().untyped(),
2848 &member_name,
2849 );
2850 let member_path = match &long_ty {
2851 TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id))
2852 if n_snapshots == 0 && deref_functions.is_empty() =>
2853 {
2854 lexpr.as_member_path().map(|parent| ExprVarMemberPath::Member {
2855 parent: Box::new(parent),
2856 member_id: member.id,
2857 stable_ptr,
2858 concrete_struct_id: *concrete_struct_id,
2859 ty: member.ty,
2860 })
2861 }
2862 _ => None,
2863 };
2864 let mut derefed_expr: ExprAndId = lexpr;
2865 for (deref_function, mutability) in &deref_functions {
2866 let cur_expr = expr_function_call(
2867 ctx,
2868 *deref_function,
2869 vec![NamedArg(derefed_expr, None, *mutability)],
2870 stable_ptr,
2871 stable_ptr,
2872 )
2873 .unwrap();
2874
2875 derefed_expr =
2876 ExprAndId { expr: cur_expr.clone(), id: ctx.arenas.exprs.alloc(cur_expr) };
2877 }
2878 let (_, long_ty) = finalized_snapshot_peeled_ty(ctx, derefed_expr.ty(), &rhs_syntax)?;
2879 let derefed_expr_concrete_struct_id = match long_ty {
2880 TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) => {
2881 concrete_struct_id
2882 }
2883 _ => unreachable!(),
2884 };
2885 let ty = if !deref_functions.is_empty() {
2886 member.ty
2887 } else {
2888 wrap_in_snapshots(ctx.db, member.ty, n_snapshots)
2889 };
2890 Ok(Expr::MemberAccess(ExprMemberAccess {
2891 expr: derefed_expr.id,
2892 concrete_struct_id: derefed_expr_concrete_struct_id,
2893 member: member.id,
2894 ty,
2895 member_path,
2896 n_snapshots,
2897 stable_ptr,
2898 }))
2899 }
2900
2901 TypeLongId::Snapshot(_) => {
2902 Err(ctx.diagnostics.report(&rhs_syntax, Unsupported))
2904 }
2905 TypeLongId::Closure(_) => Err(ctx.diagnostics.report(&rhs_syntax, Unsupported)),
2906 TypeLongId::ImplType(impl_type_id) => {
2907 unreachable!(
2908 "Impl type should've been reduced {:?}.",
2909 impl_type_id.debug(ctx.db.elongate())
2910 )
2911 }
2912 TypeLongId::Var(_) => Err(ctx.diagnostics.report(
2913 &rhs_syntax,
2914 InternalInferenceError(InferenceError::TypeNotInferred(long_ty.intern(ctx.db))),
2915 )),
2916 TypeLongId::GenericParameter(_) | TypeLongId::Coupon(_) => Err(ctx
2917 .diagnostics
2918 .report(&rhs_syntax, TypeHasNoMembers { ty: long_ty.intern(ctx.db), member_name })),
2919 TypeLongId::Missing(diag_added) => Err(*diag_added),
2920 TypeLongId::TraitType(_) => {
2921 panic!("Trait types should only appear in traits, where there are no function bodies.")
2922 }
2923 }
2924}
2925
2926fn get_enriched_type_member_access(
2931 ctx: &mut ComputationContext<'_>,
2932 expr: ExprAndId,
2933 stable_ptr: ast::ExprPtr,
2934 accessed_member_name: &str,
2935) -> Maybe<Option<EnrichedTypeMemberAccess>> {
2936 let (_, mut long_ty) = peel_snapshots(ctx.db, expr.ty());
2937 if matches!(long_ty, TypeLongId::Var(_)) {
2938 ctx.resolver.inference().solve().ok();
2940 long_ty = ctx.resolver.inference().rewrite(long_ty).no_err();
2941 }
2942 let (_, long_ty) = peel_snapshots_ex(ctx.db, long_ty);
2943 let base_var = match &expr.expr {
2944 Expr::Var(expr_var) => Some(expr_var.var),
2945 Expr::MemberAccess(ExprMemberAccess { member_path: Some(member_path), .. }) => {
2946 Some(member_path.base_var())
2947 }
2948 _ => None,
2949 };
2950 let is_mut_var = base_var
2951 .filter(|var_id| matches!(ctx.semantic_defs.get(var_id), Some(var) if var.is_mut()))
2952 .is_some();
2953 let ty = long_ty.clone().intern(ctx.db);
2954 let key = (ty, is_mut_var);
2955 let mut enriched_members = match ctx.resolver.type_enriched_members.entry(key) {
2956 Entry::Occupied(entry) => {
2957 let e = entry.get();
2958 match e.get_member(accessed_member_name) {
2959 Some(value) => return Ok(Some(value)),
2960 None => {
2961 if e.exploration_tail.is_none() {
2962 return Ok(None);
2964 }
2965 }
2966 }
2967 entry.swap_remove()
2969 }
2970 Entry::Vacant(_) => {
2971 let members =
2972 if let TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) = long_ty {
2973 let members = ctx.db.concrete_struct_members(concrete_struct_id)?;
2974 if let Some(member) = members.get(accessed_member_name) {
2975 return Ok(Some(EnrichedTypeMemberAccess {
2977 member: member.clone(),
2978 deref_functions: vec![],
2979 }));
2980 }
2981 members.iter().map(|(k, v)| (k.clone(), (v.clone(), 0))).collect()
2982 } else {
2983 Default::default()
2984 };
2985 EnrichedMembers { members, deref_functions: vec![], exploration_tail: Some(expr.id) }
2986 }
2987 };
2988 enrich_members(ctx, &mut enriched_members, is_mut_var, stable_ptr, accessed_member_name)?;
2989 let e = ctx.resolver.type_enriched_members.entry(key).or_insert(enriched_members);
2990 Ok(e.get_member(accessed_member_name))
2991}
2992
2993fn enrich_members(
2998 ctx: &mut ComputationContext<'_>,
2999 enriched_members: &mut EnrichedMembers,
3000 is_mut_var: bool,
3001 stable_ptr: ast::ExprPtr,
3002 accessed_member_name: &str,
3003) -> Maybe<()> {
3004 let EnrichedMembers { members: enriched, deref_functions, exploration_tail } = enriched_members;
3005 let mut visited_types: OrderedHashSet<TypeId> = OrderedHashSet::default();
3006
3007 let expr_id =
3008 exploration_tail.expect("`enrich_members` should be called with a `calc_tail` value.");
3009 let mut expr = ExprAndId { expr: ctx.arenas.exprs[expr_id].clone(), id: expr_id };
3010
3011 let deref_mut_trait_id = deref_mut_trait(ctx.db);
3012 let deref_trait_id = deref_trait(ctx.db);
3013
3014 let compute_deref_method_function_call_data =
3015 |ctx: &mut ComputationContext<'_>, expr: ExprAndId, use_deref_mut: bool| {
3016 let deref_trait = if use_deref_mut { deref_mut_trait_id } else { deref_trait_id };
3017 compute_method_function_call_data(
3018 ctx,
3019 &[deref_trait],
3020 if use_deref_mut { "deref_mut".into() } else { "deref".into() },
3021 expr.clone(),
3022 stable_ptr.0,
3023 None,
3024 |_, _, _| None,
3025 |_, _, _| None,
3026 )
3027 };
3028
3029 let mut use_deref_mut = deref_functions.is_empty()
3031 && is_mut_var
3032 && compute_deref_method_function_call_data(ctx, expr.clone(), true).is_ok();
3033
3034 *exploration_tail = None;
3037
3038 while let Ok((function_id, _, cur_expr, mutability)) =
3040 compute_deref_method_function_call_data(ctx, expr, use_deref_mut)
3041 {
3042 deref_functions.push((function_id, mutability));
3043 use_deref_mut = false;
3044 let n_deref = deref_functions.len();
3045 expr = cur_expr;
3046 let derefed_expr = expr_function_call(
3047 ctx,
3048 function_id,
3049 vec![NamedArg(expr, None, mutability)],
3050 stable_ptr,
3051 stable_ptr,
3052 )?;
3053 let ty = ctx.reduce_ty(derefed_expr.ty());
3054 let (_, long_ty) = finalized_snapshot_peeled_ty(ctx, ty, stable_ptr)?;
3055 if let TypeLongId::Var(_) = long_ty {
3057 break;
3058 }
3059 expr = ExprAndId { expr: derefed_expr.clone(), id: ctx.arenas.exprs.alloc(derefed_expr) };
3060 if let TypeLongId::Concrete(ConcreteTypeId::Struct(concrete_struct_id)) = long_ty {
3061 let members = ctx.db.concrete_struct_members(concrete_struct_id)?;
3062 for (member_name, member) in members.iter() {
3063 enriched.entry(member_name.clone()).or_insert_with(|| (member.clone(), n_deref));
3065 }
3066 if members.contains_key(accessed_member_name) {
3068 *exploration_tail = Some(expr.id);
3070 break;
3071 }
3072 }
3073 if !visited_types.insert(long_ty.intern(ctx.db)) {
3074 break;
3077 }
3078 }
3079 Ok(())
3080}
3081
3082fn finalized_snapshot_peeled_ty(
3084 ctx: &mut ComputationContext<'_>,
3085 ty: TypeId,
3086 stable_ptr: impl Into<SyntaxStablePtrId>,
3087) -> Maybe<(usize, TypeLongId)> {
3088 let ty = ctx.reduce_ty(ty);
3089 let (base_snapshots, mut long_ty) = peel_snapshots(ctx.db, ty);
3090 if let TypeLongId::ImplType(impl_type_id) = long_ty {
3091 let inference = &mut ctx.resolver.inference();
3092 let Ok(ty) = inference.reduce_impl_ty(impl_type_id) else {
3093 return Err(ctx
3094 .diagnostics
3095 .report(stable_ptr, InternalInferenceError(InferenceError::TypeNotInferred(ty))));
3096 };
3097 long_ty = ty.lookup_intern(ctx.db);
3098 }
3099 if matches!(long_ty, TypeLongId::Var(_)) {
3100 ctx.resolver.inference().solve().ok();
3102 long_ty = ctx.resolver.inference().rewrite(long_ty).no_err();
3103 }
3104 let (additional_snapshots, long_ty) = peel_snapshots_ex(ctx.db, long_ty);
3105 Ok((base_snapshots + additional_snapshots, long_ty))
3106}
3107
3108fn resolve_expr_path(ctx: &mut ComputationContext<'_>, path: &ast::ExprPath) -> Maybe<Expr> {
3110 let db = ctx.db;
3111 let syntax_db = db.upcast();
3112 let segments = path.elements(syntax_db);
3113 if segments.is_empty() {
3114 return Err(ctx.diagnostics.report(path, Unsupported));
3115 }
3116
3117 if let [PathSegment::Simple(ident_segment)] = &segments[..] {
3119 let identifier = ident_segment.ident(syntax_db);
3120 let variable_name = identifier.text(ctx.db.upcast());
3121 if let Some(res) = get_binded_expr_by_name(ctx, &variable_name, path.stable_ptr().into()) {
3122 match res.clone() {
3123 Expr::Var(expr_var) => {
3124 let item = ResolvedGenericItem::Variable(expr_var.var);
3125 ctx.resolver.data.resolved_items.generic.insert(identifier.stable_ptr(), item);
3126 }
3127 Expr::Constant(expr_const) => {
3128 let item = ResolvedConcreteItem::Constant(expr_const.const_value_id);
3129 ctx.resolver.data.resolved_items.concrete.insert(identifier.stable_ptr(), item);
3130 }
3131 _ => unreachable!(
3132 "get_binded_expr_by_name should only return variables or constants"
3133 ),
3134 };
3135 return Ok(res);
3136 }
3137 }
3138
3139 let resolved_item: ResolvedConcreteItem = ctx.resolver.resolve_concrete_path_ex(
3140 ctx.diagnostics,
3141 path,
3142 NotFoundItemType::Identifier,
3143 Some(&mut ctx.environment),
3144 )?;
3145
3146 match resolved_item {
3147 ResolvedConcreteItem::Constant(const_value_id) => Ok(Expr::Constant(ExprConstant {
3148 const_value_id,
3149 ty: const_value_id.ty(db)?,
3150 stable_ptr: path.stable_ptr().into(),
3151 })),
3152
3153 ResolvedConcreteItem::Variant(variant) if variant.ty == unit_ty(db) => {
3154 let stable_ptr = path.stable_ptr().into();
3155 let concrete_enum_id = variant.concrete_enum_id;
3156 Ok(semantic::Expr::EnumVariantCtor(semantic::ExprEnumVariantCtor {
3157 variant,
3158 value_expr: unit_expr(ctx, stable_ptr),
3159 ty: TypeLongId::Concrete(ConcreteTypeId::Enum(concrete_enum_id)).intern(db),
3160 stable_ptr,
3161 }))
3162 }
3163 resolved_item => Err(ctx.diagnostics.report(path, UnexpectedElement {
3164 expected: vec![ElementKind::Variable, ElementKind::Constant],
3165 actual: (&resolved_item).into(),
3166 })),
3167 }
3168}
3169
3170pub fn resolve_variable_by_name(
3174 ctx: &mut ComputationContext<'_>,
3175 identifier: &ast::TerminalIdentifier,
3176 stable_ptr: ast::ExprPtr,
3177) -> Maybe<Expr> {
3178 let variable_name = identifier.text(ctx.db.upcast());
3179 let res = get_binded_expr_by_name(ctx, &variable_name, stable_ptr)
3180 .ok_or_else(|| ctx.diagnostics.report(identifier, VariableNotFound(variable_name)))?;
3181 let item = ResolvedGenericItem::Variable(extract_matches!(&res, Expr::Var).var);
3182 ctx.resolver.data.resolved_items.generic.insert(identifier.stable_ptr(), item);
3183 Ok(res)
3184}
3185
3186pub fn get_binded_expr_by_name(
3188 ctx: &mut ComputationContext<'_>,
3189 variable_name: &SmolStr,
3190 stable_ptr: ast::ExprPtr,
3191) -> Option<Expr> {
3192 let mut maybe_env = Some(&mut *ctx.environment);
3193 while let Some(env) = maybe_env {
3194 if let Some(var) = env.variables.get(variable_name) {
3195 env.used_variables.insert(var.id());
3196 return match var {
3197 Binding::LocalItem(local_const) => match local_const.kind.clone() {
3198 crate::StatementItemKind::Constant(const_value_id, ty) => {
3199 Some(Expr::Constant(ExprConstant { const_value_id, ty, stable_ptr }))
3200 }
3201 },
3202 Binding::LocalVar(_) | Binding::Param(_) => {
3203 Some(Expr::Var(ExprVar { var: var.id(), ty: var.ty(), stable_ptr }))
3204 }
3205 };
3206 }
3207 maybe_env = env.parent.as_deref_mut();
3208 }
3209 None
3210}
3211
3212fn expr_function_call(
3214 ctx: &mut ComputationContext<'_>,
3215 function_id: FunctionId,
3216 mut named_args: Vec<NamedArg>,
3217 call_ptr: impl Into<SyntaxStablePtrId>,
3218 stable_ptr: ast::ExprPtr,
3219) -> Maybe<Expr> {
3220 let coupon_arg = maybe_pop_coupon_argument(ctx, &mut named_args, function_id);
3221
3222 let signature = ctx.db.concrete_function_signature(function_id)?;
3223 let signature = ctx.resolver.inference().rewrite(signature).unwrap();
3224
3225 if named_args.len() != signature.params.len() {
3227 return Err(ctx.diagnostics.report(call_ptr, WrongNumberOfArguments {
3228 expected: signature.params.len(),
3229 actual: named_args.len(),
3230 }));
3231 }
3232
3233 check_named_arguments(&named_args, &signature, ctx)?;
3235
3236 let mut args = Vec::new();
3237 for (NamedArg(arg, _name, mutability), param) in
3238 named_args.into_iter().zip(signature.params.iter())
3239 {
3240 let arg_typ = arg.ty();
3241 let param_typ = param.ty;
3242 if !arg_typ.is_missing(ctx.db) {
3246 let inference = &mut ctx.resolver.inference();
3247 if let Err((err_set, actual_ty, expected_ty)) =
3248 inference.conform_ty_for_diag(arg_typ, param_typ)
3249 {
3250 let diag_added = ctx
3251 .diagnostics
3252 .report(arg.deref(), WrongArgumentType { expected_ty, actual_ty });
3253 inference.consume_reported_error(err_set, diag_added);
3254 }
3255 }
3256
3257 args.push(if param.mutability == Mutability::Reference {
3258 let Some(ref_arg) = arg.as_member_path() else {
3260 return Err(ctx.diagnostics.report(arg.deref(), RefArgNotAVariable));
3261 };
3262 if !ctx.semantic_defs[&ref_arg.base_var()].is_mut() {
3264 ctx.diagnostics.report(arg.deref(), RefArgNotMutable);
3265 }
3266 if mutability != Mutability::Reference {
3268 ctx.diagnostics.report(arg.deref(), RefArgNotExplicit);
3269 }
3270 ExprFunctionCallArg::Reference(ref_arg)
3271 } else {
3272 if mutability != Mutability::Immutable {
3274 ctx.diagnostics.report(arg.deref(), ImmutableArgWithModifiers);
3275 }
3276 ExprFunctionCallArg::Value(arg.id)
3277 });
3278 }
3279
3280 let expr_function_call = ExprFunctionCall {
3281 function: function_id,
3282 args,
3283 coupon_arg,
3284 ty: signature.return_type,
3285 stable_ptr,
3286 };
3287 if signature.panicable && has_panic_incompatibility(ctx, &expr_function_call) {
3289 return Err(ctx.diagnostics.report(call_ptr, PanicableFromNonPanicable));
3292 }
3293 Ok(Expr::FunctionCall(expr_function_call))
3294}
3295
3296fn maybe_pop_coupon_argument(
3299 ctx: &mut ComputationContext<'_>,
3300 named_args: &mut Vec<NamedArg>,
3301 function_id: FunctionId,
3302) -> Option<id_arena::Id<Expr>> {
3303 let mut coupon_arg: Option<ExprId> = None;
3304 if let Some(NamedArg(arg, Some(name_terminal), mutability)) = named_args.last() {
3305 let coupons_enabled = are_coupons_enabled(ctx.db, ctx.resolver.module_file_id);
3306 if name_terminal.text(ctx.db.upcast()) == "__coupon__" && coupons_enabled {
3307 let expected_ty = TypeLongId::Coupon(function_id).intern(ctx.db);
3309 let arg_typ = arg.ty();
3310 if !arg_typ.is_missing(ctx.db) {
3311 let inference = &mut ctx.resolver.inference();
3312 if let Err((err_set, actual_ty, expected_ty)) =
3313 inference.conform_ty_for_diag(arg_typ, expected_ty)
3314 {
3315 let diag_added = ctx
3316 .diagnostics
3317 .report(arg.deref(), WrongArgumentType { expected_ty, actual_ty });
3318 inference.consume_reported_error(err_set, diag_added);
3319 }
3320 }
3321
3322 if *mutability != Mutability::Immutable {
3324 ctx.diagnostics.report(arg.deref(), CouponArgumentNoModifiers);
3325 }
3326
3327 coupon_arg = Some(arg.id);
3328
3329 named_args.pop();
3331 }
3332 }
3333 coupon_arg
3334}
3335
3336fn has_panic_incompatibility(
3338 ctx: &mut ComputationContext<'_>,
3339 expr_function_call: &ExprFunctionCall,
3340) -> bool {
3341 if try_extract_minus_literal(ctx.db, &ctx.arenas.exprs, expr_function_call).is_some() {
3344 return false;
3345 }
3346 if let Some(signature) = ctx.signature {
3347 !signature.panicable
3349 } else {
3350 false
3351 }
3352}
3353
3354fn check_named_arguments(
3356 named_args: &[NamedArg],
3357 signature: &Signature,
3358 ctx: &mut ComputationContext<'_>,
3359) -> Maybe<()> {
3360 let mut res: Maybe<()> = Ok(());
3361
3362 let mut seen_named_arguments: bool = false;
3365 let mut reported_unnamed_argument_follows_named: bool = false;
3368 for (NamedArg(arg, name_opt, _mutability), param) in
3369 named_args.iter().zip(signature.params.iter())
3370 {
3371 if let Some(name_terminal) = name_opt {
3373 seen_named_arguments = true;
3374 let name = name_terminal.text(ctx.db.upcast());
3375 if param.name != name.clone() {
3376 res = Err(ctx.diagnostics.report(name_terminal, NamedArgumentMismatch {
3377 expected: param.name.clone(),
3378 found: name,
3379 }));
3380 }
3381 } else if seen_named_arguments && !reported_unnamed_argument_follows_named {
3382 reported_unnamed_argument_follows_named = true;
3383 res = Err(ctx.diagnostics.report(arg.deref(), UnnamedArgumentFollowsNamed));
3384 }
3385 }
3386 res
3387}
3388
3389pub fn compute_statement_semantic(
3391 ctx: &mut ComputationContext<'_>,
3392 syntax: ast::Statement,
3393) -> Maybe<StatementId> {
3394 let db = ctx.db;
3395 let syntax_db = db.upcast();
3396 validate_statement_attributes(ctx, &syntax);
3399 let feature_restore = ctx
3400 .resolver
3401 .data
3402 .feature_config
3403 .override_with(extract_item_feature_config(db, &syntax, ctx.diagnostics));
3404 let statement = match &syntax {
3405 ast::Statement::Let(let_syntax) => {
3406 let rhs_syntax = &let_syntax.rhs(syntax_db);
3407 let (rhs_expr, ty) = match let_syntax.type_clause(syntax_db) {
3408 ast::OptionTypeClause::Empty(_) => {
3409 let rhs_expr = compute_expr_semantic(ctx, rhs_syntax);
3410 let inferred_type = rhs_expr.ty();
3411 (rhs_expr, inferred_type)
3412 }
3413 ast::OptionTypeClause::TypeClause(type_clause) => {
3414 let var_type_path = type_clause.ty(syntax_db);
3415 let explicit_type = resolve_type_with_environment(
3416 db,
3417 ctx.diagnostics,
3418 &mut ctx.resolver,
3419 &var_type_path,
3420 Some(&mut ctx.environment),
3421 );
3422
3423 let rhs_expr = compute_expr_semantic(ctx, rhs_syntax);
3424 let inferred_type = ctx.reduce_ty(rhs_expr.ty());
3425 if !inferred_type.is_missing(db) {
3426 let inference = &mut ctx.resolver.inference();
3427 if let Err((err_set, actual_ty, expected_ty)) =
3428 inference.conform_ty_for_diag(inferred_type, explicit_type)
3429 {
3430 let diag_added = ctx
3431 .diagnostics
3432 .report(rhs_syntax, WrongArgumentType { expected_ty, actual_ty });
3433 inference.consume_reported_error(err_set, diag_added);
3434 }
3435 }
3436 (rhs_expr, explicit_type)
3437 }
3438 };
3439 let rhs_expr_id = rhs_expr.id;
3440
3441 let pattern = compute_pattern_semantic(
3442 ctx,
3443 &let_syntax.pattern(syntax_db),
3444 ty,
3445 &mut UnorderedHashMap::default(),
3446 );
3447 let variables = pattern.variables(&ctx.arenas.patterns);
3448 for v in variables {
3449 let var_def = Binding::LocalVar(v.var.clone());
3450 if let Some(old_var) =
3451 ctx.environment.variables.insert(v.name.clone(), var_def.clone())
3452 {
3453 if matches!(old_var, Binding::LocalItem(_)) {
3454 return Err(ctx
3455 .diagnostics
3456 .report(v.stable_ptr, MultipleDefinitionforBinding(v.name.clone())));
3457 }
3458 ctx.add_unused_binding_warning(&v.name, &old_var);
3459 }
3460 ctx.semantic_defs.insert(var_def.id(), var_def);
3461 }
3462 semantic::Statement::Let(semantic::StatementLet {
3463 pattern: pattern.id,
3464 expr: rhs_expr_id,
3465 stable_ptr: syntax.stable_ptr(),
3466 })
3467 }
3468 ast::Statement::Expr(stmt_expr_syntax) => {
3469 let expr_syntax = stmt_expr_syntax.expr(syntax_db);
3470 let expr = compute_expr_semantic(ctx, &expr_syntax);
3471 if matches!(
3472 stmt_expr_syntax.semicolon(syntax_db),
3473 ast::OptionTerminalSemicolon::Empty(_)
3474 ) && !matches!(
3475 expr_syntax,
3476 ast::Expr::Block(_) | ast::Expr::If(_) | ast::Expr::Match(_)
3477 ) {
3478 ctx.diagnostics.report_after(&expr_syntax, MissingSemicolon);
3480 }
3481 let ty: TypeId = expr.ty();
3482 if let TypeLongId::Concrete(concrete) = ty.lookup_intern(db) {
3483 if concrete.is_must_use(db)? {
3484 ctx.diagnostics.report(&expr_syntax, UnhandledMustUseType(ty));
3485 }
3486 }
3487 if let Expr::FunctionCall(expr_function_call) = &expr.expr {
3488 let generic_function_id =
3489 expr_function_call.function.lookup_intern(db).function.generic_function;
3490 if generic_function_id.is_must_use(db)? {
3491 ctx.diagnostics.report(&expr_syntax, UnhandledMustUseFunction);
3492 }
3493 }
3494 semantic::Statement::Expr(semantic::StatementExpr {
3495 expr: expr.id,
3496 stable_ptr: syntax.stable_ptr(),
3497 })
3498 }
3499 ast::Statement::Continue(continue_syntax) => {
3500 if !ctx.is_inside_loop() {
3501 return Err(ctx
3502 .diagnostics
3503 .report(continue_syntax, ContinueOnlyAllowedInsideALoop));
3504 }
3505 semantic::Statement::Continue(semantic::StatementContinue {
3506 stable_ptr: syntax.stable_ptr(),
3507 })
3508 }
3509 ast::Statement::Return(return_syntax) => {
3510 if ctx.is_inside_loop() {
3511 return Err(ctx.diagnostics.report(return_syntax, ReturnNotAllowedInsideALoop));
3512 }
3513
3514 let (expr_option, expr_ty, stable_ptr) = match return_syntax.expr_clause(syntax_db) {
3515 ast::OptionExprClause::Empty(empty_clause) => {
3516 (None, unit_ty(db), empty_clause.stable_ptr().untyped())
3517 }
3518 ast::OptionExprClause::ExprClause(expr_clause) => {
3519 let expr_syntax = expr_clause.expr(syntax_db);
3520 let expr = compute_expr_semantic(ctx, &expr_syntax);
3521 (Some(expr.id), expr.ty(), expr_syntax.stable_ptr().untyped())
3522 }
3523 };
3524 let expected_ty = match ctx.inner_ctx {
3525 None => {
3526 ctx.get_signature(
3527 return_syntax.into(),
3528 UnsupportedOutsideOfFunctionFeatureName::ReturnStatement,
3529 )?
3530 .return_type
3531 }
3532 Some(InnerContext::Closure { return_type }) => return_type,
3533 _ => unreachable!("Return statement inside a loop"),
3534 };
3535
3536 let expected_ty = ctx.reduce_ty(expected_ty);
3537 let expr_ty = ctx.reduce_ty(expr_ty);
3538 if !expected_ty.is_missing(db) && !expr_ty.is_missing(db) {
3539 let inference = &mut ctx.resolver.inference();
3540 if let Err((err_set, actual_ty, expected_ty)) =
3541 inference.conform_ty_for_diag(expr_ty, expected_ty)
3542 {
3543 let diag_added = ctx
3544 .diagnostics
3545 .report(stable_ptr, WrongReturnType { expected_ty, actual_ty });
3546 inference.consume_reported_error(err_set, diag_added);
3547 }
3548 }
3549 semantic::Statement::Return(semantic::StatementReturn {
3550 expr_option,
3551 stable_ptr: syntax.stable_ptr(),
3552 })
3553 }
3554 ast::Statement::Break(break_syntax) => {
3555 let (expr_option, ty, stable_ptr) = match break_syntax.expr_clause(syntax_db) {
3556 ast::OptionExprClause::Empty(expr_empty) => {
3557 (None, unit_ty(db), expr_empty.stable_ptr().untyped())
3558 }
3559 ast::OptionExprClause::ExprClause(expr_clause) => {
3560 let expr_syntax = expr_clause.expr(syntax_db);
3561 let expr = compute_expr_semantic(ctx, &expr_syntax);
3562
3563 (Some(expr.id), expr.ty(), expr.stable_ptr().untyped())
3564 }
3565 };
3566 let ty = ctx.reduce_ty(ty);
3567 match &mut ctx.inner_ctx {
3568 None | Some(InnerContext::Closure { .. }) => {
3569 return Err(ctx.diagnostics.report(break_syntax, BreakOnlyAllowedInsideALoop));
3570 }
3571 Some(InnerContext::Loop { type_merger, .. }) => {
3572 type_merger.try_merge_types(
3573 ctx.db,
3574 ctx.diagnostics,
3575 &mut ctx.resolver.inference(),
3576 ty,
3577 stable_ptr,
3578 );
3579 }
3580 Some(InnerContext::While | InnerContext::For) => {
3581 if expr_option.is_some() {
3582 ctx.diagnostics.report(break_syntax, BreakWithValueOnlyAllowedInsideALoop);
3583 };
3584 }
3585 };
3586 semantic::Statement::Break(semantic::StatementBreak {
3587 expr_option,
3588 stable_ptr: syntax.stable_ptr(),
3589 })
3590 }
3591 ast::Statement::Item(stmt_item_syntax) => {
3592 let item_syntax = &stmt_item_syntax.item(syntax_db);
3593 match item_syntax {
3594 ast::ModuleItem::Constant(const_syntax) => {
3595 let lhs = const_syntax.type_clause(db.upcast()).ty(db.upcast());
3596 let rhs = const_syntax.value(db.upcast());
3597 let rhs_expr = compute_expr_semantic(ctx, &rhs);
3598 let explicit_type = resolve_type_with_environment(
3599 db,
3600 ctx.diagnostics,
3601 &mut ctx.resolver,
3602 &lhs,
3603 Some(&mut ctx.environment),
3604 );
3605 let rhs_resolved_expr = resolve_const_expr_and_evaluate(
3606 db,
3607 ctx,
3608 &rhs_expr,
3609 stmt_item_syntax.stable_ptr().untyped(),
3610 explicit_type,
3611 );
3612 let name_syntax = const_syntax.name(syntax_db);
3613 let name = name_syntax.text(db.upcast());
3614 let rhs_id = StatementConstLongId(
3615 ctx.resolver.module_file_id,
3616 const_syntax.stable_ptr(),
3617 );
3618 let var_def = Binding::LocalItem(LocalItem {
3619 id: StatementItemId::Constant(rhs_id.intern(db)),
3620 kind: StatementItemKind::Constant(
3621 db.intern_const_value(rhs_resolved_expr.clone()),
3622 rhs_resolved_expr.ty(db.upcast())?,
3623 ),
3624 });
3625 add_item_to_statement_environment(ctx, name, var_def, &name_syntax);
3626 }
3627 ast::ModuleItem::Use(use_syntax) => {
3628 for leaf in get_all_path_leaves(syntax_db, use_syntax) {
3629 let stable_ptr = leaf.stable_ptr();
3630 let segments = get_use_path_segments(syntax_db, ast::UsePath::Leaf(leaf))?;
3631 let resolved_item = ctx.resolver.resolve_generic_path(
3632 ctx.diagnostics,
3633 segments,
3634 NotFoundItemType::Identifier,
3635 Some(&mut ctx.environment),
3636 )?;
3637 let var_def_id = StatementItemId::Use(
3638 StatementUseLongId(ctx.resolver.module_file_id, stable_ptr).intern(db),
3639 );
3640 let name = var_def_id.name(db.upcast());
3641 match resolved_item {
3642 ResolvedGenericItem::GenericConstant(const_id) => {
3643 let var_def = Binding::LocalItem(LocalItem {
3644 id: var_def_id,
3645 kind: StatementItemKind::Constant(
3646 db.constant_const_value(const_id)?,
3647 db.constant_const_type(const_id)?,
3648 ),
3649 });
3650 add_item_to_statement_environment(ctx, name, var_def, stable_ptr);
3651 }
3652 ResolvedGenericItem::GenericType(generic_type_id) => {
3653 add_type_to_statement_environment(
3654 ctx,
3655 name,
3656 ResolvedGenericItem::GenericType(generic_type_id),
3657 stable_ptr,
3658 );
3659 }
3660 ResolvedGenericItem::Module(_)
3661 | ResolvedGenericItem::GenericFunction(_)
3662 | ResolvedGenericItem::TraitFunction(_)
3663 | ResolvedGenericItem::GenericTypeAlias(_)
3664 | ResolvedGenericItem::GenericImplAlias(_)
3665 | ResolvedGenericItem::Variant(_)
3666 | ResolvedGenericItem::Trait(_)
3667 | ResolvedGenericItem::Impl(_)
3668 | ResolvedGenericItem::Variable(_) => {
3669 return Err(ctx
3670 .diagnostics
3671 .report(stable_ptr, UnsupportedUseItemInStatement));
3672 }
3673 }
3674 }
3675 }
3676 ast::ModuleItem::Module(_) => {
3677 unreachable!("Modules are not supported inside a function.")
3678 }
3679 ast::ModuleItem::FreeFunction(_) => {
3680 unreachable!("FreeFunction type not supported.")
3681 }
3682 ast::ModuleItem::ExternFunction(_) => {
3683 unreachable!("ExternFunction type not supported.")
3684 }
3685 ast::ModuleItem::ExternType(_) => unreachable!("ExternType type not supported."),
3686 ast::ModuleItem::Trait(_) => unreachable!("Trait type not supported."),
3687 ast::ModuleItem::Impl(_) => unreachable!("Impl type not supported."),
3688 ast::ModuleItem::ImplAlias(_) => unreachable!("ImplAlias type not supported."),
3689 ast::ModuleItem::Struct(_) => unreachable!("Struct type not supported."),
3690 ast::ModuleItem::Enum(_) => unreachable!("Enum type not supported."),
3691 ast::ModuleItem::TypeAlias(_) => unreachable!("TypeAlias type not supported."),
3692 ast::ModuleItem::InlineMacro(_) => unreachable!("InlineMacro type not supported."),
3693 ast::ModuleItem::HeaderDoc(_) => unreachable!("HeaderDoc type not supported."),
3694 ast::ModuleItem::Missing(_) => unreachable!("Missing type not supported."),
3695 }
3696 semantic::Statement::Item(semantic::StatementItem { stable_ptr: syntax.stable_ptr() })
3697 }
3698 ast::Statement::Missing(_) => todo!(),
3699 };
3700 ctx.resolver.data.feature_config.restore(feature_restore);
3701 Ok(ctx.arenas.statements.alloc(statement))
3702}
3703
3704fn add_item_to_statement_environment(
3707 ctx: &mut ComputationContext<'_>,
3708 name: SmolStr,
3709 var_def: Binding,
3710 stable_ptr: impl Into<SyntaxStablePtrId>,
3711) {
3712 if let Some(old_var) = ctx.environment.variables.insert(name.clone(), var_def.clone()) {
3713 ctx.diagnostics.report(stable_ptr, match old_var {
3714 Binding::LocalItem(_) => MultipleConstantDefinition(name),
3715 Binding::LocalVar(_) | Binding::Param(_) => MultipleDefinitionforBinding(name),
3716 });
3717 }
3718 ctx.semantic_defs.insert(var_def.id(), var_def);
3719}
3720
3721fn add_type_to_statement_environment(
3724 ctx: &mut ComputationContext<'_>,
3725 name: SmolStr,
3726 resolved_generic_item: ResolvedGenericItem,
3727 stable_ptr: impl Into<SyntaxStablePtrId> + std::marker::Copy,
3728) {
3729 if ctx
3730 .environment
3731 .use_items
3732 .insert(name.clone(), StatementGenericItemData {
3733 resolved_generic_item,
3734 stable_ptr: stable_ptr.into(),
3735 })
3736 .is_some()
3737 {
3738 ctx.diagnostics.report(stable_ptr, MultipleGenericItemDefinition(name));
3739 }
3740}
3741
3742fn compute_bool_condition_semantic(
3745 ctx: &mut ComputationContext<'_>,
3746 condition_syntax: &ast::Expr,
3747) -> ExprAndId {
3748 let condition = compute_expr_semantic(ctx, condition_syntax);
3749 let inference = &mut ctx.resolver.inference();
3750 if let Err((err_set, condition_ty, _)) =
3751 inference.conform_ty_for_diag(condition.ty(), core_bool_ty(ctx.db))
3752 {
3753 let diag_added = ctx.diagnostics.report(condition.deref(), ConditionNotBool(condition_ty));
3754 inference.consume_reported_error(err_set, diag_added);
3755 }
3756 condition
3757}
3758
3759fn check_struct_member_is_visible(
3761 ctx: &mut ComputationContext<'_>,
3762 member: &Member,
3763 stable_ptr: SyntaxStablePtrId,
3764 member_name: &SmolStr,
3765) {
3766 let db = ctx.db.upcast();
3767 let containing_module_id = member.id.parent_module(db);
3768 if ctx.resolver.ignore_visibility_checks(containing_module_id) {
3769 return;
3770 }
3771 let user_module_id = ctx.resolver.module_file_id.0;
3772 if !visibility::peek_visible_in(db, member.visibility, containing_module_id, user_module_id) {
3773 ctx.diagnostics.report(stable_ptr, MemberNotVisible(member_name.clone()));
3774 }
3775}
3776
3777fn validate_statement_attributes(ctx: &mut ComputationContext<'_>, syntax: &ast::Statement) {
3780 let allowed_attributes = ctx.db.allowed_statement_attributes();
3781 let mut diagnostics = vec![];
3782 validate_attributes_flat(ctx.db.upcast(), &allowed_attributes, syntax, &mut diagnostics);
3783 for diagnostic in diagnostics {
3785 ctx.diagnostics
3786 .report(diagnostic.stable_ptr, SemanticDiagnosticKind::UnknownStatementAttribute);
3787 }
3788}
3789
3790fn function_parameter_types(
3792 ctx: &mut ComputationContext<'_>,
3793 function: FunctionId,
3794) -> Maybe<impl Iterator<Item = TypeId>> {
3795 let signature = ctx.db.concrete_function_signature(function)?;
3796 let param_types = signature.params.into_iter().map(|param| param.ty);
3797 Ok(param_types)
3798}