Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/expr.rs')
| -rw-r--r-- | crates/hir-ty/src/infer/expr.rs | 1106 |
1 files changed, 616 insertions, 490 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index d80ea71674..0675b5e857 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -4,11 +4,11 @@ use std::{iter::repeat_with, mem}; use either::Either; use hir_def::{ - FieldId, GenericDefId, ItemContainerId, Lookup, TupleFieldId, TupleId, + AdtId, FieldId, TupleFieldId, TupleId, VariantId, expr_store::path::{GenericArgs as HirGenericArgs, Path}, hir::{ Array, AsmOperand, AsmOptions, BinaryOp, BindingAnnotation, Expr, ExprId, ExprOrPatId, - InlineAsmKind, LabelId, Literal, Pat, PatId, RecordSpread, Statement, UnaryOp, + InlineAsmKind, LabelId, Pat, PatId, RecordLitField, RecordSpread, Statement, UnaryOp, }, resolver::ValueNs, signatures::VariantFields, @@ -16,35 +16,33 @@ use hir_def::{ use hir_def::{FunctionId, hir::ClosureKind}; use hir_expand::name::Name; use rustc_ast_ir::Mutability; +use rustc_hash::FxHashMap; use rustc_type_ir::{ InferTy, Interner, - inherent::{AdtDef, GenericArgs as _, IntoKind, Ty as _}, + inherent::{GenericArgs as _, IntoKind, Ty as _}, }; +use stdx::never; use syntax::ast::RangeOp; use tracing::debug; use crate::{ - Adjust, Adjustment, CallableDefId, DeclContext, DeclOrigin, Rawness, consteval, - generics::generics, - infer::{ - AllowTwoPhase, BreakableKind, coerce::CoerceMany, find_continuable, - pat::contains_explicit_ref_binding, - }, - lower::{GenericPredicates, lower_mutability}, + Adjust, Adjustment, CallableDefId, Rawness, Span, + consteval::literal_ty, + infer::{AllowTwoPhase, BreakableKind, coerce::CoerceMany, find_continuable, pat::PatOrigin}, + lower::lower_mutability, method_resolution::{self, CandidateId, MethodCallee, MethodError}, next_solver::{ - ClauseKind, FnSig, GenericArg, GenericArgs, TraitRef, Ty, TyKind, TypeError, + ClauseKind, FnSig, GenericArg, GenericArgs, Ty, TyKind, TypeError, infer::{ BoundRegionConversionTime, InferOk, traits::{Obligation, ObligationCause}, }, obligation_ctxt::ObligationCtxt, - util::clauses_as_obligations, }, }; use super::{ - BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch, + BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic, cast::CastCheck, find_breakable, }; @@ -63,17 +61,41 @@ impl<'db> InferenceContext<'_, 'db> { ) -> Ty<'db> { let ty = self.infer_expr_inner(tgt_expr, expected, is_read); if let Some(expected_ty) = expected.only_has_type(&mut self.table) { - let could_unify = self.unify(ty, expected_ty); - if !could_unify { - self.result.type_mismatches.get_or_insert_default().insert( - tgt_expr.into(), - TypeMismatch { expected: expected_ty.store(), actual: ty.store() }, - ); - } + _ = self.demand_eqtype(tgt_expr.into(), expected_ty, ty); } ty } + pub(crate) fn infer_expr_suptype_coerce_never( + &mut self, + expr: ExprId, + expected: &Expectation<'db>, + is_read: ExprIsRead, + ) -> Ty<'db> { + let ty = self.infer_expr_inner(expr, expected, is_read); + if ty.is_never() { + if let Some(adjustments) = self.result.expr_adjustments.get(&expr) { + return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &**adjustments { + target.as_ref() + } else { + self.err_ty() + }; + } + + if let Some(target) = expected.only_has_type(&mut self.table) { + self.coerce(expr, ty, target, AllowTwoPhase::No, ExprIsRead::Yes) + .expect("never-to-any coercion should always succeed") + } else { + ty + } + } else { + if let Some(expected_ty) = expected.only_has_type(&mut self.table) { + _ = self.demand_suptype(expr.into(), expected_ty, ty); + } + ty + } + } + pub(crate) fn infer_expr_no_expect( &mut self, tgt_expr: ExprId, @@ -92,13 +114,10 @@ impl<'db> InferenceContext<'_, 'db> { ) -> Ty<'db> { let ty = self.infer_expr_inner(expr, expected, is_read); if let Some(target) = expected.only_has_type(&mut self.table) { - match self.coerce(expr.into(), ty, target, AllowTwoPhase::No, is_read) { + match self.coerce(expr, ty, target, AllowTwoPhase::No, is_read) { Ok(res) => res, Err(_) => { - self.result.type_mismatches.get_or_insert_default().insert( - expr.into(), - TypeMismatch { expected: target.store(), actual: ty.store() }, - ); + self.emit_type_mismatch(expr.into(), target, ty); target } } @@ -154,7 +173,7 @@ impl<'db> InferenceContext<'_, 'db> { fn pat_guaranteed_to_constitute_read_for_never(&self, pat: PatId) -> bool { match &self.store[pat] { // Does not constitute a read. - Pat::Wild => false, + Pat::Wild | Pat::Rest => false, // This is unnecessarily restrictive when the pattern that doesn't // constitute a read is unreachable. @@ -175,6 +194,7 @@ impl<'db> InferenceContext<'_, 'db> { | Pat::Path(_) | Pat::Tuple { .. } | Pat::Box { .. } + | Pat::Deref { .. } | Pat::Ref { .. } | Pat::Lit(_) | Pat::Range { .. } @@ -251,13 +271,12 @@ impl<'db> InferenceContext<'_, 'db> { } } - #[expect(clippy::needless_return)] pub(crate) fn check_lhs_assignable(&self, lhs: ExprId) { if self.is_syntactic_place_expr(lhs) { return; } - // FIXME: Emit diagnostic. + self.push_diagnostic(InferenceDiagnostic::InvalidLhsOfAssignment { lhs }); } fn infer_expr_coerce_never( @@ -279,27 +298,21 @@ impl<'db> InferenceContext<'_, 'db> { } if let Some(target) = expected.only_has_type(&mut self.table) { - self.coerce(expr.into(), ty, target, AllowTwoPhase::No, ExprIsRead::Yes) + self.coerce(expr, ty, target, AllowTwoPhase::No, ExprIsRead::Yes) .expect("never-to-any coercion should always succeed") } else { ty } } else { if let Some(expected_ty) = expected.only_has_type(&mut self.table) { - let could_unify = self.unify(ty, expected_ty); - if !could_unify { - self.result.type_mismatches.get_or_insert_default().insert( - expr.into(), - TypeMismatch { expected: expected_ty.store(), actual: ty.store() }, - ); - } + _ = self.demand_eqtype(expr.into(), ty, expected_ty); } ty } } #[tracing::instrument(level = "debug", skip(self, is_read), ret)] - fn infer_expr_inner( + pub(super) fn infer_expr_inner( &mut self, tgt_expr: ExprId, expected: &Expectation<'db>, @@ -312,7 +325,7 @@ impl<'db> InferenceContext<'_, 'db> { let ty = match expr { Expr::Missing => self.err_ty(), &Expr::If { condition, then_branch, else_branch } => { - let expected = &expected.adjust_for_branches(&mut self.table); + let expected = &expected.adjust_for_branches(&mut self.table, tgt_expr.into()); self.infer_expr_coerce_never( condition, &Expectation::HasType(self.types.types.bool), @@ -328,17 +341,23 @@ impl<'db> InferenceContext<'_, 'db> { coercion_sites[1] = else_branch; } let mut coerce = CoerceMany::with_coercion_sites( - expected.coercion_target_type(&mut self.table), + expected.coercion_target_type(&mut self.table, then_branch.into()), &coercion_sites, ); - coerce.coerce(self, &ObligationCause::new(), then_branch, then_ty, ExprIsRead::Yes); + coerce.coerce( + self, + &ObligationCause::new(then_branch), + then_branch, + then_ty, + ExprIsRead::Yes, + ); match else_branch { Some(else_branch) => { let else_ty = self.infer_expr_inner(else_branch, expected, ExprIsRead::Yes); let else_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); coerce.coerce( self, - &ObligationCause::new(), + &ObligationCause::new(else_branch), else_branch, else_ty, ExprIsRead::Yes, @@ -349,7 +368,7 @@ impl<'db> InferenceContext<'_, 'db> { coerce.coerce_forced_unit( self, tgt_expr, - &ObligationCause::new(), + &ObligationCause::new(tgt_expr), true, ExprIsRead::Yes, ); @@ -366,11 +385,7 @@ impl<'db> InferenceContext<'_, 'db> { ExprIsRead::No }; let input_ty = self.infer_expr(expr, &Expectation::none(), child_is_read); - self.infer_top_pat( - pat, - input_ty, - Some(DeclContext { origin: DeclOrigin::LetExpr }), - ); + self.infer_top_pat(pat, input_ty, PatOrigin::LetExpr); self.types.types.bool } Expr::Block { statements, tail, label, id: _ } => { @@ -386,9 +401,7 @@ impl<'db> InferenceContext<'_, 'db> { .1 } &Expr::Loop { body, label } => { - // FIXME: should be: - // let ty = expected.coercion_target_type(&mut self.table); - let ty = self.table.next_ty_var(); + let ty = expected.coercion_target_type(&mut self.table, tgt_expr.into()); let (breaks, ()) = self.with_breakable_ctx(BreakableKind::Loop, Some(ty), label, |this| { this.infer_expr( @@ -449,15 +462,15 @@ impl<'db> InferenceContext<'_, 'db> { let matchee_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let mut all_arms_diverge = Diverges::Always; for arm in arms.iter() { - self.infer_top_pat(arm.pat, input_ty, None); + self.infer_top_pat(arm.pat, input_ty, PatOrigin::MatchArm); } - let expected = expected.adjust_for_branches(&mut self.table); + let expected = expected.adjust_for_branches(&mut self.table, tgt_expr.into()); let result_ty = match &expected { // We don't coerce to `()` so that if the match expression is a // statement it's branches can have any consistent type. Expectation::HasType(ty) if *ty != self.types.types.unit => *ty, - _ => self.table.next_ty_var(), + _ => self.table.next_ty_var((*expr).into()), }; let mut coerce = CoerceMany::new(result_ty); @@ -476,7 +489,7 @@ impl<'db> InferenceContext<'_, 'db> { all_arms_diverge &= self.diverges; coerce.coerce( self, - &ObligationCause::new(), + &ObligationCause::new(arm.expr), arm.expr, arm_ty, ExprIsRead::Yes, @@ -527,10 +540,11 @@ impl<'db> InferenceContext<'_, 'db> { match find_breakable(&mut self.breakables, label) { Some(ctxt) => match ctxt.coerce.take() { Some(mut coerce) => { + let expr = expr.unwrap_or(tgt_expr); coerce.coerce( self, - &ObligationCause::new(), - expr.unwrap_or(tgt_expr), + &ObligationCause::new(expr), + expr, val_ty, ExprIsRead::Yes, ); @@ -566,7 +580,7 @@ impl<'db> InferenceContext<'_, 'db> { } else { let unit = self.types.types.unit; let _ = self.coerce( - tgt_expr.into(), + tgt_expr, unit, yield_ty, AllowTwoPhase::No, @@ -586,80 +600,10 @@ impl<'db> InferenceContext<'_, 'db> { self.types.types.never } Expr::RecordLit { path, fields, spread, .. } => { - let (ty, def_id) = self.resolve_variant(tgt_expr.into(), path.as_deref(), false); - - if let Some(t) = expected.only_has_type(&mut self.table) { - self.unify(ty, t); - } - - let substs = ty.as_adt().map(|(_, s)| s).unwrap_or(self.types.empty.generic_args); - if let Some(variant) = def_id { - self.write_variant_resolution(tgt_expr.into(), variant); - } - match def_id { - _ if fields.is_empty() => {} - Some(def) => { - let field_types = self.db.field_types(def); - let variant_data = def.fields(self.db); - let visibilities = VariantFields::field_visibilities(self.db, def); - for field in fields.iter() { - let field_def = { - match variant_data.field(&field.name) { - Some(local_id) => { - if !visibilities[local_id] - .is_visible_from(self.db, self.resolver.module()) - { - self.push_diagnostic( - InferenceDiagnostic::NoSuchField { - field: field.expr.into(), - private: Some(local_id), - variant: def, - }, - ); - } - Some(local_id) - } - None => { - self.push_diagnostic(InferenceDiagnostic::NoSuchField { - field: field.expr.into(), - private: None, - variant: def, - }); - None - } - } - }; - let field_ty = field_def.map_or(self.err_ty(), |it| { - field_types[it].get().instantiate(self.interner(), &substs) - }); - - // Field type might have some unknown types - // FIXME: we may want to emit a single type variable for all instance of type fields? - let field_ty = self.insert_type_vars(field_ty); - self.infer_expr_coerce( - field.expr, - &Expectation::has_type(field_ty), - ExprIsRead::Yes, - ); - } - } - None => { - for field in fields.iter() { - // Field projections don't constitute reads. - self.infer_expr_coerce(field.expr, &Expectation::None, ExprIsRead::No); - } - } - } - if let RecordSpread::Expr(expr) = *spread { - self.infer_expr_coerce_never(expr, &Expectation::has_type(ty), ExprIsRead::Yes); - } - ty + self.infer_record_expr(tgt_expr, expected, path, fields, *spread) } Expr::Field { expr, name } => self.infer_field_access(tgt_expr, *expr, name, expected), - Expr::Await { expr } => { - let inner_ty = self.infer_expr_inner(*expr, &Expectation::none(), ExprIsRead::Yes); - self.resolve_associated_type(inner_ty, self.resolve_future_future_output()) - } + Expr::Await { expr } => self.infer_await_expr(tgt_expr, *expr), Expr::Cast { expr, type_ref } => { let cast_ty = self.make_body_ty(*type_ref); let expr_ty = @@ -667,34 +611,13 @@ impl<'db> InferenceContext<'_, 'db> { self.deferred_cast_checks.push(CastCheck::new(tgt_expr, *expr, expr_ty, cast_ty)); cast_ty } - Expr::Ref { expr, rawness, mutability } => { - let mutability = lower_mutability(*mutability); - let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = expected - .only_has_type(&mut self.table) - .as_ref() - .and_then(|t| t.as_reference_or_ptr()) - { - if exp_mutability == Mutability::Mut && mutability == Mutability::Not { - // FIXME: record type error - expected mut reference but found shared ref, - // which cannot be coerced - } - if exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr { - // FIXME: record type error - expected reference but found ptr, - // which cannot be coerced - } - Expectation::rvalue_hint(self, exp_inner) - } else { - Expectation::none() - }; - let inner_ty = self.infer_expr_inner(*expr, &expectation, ExprIsRead::Yes); - match rawness { - Rawness::RawPtr => Ty::new_ptr(self.interner(), inner_ty, mutability), - Rawness::Ref => { - let lt = self.table.next_region_var(); - Ty::new_ref(self.interner(), lt, inner_ty, mutability) - } - } - } + Expr::Ref { expr, rawness, mutability } => self.infer_ref_expr( + *rawness, + lower_mutability(*mutability), + *expr, + expected, + tgt_expr, + ), &Expr::Box { expr } => self.infer_expr_box(expr, expected), Expr::UnaryOp { expr, op } => self.infer_unop_expr(*op, *expr, expected, tgt_expr), Expr::BinaryOp { lhs, rhs, op } => match op { @@ -715,29 +638,6 @@ impl<'db> InferenceContext<'_, 'db> { &Pat::Expr(expr) => { Some(self.infer_expr(expr, &Expectation::none(), ExprIsRead::No)) } - Pat::Path(path) => { - let resolver_guard = - self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr); - let resolution = self.resolver.resolve_path_in_value_ns_fully( - self.db, - path, - self.store.pat_path_hygiene(target), - ); - self.resolver.reset_to_guard(resolver_guard); - - if matches!( - resolution, - Some( - ValueNs::ConstId(_) - | ValueNs::StructId(_) - | ValueNs::EnumVariantId(_) - ) - ) { - None - } else { - Some(self.infer_expr_path(path, target.into(), tgt_expr)) - } - } _ => None, }; let is_destructuring_assignment = lhs_ty.is_none(); @@ -748,9 +648,9 @@ impl<'db> InferenceContext<'_, 'db> { } else { let rhs_ty = self.infer_expr(value, &Expectation::none(), ExprIsRead::Yes); let resolver_guard = - self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr); + self.resolver.update_to_inner_scope(self.db, self.store_owner, tgt_expr); self.inside_assignment = true; - self.infer_top_pat(target, rhs_ty, None); + self.infer_top_pat(target, rhs_ty, PatOrigin::DestructuringAssignment); self.inside_assignment = false; self.resolver.reset_to_guard(resolver_guard); } @@ -759,7 +659,7 @@ impl<'db> InferenceContext<'_, 'db> { // However, rustc lowers destructuring assignments into blocks, and blocks return `!` if they have no tail // expression and they diverge. Therefore, we have to do the same here, even though we don't lower destructuring // assignments into blocks. - self.table.new_maybe_never_var() + self.table.new_maybe_never_var(value.into()) } else { self.types.types.unit } @@ -814,8 +714,8 @@ impl<'db> InferenceContext<'_, 'db> { let base_t = self.infer_expr_no_expect(*base, ExprIsRead::Yes); let idx_t = self.infer_expr_no_expect(*index, ExprIsRead::Yes); - let base_t = self.table.structurally_resolve_type(base_t); - match self.lookup_indexing(tgt_expr, *base, base_t, idx_t) { + let base_t = self.structurally_resolve_type((*base).into(), base_t); + match self.lookup_indexing(tgt_expr, *base, *index, base_t, idx_t) { Some((trait_index_ty, trait_element_ty)) => { // two-phase not needed because index_ty is never mutable self.demand_coerce( @@ -835,14 +735,14 @@ impl<'db> InferenceContext<'_, 'db> { Expr::Tuple { exprs, .. } => { let mut tys = match expected .only_has_type(&mut self.table) - .map(|t| self.table.try_structurally_resolve_type(t).kind()) + .map(|t| self.table.try_structurally_resolve_type(tgt_expr.into(), t).kind()) { Some(TyKind::Tuple(substs)) => substs .iter() - .chain(repeat_with(|| self.table.next_ty_var())) + .chain(repeat_with(|| self.table.next_ty_var(Span::Dummy))) .take(exprs.len()) .collect::<Vec<_>>(), - _ => (0..exprs.len()).map(|_| self.table.next_ty_var()).collect(), + _ => exprs.iter().map(|&expr| self.table.next_ty_var(expr.into())).collect(), }; for (expr, ty) in exprs.iter().zip(tys.iter_mut()) { @@ -852,107 +752,51 @@ impl<'db> InferenceContext<'_, 'db> { Ty::new_tup(self.interner(), &tys) } - Expr::Array(array) => self.infer_expr_array(array, expected), - Expr::Literal(lit) => match lit { - Literal::Bool(..) => self.types.types.bool, - Literal::String(..) => self.types.types.static_str_ref, - Literal::ByteString(bs) => { - let byte_type = self.types.types.u8; - - let len = consteval::usize_const( - self.db, - Some(bs.len() as u128), - self.resolver.krate(), - ); - - let array_type = Ty::new_array_with_const_len(self.interner(), byte_type, len); - Ty::new_ref( - self.interner(), - self.types.regions.statik, - array_type, - Mutability::Not, - ) - } - Literal::CString(..) => Ty::new_ref( - self.interner(), - self.types.regions.statik, - self.lang_items.CStr.map_or_else( - || self.err_ty(), - |strukt| { - Ty::new_adt( - self.interner(), - strukt.into(), - self.types.empty.generic_args, - ) - }, - ), - Mutability::Not, - ), - Literal::Char(..) => self.types.types.char, - Literal::Int(_v, ty) => match ty { - Some(int_ty) => match int_ty { - hir_def::builtin_type::BuiltinInt::Isize => self.types.types.isize, - hir_def::builtin_type::BuiltinInt::I8 => self.types.types.i8, - hir_def::builtin_type::BuiltinInt::I16 => self.types.types.i16, - hir_def::builtin_type::BuiltinInt::I32 => self.types.types.i32, - hir_def::builtin_type::BuiltinInt::I64 => self.types.types.i64, - hir_def::builtin_type::BuiltinInt::I128 => self.types.types.i128, - }, - None => { - let expected_ty = expected.to_option(&mut self.table); - tracing::debug!(?expected_ty); - let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) { - Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty, - Some(TyKind::Char) => Some(self.types.types.u8), - Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => { - Some(self.types.types.usize) - } - _ => None, - }; - opt_ty.unwrap_or_else(|| self.table.next_int_var()) - } + Expr::Array(Array::ElementList { elements }) => { + self.infer_array_elements_expr(elements, expected, tgt_expr) + } + Expr::Array(Array::Repeat { initializer, repeat }) => { + self.infer_array_repeat_expr(*initializer, *repeat, expected, tgt_expr) + } + Expr::Literal(lit) => literal_ty( + self.interner(), + lit, + |_| { + let expected_ty = expected.to_option(&self.table); + tracing::debug!(?expected_ty); + let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) { + Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty, + Some(TyKind::Char) => Some(self.types.types.u8), + Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => { + Some(self.types.types.usize) + } + _ => None, + }; + opt_ty.unwrap_or_else(|| self.table.next_int_var()) }, - Literal::Uint(_v, ty) => match ty { - Some(int_ty) => match int_ty { - hir_def::builtin_type::BuiltinUint::Usize => self.types.types.usize, - hir_def::builtin_type::BuiltinUint::U8 => self.types.types.u8, - hir_def::builtin_type::BuiltinUint::U16 => self.types.types.u16, - hir_def::builtin_type::BuiltinUint::U32 => self.types.types.u32, - hir_def::builtin_type::BuiltinUint::U64 => self.types.types.u64, - hir_def::builtin_type::BuiltinUint::U128 => self.types.types.u128, - }, - None => { - let expected_ty = expected.to_option(&mut self.table); - let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) { - Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty, - Some(TyKind::Char) => Some(self.types.types.u8), - Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => { - Some(self.types.types.usize) - } - _ => None, - }; - opt_ty.unwrap_or_else(|| self.table.next_int_var()) - } + |_| { + let expected_ty = expected.to_option(&self.table); + let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) { + Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty, + Some(TyKind::Char) => Some(self.types.types.u8), + Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => { + Some(self.types.types.usize) + } + _ => None, + }; + opt_ty.unwrap_or_else(|| self.table.next_int_var()) }, - Literal::Float(_v, ty) => match ty { - Some(float_ty) => match float_ty { - hir_def::builtin_type::BuiltinFloat::F16 => self.types.types.f16, - hir_def::builtin_type::BuiltinFloat::F32 => self.types.types.f32, - hir_def::builtin_type::BuiltinFloat::F64 => self.types.types.f64, - hir_def::builtin_type::BuiltinFloat::F128 => self.types.types.f128, - }, - None => { - let opt_ty = expected - .to_option(&mut self.table) - .filter(|ty| matches!(ty.kind(), TyKind::Float(_))); - opt_ty.unwrap_or_else(|| self.table.next_float_var()) - } + |_| { + let opt_ty = expected + .to_option(&self.table) + .filter(|ty| matches!(ty.kind(), TyKind::Float(_))); + opt_ty.unwrap_or_else(|| self.table.next_float_var()) }, - }, + ), Expr::Underscore => { // Underscore expression is an error, we render a specialized diagnostic // to let the user know what type is expected though. - let expected = expected.to_option(&mut self.table).unwrap_or_else(|| self.err_ty()); + let expected = expected.to_option(&self.table).unwrap_or_else(|| self.err_ty()); self.push_diagnostic(InferenceDiagnostic::TypedHole { expr: tgt_expr, expected: expected.store(), @@ -972,17 +816,18 @@ impl<'db> InferenceContext<'_, 'db> { // allows them to be inferred based on how they are used later in the // function. if is_input { - let ty = this.table.structurally_resolve_type(ty); + let ty = this.structurally_resolve_type(expr.into(), ty); match ty.kind() { TyKind::FnDef(def, parameters) => { let fnptr_ty = Ty::new_fn_ptr( this.interner(), this.interner() .fn_sig(def) - .instantiate(this.interner(), parameters), + .instantiate(this.interner(), parameters) + .skip_norm_wip(), ); _ = this.coerce( - expr.into(), + expr, ty, fnptr_ty, AllowTwoPhase::No, @@ -992,7 +837,7 @@ impl<'db> InferenceContext<'_, 'db> { TyKind::Ref(_, base_ty, mutbl) => { let ptr_ty = Ty::new_ptr(this.interner(), base_ty, mutbl); _ = this.coerce( - expr.into(), + expr, ty, ptr_ty, AllowTwoPhase::No, @@ -1037,7 +882,6 @@ impl<'db> InferenceContext<'_, 'db> { } } }; - // use a new type variable if we got unknown here let ty = self.insert_type_vars_shallow(ty); self.write_expr_ty(tgt_expr, ty); if self.shallow_resolve(ty).is_never() @@ -1049,6 +893,301 @@ impl<'db> InferenceContext<'_, 'db> { ty } + fn infer_ref_expr( + &mut self, + rawness: Rawness, + mutbl: Mutability, + oprnd: ExprId, + expected: &Expectation<'db>, + expr: ExprId, + ) -> Ty<'db> { + let hint = expected.only_has_type(&mut self.table).map_or(Expectation::None, |ty| { + match self.table.resolve_vars_with_obligations(ty).kind() { + TyKind::Ref(_, ty, _) | TyKind::RawPtr(ty, _) => { + if self.is_syntactic_place_expr(oprnd) { + // Places may legitimately have unsized types. + // For example, dereferences of a wide pointer and + // the last field of a struct can be unsized. + Expectation::has_type(ty) + } else { + Expectation::rvalue_hint(self, ty) + } + } + _ => Expectation::None, + } + }); + let ty = self.infer_expr_inner(oprnd, &hint, ExprIsRead::No); + + match rawness { + Rawness::RawPtr => Ty::new_ptr(self.interner(), ty, mutbl), + Rawness::Ref => { + // Note: at this point, we cannot say what the best lifetime + // is to use for resulting pointer. We want to use the + // shortest lifetime possible so as to avoid spurious borrowck + // errors. Moreover, the longest lifetime will depend on the + // precise details of the value whose address is being taken + // (and how long it is valid), which we don't know yet until + // type inference is complete. + // + // Therefore, here we simply generate a region variable. The + // region inferencer will then select a suitable value. + // Finally, borrowck will infer the value of the region again, + // this time with enough precision to check that the value + // whose address was taken can actually be made to live as long + // as it needs to live. + let region = self.table.next_region_var(expr.into()); + Ty::new_ref(self.interner(), region, ty, mutbl) + } + } + } + + fn infer_await_expr(&mut self, expr: ExprId, awaitee: ExprId) -> Ty<'db> { + let awaitee_ty = self.infer_expr_no_expect(awaitee, ExprIsRead::Yes); + let (Some(into_future), Some(into_future_output)) = + (self.lang_items.IntoFuture, self.lang_items.IntoFutureOutput) + else { + return self.types.types.error; + }; + self.table.register_bound(awaitee_ty, into_future, ObligationCause::new(expr)); + // Do not eagerly normalize. + Ty::new_projection(self.interner(), into_future_output.into(), [awaitee_ty]) + } + + fn infer_record_expr( + &mut self, + expr: ExprId, + expected: &Expectation<'db>, + path: &Path, + fields: &[RecordLitField], + base_expr: RecordSpread, + ) -> Ty<'db> { + // Find the relevant variant + let (adt_ty, Some(variant)) = self.resolve_variant(expr.into(), path, false) else { + // FIXME: Emit an error. + for field in fields { + self.infer_expr_no_expect(field.expr, ExprIsRead::Yes); + } + + return self.types.types.error; + }; + self.write_variant_resolution(expr.into(), variant); + + // Prohibit struct expressions when non-exhaustive flag is set. + if self.has_applicable_non_exhaustive(variant.into()) { + self.push_diagnostic(InferenceDiagnostic::NonExhaustiveRecordExpr { expr }); + } + + self.check_record_expr_fields(adt_ty, expected, expr, variant, fields, base_expr); + + self.require_type_is_sized(adt_ty, expr.into()); + adt_ty + } + + fn check_record_expr_fields( + &mut self, + adt_ty: Ty<'db>, + expected: &Expectation<'db>, + expr: ExprId, + variant: VariantId, + hir_fields: &[RecordLitField], + base_expr: RecordSpread, + ) { + let interner = self.interner(); + + let adt_ty = self.table.try_structurally_resolve_type(expr.into(), adt_ty); + let adt_ty_hint = expected.only_has_type(&mut self.table).and_then(|expected| { + self.infcx() + .fudge_inference_if_ok(|| { + let mut ocx = ObligationCtxt::new(self.infcx()); + ocx.sup(&ObligationCause::new(expr), self.table.param_env, expected, adt_ty)?; + if !ocx.try_evaluate_obligations().is_empty() { + return Err(TypeError::Mismatch); + } + Ok(self.resolve_vars_if_possible(adt_ty)) + }) + .ok() + }); + if let Some(adt_ty_hint) = adt_ty_hint { + // re-link the variables that the fudging above can create. + _ = self.demand_eqtype(expr.into(), adt_ty_hint, adt_ty); + } + + let TyKind::Adt(adt, args) = adt_ty.kind() else { + never!("non-ADT passed to check_struct_expr_fields"); + return; + }; + let adt_id = adt.def_id(); + + let variant_fields = variant.fields(self.db); + let variant_field_tys = self.db.field_types(variant); + let variant_field_vis = VariantFields::field_visibilities(self.db, variant); + let mut remaining_fields = variant_fields + .fields() + .iter() + .map(|(i, field)| (field.name.clone(), i)) + .collect::<FxHashMap<_, _>>(); + + let mut seen_fields = FxHashMap::default(); + + // Type-check each field. + for field in hir_fields { + let name = &field.name; + let field_type = if let Some(i) = remaining_fields.remove(name) { + seen_fields.insert(name, i); + + if !self.resolver.is_visible(self.db, variant_field_vis[i]) { + self.push_diagnostic(InferenceDiagnostic::NoSuchField { + field: field.expr.into(), + private: Some(i), + variant, + }); + } + + variant_field_tys[i].get().instantiate(interner, args).skip_norm_wip() + } else { + if let Some(field_idx) = seen_fields.get(&name) { + self.push_diagnostic(InferenceDiagnostic::DuplicateField { + field: field.expr.into(), + variant, + }); + variant_field_tys[*field_idx].get().instantiate(interner, args).skip_norm_wip() + } else { + self.push_diagnostic(InferenceDiagnostic::NoSuchField { + field: field.expr.into(), + private: None, + variant, + }); + self.types.types.error + } + }; + + // Check that the expected field type is WF. Otherwise, we emit no use-site error + // in the case of coercions for non-WF fields, which leads to incorrect error + // tainting. See issue #126272. + self.table.register_wf_obligation(field_type.into(), ObligationCause::new(field.expr)); + + // Make sure to give a type to the field even if there's + // an error, so we can continue type-checking. + self.infer_expr_coerce(field.expr, &Expectation::has_type(field_type), ExprIsRead::Yes); + } + + // Make sure the programmer specified correct number of fields. + if matches!(adt_id, AdtId::UnionId(_)) && hir_fields.len() != 1 { + self.push_diagnostic(InferenceDiagnostic::UnionExprMustHaveExactlyOneField { expr }); + } + + match base_expr { + RecordSpread::FieldDefaults => { + let mut missing_mandatory_fields = Vec::new(); + let mut missing_optional_fields = Vec::new(); + for (field_idx, field) in variant_fields.fields().iter() { + if remaining_fields.remove(&field.name).is_some() { + if field.default_value.is_none() { + missing_mandatory_fields.push(field_idx); + } else { + missing_optional_fields.push(field_idx); + } + } + } + if !missing_mandatory_fields.is_empty() { + // FIXME: Emit an error: missing fields. + } + } + RecordSpread::Expr(base_expr) => { + // FIXME: We are currently creating two branches here in order to maintain + // consistency. But they should be merged as much as possible. + if self.features.type_changing_struct_update { + if matches!(adt_id, AdtId::StructId(_)) { + // Make some fresh generic parameters for our ADT type. + let fresh_args = self.table.fresh_args_for_item(expr.into(), adt_id.into()); + // We do subtyping on the FRU fields first, so we can + // learn exactly what types we expect the base expr + // needs constrained to be compatible with the struct + // type we expect from the expectation value. + for (field_idx, field) in variant_fields.fields().iter() { + let fru_ty = variant_field_tys[field_idx] + .get() + .instantiate(interner, fresh_args) + .skip_norm_wip(); + if remaining_fields.remove(&field.name).is_some() { + let target_ty = variant_field_tys[field_idx] + .get() + .instantiate(interner, args) + .skip_norm_wip(); + let cause = ObligationCause::new(expr); + match self.table.at(&cause).sup(target_ty, fru_ty) { + Ok(InferOk { obligations, value: () }) => { + self.table.register_predicates(obligations) + } + Err(_) => { + never!( + "subtyping remaining fields of type changing FRU \ + failed: {target_ty:?} != {fru_ty:?}: {:?}", + field.name, + ); + } + } + } + } + // The use of fresh args that we have subtyped against + // our base ADT type's fields allows us to guide inference + // along so that, e.g. + // ``` + // MyStruct<'a, F1, F2, const C: usize> { + // f: F1, + // // Other fields that reference `'a`, `F2`, and `C` + // } + // + // let x = MyStruct { + // f: 1usize, + // ..other_struct + // }; + // ``` + // will have the `other_struct` expression constrained to + // `MyStruct<'a, _, F2, C>`, as opposed to just `_`... + // This is important to allow coercions to happen in + // `other_struct` itself. See `coerce-in-base-expr.rs`. + let fresh_base_ty = Ty::new_adt(self.interner(), adt_id, fresh_args); + self.infer_expr_suptype_coerce_never( + base_expr, + &Expectation::has_type(self.resolve_vars_if_possible(fresh_base_ty)), + ExprIsRead::Yes, + ); + } else { + // Check the base_expr, regardless of a bad expected adt_ty, so we can get + // type errors on that expression, too. + self.infer_expr_no_expect(base_expr, ExprIsRead::Yes); + self.push_diagnostic( + InferenceDiagnostic::FunctionalRecordUpdateOnNonStruct { base_expr }, + ); + } + } else { + self.infer_expr_suptype_coerce_never( + base_expr, + &Expectation::has_type(adt_ty), + ExprIsRead::Yes, + ); + if !matches!(adt_id, AdtId::StructId(_)) { + self.push_diagnostic( + InferenceDiagnostic::FunctionalRecordUpdateOnNonStruct { base_expr }, + ); + } + } + } + RecordSpread::None => { + if !matches!(adt_id, AdtId::UnionId(_)) + && !remaining_fields.is_empty() + //~ non_exhaustive already reported, which will only happen for extern modules + && !self.has_applicable_non_exhaustive(adt_id.into()) + { + debug!(?remaining_fields); + + // FIXME: Emit an error: missing fields. + } + } + } + } + fn demand_scrutinee_type( &mut self, scrut: ExprId, @@ -1114,16 +1253,16 @@ impl<'db> InferenceContext<'_, 'db> { // ...but otherwise we want to use any supertype of the // scrutinee. This is sort of a workaround, see note (*) in // `check_pat` for some details. - let scrut_ty = self.table.next_ty_var(); + let scrut_ty = self.table.next_ty_var(scrut.into()); self.infer_expr_coerce_never(scrut, &Expectation::HasType(scrut_ty), scrutinee_is_read); scrut_ty } } fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty<'db> { - let g = self.resolver.update_to_inner_scope(self.db, self.owner, scope_id); + let g = self.resolver.update_to_inner_scope(self.db, self.store_owner, scope_id); let ty = match self.infer_path(path, id) { - Some(ty) => ty, + Some((_, ty)) => ty, None => { if path.mod_path().is_some_and(|mod_path| mod_path.is_ident() || mod_path.is_self()) { @@ -1149,7 +1288,7 @@ impl<'db> InferenceContext<'_, 'db> { }; let mut oprnd_t = self.infer_expr_inner(oprnd, expected_inner, ExprIsRead::Yes); - oprnd_t = self.table.structurally_resolve_type(oprnd_t); + oprnd_t = self.structurally_resolve_type(oprnd.into(), oprnd_t); match unop { UnaryOp::Deref => { if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) { @@ -1176,63 +1315,83 @@ impl<'db> InferenceContext<'_, 'db> { } oprnd_t } - fn infer_expr_array(&mut self, array: &Array, expected: &Expectation<'db>) -> Ty<'db> { - let elem_ty = match expected - .to_option(&mut self.table) - .map(|t| self.table.try_structurally_resolve_type(t).kind()) - { - Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st, - _ => self.table.next_ty_var(), - }; - let krate = self.resolver.krate(); + fn infer_array_repeat_expr( + &mut self, + element: ExprId, + count: ExprId, + expected: &Expectation<'db>, + expr: ExprId, + ) -> Ty<'db> { + let interner = self.interner(); + let count_ct = self.create_body_anon_const(count, self.types.types.usize, true); + let count = self.table.try_structurally_resolve_const(count.into(), count_ct); + + let uty = match expected { + Expectation::HasType(uty) => uty.builtin_index(), + _ => None, + }; - let expected = Expectation::has_type(elem_ty); - let (elem_ty, len) = match array { - Array::ElementList { elements, .. } if elements.is_empty() => { - (elem_ty, consteval::usize_const(self.db, Some(0), krate)) + let t = match uty { + Some(uty) => { + self.infer_expr_coerce(element, &Expectation::has_type(uty), ExprIsRead::Yes); + uty } - Array::ElementList { elements, .. } => { - let mut coerce = CoerceMany::with_coercion_sites(elem_ty, elements); - for &expr in elements.iter() { - let cur_elem_ty = self.infer_expr_inner(expr, &expected, ExprIsRead::Yes); - coerce.coerce( - self, - &ObligationCause::new(), - expr, - cur_elem_ty, - ExprIsRead::Yes, - ); - } - ( - coerce.complete(self), - consteval::usize_const(self.db, Some(elements.len() as u128), krate), - ) + None => { + let ty = self.table.next_ty_var(element.into()); + self.infer_expr(element, &Expectation::has_type(ty), ExprIsRead::Yes); + ty } - &Array::Repeat { initializer, repeat } => { - self.infer_expr_coerce( - initializer, - &Expectation::has_type(elem_ty), - ExprIsRead::Yes, - ); - let usize = self.types.types.usize; - let len = match self.store[repeat] { - Expr::Underscore => { - self.write_expr_ty(repeat, usize); - self.table.next_const_var() - } - _ => { - self.infer_expr(repeat, &Expectation::HasType(usize), ExprIsRead::Yes); - consteval::eval_to_const(repeat, self) - } - }; + }; + + // We defer checking whether the element type is `Copy` as it is possible to have + // an inference variable as a repeat count and it seems unlikely that `Copy` would + // have inference side effects required for type checking to succeed. + // FIXME: Do it here like rustc. + // self.deferred_repeat_expr_checks.borrow_mut().push((element, element_ty, count)); + + let ty = Ty::new_array_with_const_len(interner, t, count); + self.table.register_wf_obligation(ty.into(), ObligationCause::new(expr)); + ty + } - (elem_ty, len) + fn infer_array_elements_expr( + &mut self, + args: &[ExprId], + expected: &Expectation<'db>, + expr: ExprId, + ) -> Ty<'db> { + let element_ty = if !args.is_empty() { + let coerce_to = expected + .to_option(&self.table) + .and_then(|uty| { + self.table + .resolve_vars_with_obligations(uty) + .builtin_index() + // Avoid using the original type variable as the coerce_to type, as it may resolve + // during the first coercion instead of being the LUB type. + .filter(|t| !self.table.resolve_vars_with_obligations(*t).is_ty_var()) + }) + .unwrap_or_else(|| self.table.next_ty_var(expr.into())); + let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); + + for &e in args { + // FIXME: the element expectation should use + // `try_structurally_resolve_and_adjust_for_branches` just like in `if` and `match`. + // While that fixes nested coercion, it will break [some + // code like this](https://github.com/rust-lang/rust/pull/140283#issuecomment-2958776528). + // If we find a way to support recursive tuple coercion, this break can be avoided. + let e_ty = + self.infer_expr_inner(e, &Expectation::has_type(coerce_to), ExprIsRead::Yes); + let cause = ObligationCause::new(e); + coerce.coerce(self, &cause, e, e_ty, ExprIsRead::Yes); } + coerce.complete(self) + } else { + self.table.next_ty_var(expr.into()) }; - // Try to evaluate unevaluated constant, and insert variable if is not possible. - let len = self.table.insert_const_vars_shallow(len); - Ty::new_array_with_const_len(self.interner(), elem_ty, len) + let array_len = args.len() as u128; + Ty::new_array(self.interner(), element_ty, array_len) } pub(super) fn infer_return(&mut self, expr: ExprId) { @@ -1244,7 +1403,13 @@ impl<'db> InferenceContext<'_, 'db> { let return_expr_ty = self.infer_expr_inner(expr, &Expectation::HasType(ret_ty), ExprIsRead::Yes); let mut coerce_many = self.return_coercion.take().unwrap(); - coerce_many.coerce(self, &ObligationCause::new(), expr, return_expr_ty, ExprIsRead::Yes); + coerce_many.coerce( + self, + &ObligationCause::new(expr), + expr, + return_expr_ty, + ExprIsRead::Yes, + ); self.return_coercion = Some(coerce_many); } @@ -1258,7 +1423,7 @@ impl<'db> InferenceContext<'_, 'db> { coerce.coerce_forced_unit( self, ret, - &ObligationCause::new(), + &ObligationCause::new(ret), true, ExprIsRead::Yes, ); @@ -1285,7 +1450,7 @@ impl<'db> InferenceContext<'_, 'db> { // NB: this should *not* coerce. // tail calls don't support any coercions except lifetimes ones (like `&'static u8 -> &'a u8`). - self.unify(call_expr_ty, ret_ty); + _ = self.demand_eqtype(expr.into(), call_expr_ty, ret_ty); } None => { // FIXME: diagnose `become` outside of functions @@ -1311,16 +1476,7 @@ impl<'db> InferenceContext<'_, 'db> { .unwrap_or_else(Expectation::none); let inner_ty = self.infer_expr_inner(inner_expr, &inner_exp, ExprIsRead::Yes); - Ty::new_adt( - self.interner(), - box_id, - GenericArgs::fill_with_defaults( - self.interner(), - box_id.into(), - [inner_ty.into()], - |_, id, _| self.table.next_var_for_param(id), - ), - ) + Ty::new_box(self.interner(), inner_ty) } else { self.err_ty() } @@ -1334,8 +1490,8 @@ impl<'db> InferenceContext<'_, 'db> { label: Option<LabelId>, expected: &Expectation<'db>, ) -> Ty<'db> { - let coerce_ty = expected.coercion_target_type(&mut self.table); - let g = self.resolver.update_to_inner_scope(self.db, self.owner, expr); + let coerce_ty = expected.coercion_target_type(&mut self.table, expr.into()); + let g = self.resolver.update_to_inner_scope(self.db, self.store_owner, expr); let (break_ty, ty) = self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty), label, |this| { @@ -1345,7 +1501,7 @@ impl<'db> InferenceContext<'_, 'db> { let decl_ty = type_ref .as_ref() .map(|&tr| this.make_body_ty(tr)) - .unwrap_or_else(|| this.table.next_ty_var()); + .unwrap_or_else(|| this.table.next_ty_var((*pat).into())); let ty = if let Some(expr) = initializer { // If we have a subpattern that performs a read, we want to consider this @@ -1356,7 +1512,7 @@ impl<'db> InferenceContext<'_, 'db> { } else { ExprIsRead::No }; - let ty = if contains_explicit_ref_binding(this.store, *pat) { + let ty = if this.contains_explicit_ref_binding(*pat) { this.infer_expr( *expr, &Expectation::has_type(decl_ty), @@ -1374,11 +1530,11 @@ impl<'db> InferenceContext<'_, 'db> { decl_ty }; - let decl = DeclContext { - origin: DeclOrigin::LocalDecl { has_else: else_branch.is_some() }, - }; - - this.infer_top_pat(*pat, ty, Some(decl)); + this.infer_top_pat( + *pat, + ty, + PatOrigin::LetStmt { has_else: else_branch.is_some() }, + ); if let Some(expr) = else_branch { let previous_diverges = mem::replace(&mut this.diverges, Diverges::Maybe); @@ -1418,11 +1574,11 @@ impl<'db> InferenceContext<'_, 'db> { // `!`). if this.diverges.is_always() { // we don't even make an attempt at coercion - this.table.new_maybe_never_var() + this.table.new_maybe_never_var(expr.into()) } else if let Some(t) = expected.only_has_type(&mut this.table) { if this .coerce( - expr.into(), + expr, this.types.types.unit, t, AllowTwoPhase::No, @@ -1430,13 +1586,7 @@ impl<'db> InferenceContext<'_, 'db> { ) .is_err() { - this.result.type_mismatches.get_or_insert_default().insert( - expr.into(), - TypeMismatch { - expected: t.store(), - actual: this.types.types.unit.store(), - }, - ); + this.emit_type_mismatch(expr.into(), t, this.types.types.unit); } t } else { @@ -1451,11 +1601,12 @@ impl<'db> InferenceContext<'_, 'db> { fn lookup_field( &mut self, + field_expr: ExprId, receiver_ty: Ty<'db>, name: &Name, ) -> Option<(Ty<'db>, Either<FieldId, TupleFieldId>, Vec<Adjustment>, bool)> { let interner = self.interner(); - let mut autoderef = self.table.autoderef_with_tracking(receiver_ty); + let mut autoderef = self.table.autoderef_with_tracking(receiver_ty, field_expr.into()); let mut private_field = None; let res = autoderef.by_ref().find_map(|(derefed_ty, _)| { let (field_id, parameters) = match derefed_ty.kind() { @@ -1474,7 +1625,7 @@ impl<'db> InferenceContext<'_, 'db> { }) }); } - TyKind::Adt(adt, parameters) => match adt.def_id().0 { + TyKind::Adt(adt, parameters) => match adt.def_id() { hir_def::AdtId::StructId(s) => { let local_id = s.fields(self.db).field(name)?; let field = FieldId { parent: s.into(), local_id }; @@ -1500,7 +1651,8 @@ impl<'db> InferenceContext<'_, 'db> { } let ty = self.db.field_types(field_id.parent)[field_id.local_id] .get() - .instantiate(interner, parameters); + .instantiate(interner, parameters) + .skip_norm_wip(); Some((Either::Left(field_id), ty)) }); @@ -1518,7 +1670,8 @@ impl<'db> InferenceContext<'_, 'db> { self.table.register_infer_ok(autoderef.adjust_steps_as_infer_ok()); let ty = self.db.field_types(field_id.parent)[field_id.local_id] .get() - .instantiate(self.interner(), subst); + .instantiate(self.interner(), subst) + .skip_norm_wip(); let ty = self.process_remote_user_written_ty(ty); (ty, Either::Left(field_id), adjustments, false) @@ -1535,7 +1688,7 @@ impl<'db> InferenceContext<'_, 'db> { ) -> Ty<'db> { // Field projections don't constitute reads. let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none(), ExprIsRead::No); - let receiver_ty = self.table.structurally_resolve_type(receiver_ty); + let receiver_ty = self.structurally_resolve_type(receiver.into(), receiver_ty); if name.is_missing() { // Bail out early, don't even try to look up field. Also, we don't issue an unresolved @@ -1543,7 +1696,7 @@ impl<'db> InferenceContext<'_, 'db> { return self.err_ty(); } - match self.lookup_field(receiver_ty, name) { + match self.lookup_field(tgt_expr, receiver_ty, name) { Some((ty, field_id, adjustments, is_public)) => { self.write_expr_adj(receiver, adjustments.into_boxed_slice()); self.result.field_resolutions.insert(tgt_expr, field_id); @@ -1585,14 +1738,21 @@ impl<'db> InferenceContext<'_, 'db> { fn instantiate_erroneous_method(&mut self, def_id: FunctionId) -> MethodCallee<'db> { // FIXME: Using fresh infer vars for the method args isn't optimal, // we can do better by going thorough the full probe/confirm machinery. - let args = self.table.fresh_args_for_item(def_id.into()); - let sig = self.db.callable_item_signature(def_id.into()).instantiate(self.interner(), args); - let sig = - self.infcx().instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, sig); + let args = self.table.fresh_args_for_item(Span::Dummy, def_id.into()); + let sig = self + .db + .callable_item_signature(def_id.into()) + .instantiate(self.interner(), args) + .skip_norm_wip(); + let sig = self.infcx().instantiate_binder_with_fresh_vars( + Span::Dummy, + BoundRegionConversionTime::FnCall, + sig, + ); MethodCallee { def_id, args, sig } } - fn check_call( + fn infer_method_call_as_call( &mut self, tgt_expr: ExprId, args: &[ExprId], @@ -1603,7 +1763,14 @@ impl<'db> InferenceContext<'_, 'db> { is_varargs: bool, expected: &Expectation<'db>, ) -> Ty<'db> { - self.register_obligations_for_call(callee_ty); + if let TyKind::FnDef(def_id, args) = callee_ty.kind() { + let def_id = match def_id.0 { + CallableDefId::FunctionId(it) => it.into(), + CallableDefId::StructId(it) => it.into(), + CallableDefId::EnumVariantId(it) => it.loc(self.db).parent.into(), + }; + self.add_required_obligations_for_value_path(tgt_expr.into(), def_id, args); + } self.check_call_arguments( tgt_expr, @@ -1628,7 +1795,7 @@ impl<'db> InferenceContext<'_, 'db> { expected: &Expectation<'db>, ) -> Ty<'db> { let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none(), ExprIsRead::Yes); - let receiver_ty = self.table.try_structurally_resolve_type(receiver_ty); + let receiver_ty = self.table.try_structurally_resolve_type(receiver.into(), receiver_ty); let resolved = self.lookup_method_including_private( receiver_ty, @@ -1650,30 +1817,31 @@ impl<'db> InferenceContext<'_, 'db> { // Failed to resolve, report diagnostic and try to resolve as call to field access or // assoc function Err(_) => { - let field_with_same_name_exists = match self.lookup_field(receiver_ty, method_name) - { - Some((ty, field_id, adjustments, _public)) => { - self.write_expr_adj(receiver, adjustments.into_boxed_slice()); - self.result.field_resolutions.insert(tgt_expr, field_id); - Some(ty) - } - None => None, - }; + let field_with_same_name_exists = + match self.lookup_field(tgt_expr, receiver_ty, method_name) { + Some((ty, field_id, adjustments, _public)) => { + self.write_expr_adj(receiver, adjustments.into_boxed_slice()); + self.result.field_resolutions.insert(tgt_expr, field_id); + Some(ty) + } + None => None, + }; - let assoc_func_with_same_name = self.with_method_resolution(|ctx| { - if !matches!( - receiver_ty.kind(), - TyKind::Infer(InferTy::TyVar(_)) | TyKind::Error(_) - ) { - ctx.probe_for_name( - method_resolution::Mode::Path, - method_name.clone(), - receiver_ty, - ) - } else { - Err(MethodError::ErrorReported) - } - }); + let assoc_func_with_same_name = + self.with_method_resolution(tgt_expr.into(), receiver.into(), |ctx| { + if !matches!( + receiver_ty.kind(), + TyKind::Infer(InferTy::TyVar(_)) | TyKind::Error(_) + ) { + ctx.probe_for_name( + method_resolution::Mode::Path, + method_name.clone(), + receiver_ty, + ) + } else { + Err(MethodError::ErrorReported) + } + }); let assoc_func_with_same_name = match assoc_func_with_same_name { Ok(method_resolution::Pick { item: CandidateId::FunctionId(def_id), .. @@ -1709,7 +1877,7 @@ impl<'db> InferenceContext<'_, 'db> { }), }; match recovered { - Some((callee_ty, sig, strip_first)) => self.check_call( + Some((callee_ty, sig, strip_first)) => self.infer_method_call_as_call( tgt_expr, args, callee_ty, @@ -1751,7 +1919,7 @@ impl<'db> InferenceContext<'_, 'db> { expected, args, &[], - sig.c_variadic, + sig.c_variadic(), TupleArgumentsFlag::DontTupleArguments, ); ret_ty @@ -1778,7 +1946,7 @@ impl<'db> InferenceContext<'_, 'db> { let formal_input_tys: Vec<_> = formal_input_tys .iter() .map(|&ty| { - let generalized_ty = self.table.next_ty_var(); + let generalized_ty = self.table.next_ty_var(call_expr.into()); let _ = self.demand_eqtype(call_expr.into(), ty, generalized_ty); generalized_ty }) @@ -1801,13 +1969,13 @@ impl<'db> InferenceContext<'_, 'db> { // return type (likely containing type variables if the function // is polymorphic) and the expected return type. // No argument expectations are produced if unification fails. - let origin = ObligationCause::new(); + let origin = ObligationCause::new(call_expr); ocx.sup(&origin, self.table.param_env, expected_output, formal_output)?; for &ty in &formal_input_tys { ocx.register_obligation(Obligation::new( self.interner(), - ObligationCause::new(), + ObligationCause::new(call_expr), self.table.param_env, ClauseKind::WellFormed(ty.into()), )); @@ -1826,38 +1994,39 @@ impl<'db> InferenceContext<'_, 'db> { .unwrap_or_default(); // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here - let (formal_input_tys, expected_input_tys) = - if tuple_arguments == TupleArgumentsFlag::TupleArguments { - let tuple_type = self.table.structurally_resolve_type(formal_input_tys[0]); - match tuple_type.kind() { - // We expected a tuple and got a tuple - TyKind::Tuple(arg_types) => { - // Argument length differs - if arg_types.len() != provided_args.len() { - // FIXME: Emit an error. - } - let expected_input_tys = match expected_input_tys { - Some(expected_input_tys) => match expected_input_tys.first() { - Some(ty) => match ty.kind() { - TyKind::Tuple(tys) => Some(tys.iter().collect()), - _ => None, - }, - None => None, - }, - None => None, - }; - (arg_types.iter().collect(), expected_input_tys) - } - _ => { - // Otherwise, there's a mismatch, so clear out what we're expecting, and set - // our input types to err_args so we don't blow up the error messages + let (formal_input_tys, expected_input_tys) = if tuple_arguments + == TupleArgumentsFlag::TupleArguments + { + let tuple_type = self.structurally_resolve_type(call_expr.into(), formal_input_tys[0]); + match tuple_type.kind() { + // We expected a tuple and got a tuple + TyKind::Tuple(arg_types) => { + // Argument length differs + if arg_types.len() != provided_args.len() { // FIXME: Emit an error. - (vec![self.types.types.error; provided_args.len()], None) } + let expected_input_tys = match expected_input_tys { + Some(expected_input_tys) => match expected_input_tys.first() { + Some(ty) => match ty.kind() { + TyKind::Tuple(tys) => Some(tys.iter().collect()), + _ => None, + }, + None => None, + }, + None => None, + }; + (arg_types.to_vec(), expected_input_tys) } - } else { - (formal_input_tys.to_vec(), expected_input_tys) - }; + _ => { + // Otherwise, there's a mismatch, so clear out what we're expecting, and set + // our input types to err_args so we don't blow up the error messages + // FIXME: Emit an error. + (vec![self.types.types.error; provided_args.len()], None) + } + } + } else { + (formal_input_tys, expected_input_tys) + }; // If there are no external expectations at the call site, just use the types from the function defn let expected_input_tys = if let Some(expected_input_tys) = expected_input_tys { @@ -1916,13 +2085,7 @@ impl<'db> InferenceContext<'_, 'db> { let coerced_ty = this.table.resolve_vars_with_obligations(coerced_ty); let coerce_error = this - .coerce( - provided_arg.into(), - checked_ty, - coerced_ty, - AllowTwoPhase::Yes, - ExprIsRead::Yes, - ) + .coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, ExprIsRead::Yes) .err(); if coerce_error.is_some() { return Err((coerce_error, coerced_ty, checked_ty)); @@ -1933,7 +2096,7 @@ impl<'db> InferenceContext<'_, 'db> { let formal_ty_error = this .table .infer_ctxt - .at(&ObligationCause::new(), this.table.param_env) + .at(&ObligationCause::new(provided_arg), this.table.param_env) .eq(formal_input_ty, coerced_ty); // If neither check failed, the types are compatible @@ -1974,7 +2137,7 @@ impl<'db> InferenceContext<'_, 'db> { // closure wrapped in a block. // See <https://github.com/rust-lang/rust/issues/112225>. let is_closure = if let Expr::Closure { closure_kind, .. } = self.store[*arg] { - !matches!(closure_kind, ClosureKind::Coroutine(_)) + !matches!(closure_kind, ClosureKind::OldCoroutine(_)) } else { false }; @@ -1992,10 +2155,7 @@ impl<'db> InferenceContext<'_, 'db> { && args_count_matches { // Don't report type mismatches if there is a mismatch in args count. - self.result.type_mismatches.get_or_insert_default().insert( - (*arg).into(), - TypeMismatch { expected: expected.store(), actual: found.store() }, - ); + self.emit_type_mismatch((*arg).into(), expected, found); } } } @@ -2003,40 +2163,6 @@ impl<'db> InferenceContext<'_, 'db> { if !args_count_matches {} } - fn register_obligations_for_call(&mut self, callable_ty: Ty<'db>) { - let callable_ty = self.table.try_structurally_resolve_type(callable_ty); - if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind() { - let generic_predicates = GenericPredicates::query_all( - self.db, - GenericDefId::from_callable(self.db, fn_def.0), - ); - let param_env = self.table.param_env; - self.table.register_predicates(clauses_as_obligations( - generic_predicates.iter_instantiated(self.interner(), parameters.as_slice()), - ObligationCause::new(), - param_env, - )); - // add obligation for trait implementation, if this is a trait method - match fn_def.0 { - CallableDefId::FunctionId(f) => { - if let ItemContainerId::TraitId(trait_) = f.lookup(self.db).container { - // construct a TraitRef - let trait_params_len = generics(self.db, trait_.into()).len(); - let substs = - GenericArgs::new_from_slice(¶meters.as_slice()[..trait_params_len]); - self.table.register_predicate(Obligation::new( - self.interner(), - ObligationCause::new(), - self.table.param_env, - TraitRef::new_from_args(self.interner(), trait_.into(), substs), - )); - } - } - CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {} - } - } - } - pub(super) fn with_breakable_ctx<T>( &mut self, kind: BreakableKind, |