Unnamed repository; edit this file 'description' to name the repository.
Ensure we give spans for obligations everywhere
24 files changed, 324 insertions, 291 deletions
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs index 2c2400a14a..a8ed4126ab 100644 --- a/crates/hir-ty/src/autoderef.rs +++ b/crates/hir-ty/src/autoderef.rs @@ -40,7 +40,7 @@ pub fn autoderef<'db>( let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); let (ty, _) = infcx.instantiate_canonical(Span::Dummy, &ty); - let autoderef = Autoderef::new(&infcx, env.param_env, ty); + let autoderef = Autoderef::new(&infcx, env.param_env, ty, Span::Dummy); let mut v = Vec::new(); for (ty, _steps) in autoderef { // `ty` may contain unresolved inference variables. Since there's no chance they would be @@ -155,6 +155,7 @@ pub(crate) struct GeneralAutoderef<'db, Ctx, Steps = Vec<(Ty<'db>, AutoderefKind // Configurations: include_raw_pointers: bool, use_receiver_trait: bool, + span: Span, } pub(crate) type Autoderef<'a, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> = @@ -200,7 +201,7 @@ where // autoderef expect this type to have been structurally normalized. if let TyKind::Alias(..) = ty.kind() { let (normalized_ty, obligations) = - structurally_normalize_ty(self.infcx(), self.param_env(), ty)?; + structurally_normalize_ty(self.infcx(), self.param_env(), ty, self.span)?; self.state.obligations.extend(obligations); (AutoderefKind::Builtin, normalized_ty) } else { @@ -232,8 +233,9 @@ impl<'a, 'db> Autoderef<'a, 'db> { infcx: &'a InferCtxt<'db>, param_env: ParamEnv<'db>, base_ty: Ty<'db>, + span: Span, ) -> Self { - Self::new_impl(DefaultAutoderefCtx { infcx, param_env }, base_ty) + Self::new_impl(DefaultAutoderefCtx { infcx, param_env }, base_ty, span) } } @@ -242,8 +244,9 @@ impl<'a, 'b, 'db> InferenceContextAutoderef<'a, 'b, 'db> { pub(crate) fn new_from_inference_context( ctx: &'a mut InferenceContext<'b, 'db>, base_ty: Ty<'db>, + span: Span, ) -> Self { - Self::new_impl(InferenceContextAutoderefCtx(ctx), base_ty) + Self::new_impl(InferenceContextAutoderefCtx(ctx), base_ty, span) } #[inline] @@ -258,8 +261,9 @@ impl<'a, 'db> Autoderef<'a, 'db, usize> { infcx: &'a InferCtxt<'db>, param_env: ParamEnv<'db>, base_ty: Ty<'db>, + span: Span, ) -> Self { - Self::new_impl(DefaultAutoderefCtx { infcx, param_env }, base_ty) + Self::new_impl(DefaultAutoderefCtx { infcx, param_env }, base_ty, span) } } @@ -269,7 +273,7 @@ where Steps: TrackAutoderefSteps<'db>, { #[inline] - fn new_impl(ctx: Ctx, base_ty: Ty<'db>) -> Self { + fn new_impl(ctx: Ctx, base_ty: Ty<'db>, span: Span) -> Self { GeneralAutoderef { state: AutoderefSnapshot { steps: Steps::default(), @@ -282,6 +286,7 @@ where traits: None, include_raw_pointers: false, use_receiver_trait: false, + span, } } @@ -338,7 +343,7 @@ where let trait_ref = TraitRef::new(interner, trait_.into(), [ty]); let obligation = - Obligation::new(interner, ObligationCause::new(), self.param_env(), trait_ref); + Obligation::new(interner, ObligationCause::new(self.span), self.param_env(), trait_ref); // We detect whether the self type implements `Deref` before trying to // structurally normalize. We use `predicate_may_hold_opaque_types_jank` // to support not-yet-defined opaque types. It will succeed for `impl Deref` @@ -352,6 +357,7 @@ where self.infcx(), self.param_env(), Ty::new_projection(interner, trait_target.into(), [ty]), + self.span, )?; debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); self.state.obligations.extend(obligations); @@ -403,9 +409,11 @@ fn structurally_normalize_ty<'db>( infcx: &InferCtxt<'db>, param_env: ParamEnv<'db>, ty: Ty<'db>, + span: Span, ) -> Option<(Ty<'db>, PredicateObligations<'db>)> { let mut ocx = ObligationCtxt::new(infcx); - let Ok(normalized_ty) = ocx.structurally_normalize_ty(&ObligationCause::misc(), param_env, ty) + let Ok(normalized_ty) = + ocx.structurally_normalize_ty(&ObligationCause::new(span), param_env, ty) else { // We shouldn't have errors here in the old solver, except for // evaluate/fulfill mismatches, but that's not a reason for an ICE. diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index c300388c5e..97693435fe 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -771,7 +771,7 @@ fn render_const_scalar<'db>( ) -> Result { let param_env = ParamEnv::empty(); let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis); - let ty = infcx.at(&ObligationCause::new(), param_env).deeply_normalize(ty).unwrap_or(ty); + let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty); render_const_scalar_inner(f, b, memory_map, ty, param_env) } @@ -1056,7 +1056,7 @@ fn render_const_scalar_from_valtree<'db>( ) -> Result { let param_env = ParamEnv::empty(); let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis); - let ty = infcx.at(&ObligationCause::new(), param_env).deeply_normalize(ty).unwrap_or(ty); + let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty); render_const_scalar_from_valtree_inner(f, ty, valtree, param_env) } diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 09c1325c41..83659dde17 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -1934,7 +1934,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } pub(crate) fn structurally_resolve_type(&mut self, node: ExprOrPatId, ty: Ty<'db>) -> Ty<'db> { - let result = self.table.try_structurally_resolve_type(ty); + let result = self.table.try_structurally_resolve_type(node.into(), ty); if result.is_ty_var() { self.type_must_be_known_at_this_point(node, ty) } else { result } } @@ -1944,14 +1944,18 @@ impl<'body, 'db> InferenceContext<'body, 'db> { expected: Ty<'db>, actual: Ty<'db>, ) -> Result<(), ()> { - let result = self.demand_eqtype_fixme_no_diag(expected, actual); + let result = self + .table + .at(&ObligationCause::new(id)) + .eq(expected, actual) + .map(|infer_ok| self.table.register_infer_ok(infer_ok)); if result.is_err() { self.result .type_mismatches .get_or_insert_default() .insert(id, TypeMismatch { expected: expected.store(), actual: actual.store() }); } - result + result.map_err(drop) } fn demand_eqtype_fixme_no_diag( @@ -1961,7 +1965,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { ) -> Result<(), ()> { let result = self .table - .at(&ObligationCause::new()) + .at(&ObligationCause::dummy()) .eq(expected, actual) .map(|infer_ok| self.table.register_infer_ok(infer_ok)); result.map_err(drop) @@ -1975,7 +1979,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { ) -> Result<(), ()> { let result = self .table - .at(&ObligationCause::new()) + .at(&ObligationCause::new(id)) .sup(expected, actual) .map(|infer_ok| self.table.register_infer_ok(infer_ok)); if result.is_err() { @@ -2016,11 +2020,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.types.types.error } - pub(crate) fn require_type_is_sized(&mut self, ty: Ty<'db>) { + pub(crate) fn require_type_is_sized(&mut self, ty: Ty<'db>, span: Span) { if !ty.references_non_lt_error() && let Some(sized_trait) = self.lang_items.Sized { - self.table.register_bound(ty, sized_trait, ObligationCause::new()); + self.table.register_bound(ty, sized_trait, ObligationCause::new(span)); } } @@ -2085,7 +2089,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { args, ), ); - ty = self.table.try_structurally_resolve_type(alias); + ty = self.table.try_structurally_resolve_type(node.into(), alias); segments = segments.skip(1); } @@ -2185,7 +2189,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { never!("resolver should always resolve lang item paths"); return (self.err_ty(), None); }; - return self.resolve_variant_on_alias(ty, None, mod_path); + return self.resolve_variant_on_alias(node, ty, None, mod_path); }; let mut remaining_segments = path.segments().skip(remaining_idx); @@ -2298,7 +2302,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { let ty = self.db.ty(it.into()).instantiate(interner, args); let ty = self.insert_type_vars(ty, Span::Dummy); - self.resolve_variant_on_alias(ty, unresolved, mod_path) + self.resolve_variant_on_alias(node, ty, unresolved, mod_path) } TypeNs::AdtSelfType(_) => { // FIXME this could happen in array size expressions, once we're checking them @@ -2330,12 +2334,13 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn resolve_variant_on_alias( &mut self, + node: ExprOrPatId, ty: Ty<'db>, unresolved: Option<usize>, path: &ModPath, ) -> (Ty<'db>, Option<VariantId>) { let remaining = unresolved.map(|it| path.segments()[it..].len()).filter(|it| it > &0); - let ty = self.table.try_structurally_resolve_type(ty); + let ty = self.table.try_structurally_resolve_type(node.into(), ty); match remaining { None => { let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id { @@ -2548,10 +2553,14 @@ impl<'db> Expectation<'db> { /// an expected type. Otherwise, we might write parts of the type /// when checking the 'then' block which are incompatible with the /// 'else' branch. - fn adjust_for_branches(&self, table: &mut unify::InferenceTable<'db>) -> Expectation<'db> { + fn adjust_for_branches( + &self, + table: &mut unify::InferenceTable<'db>, + span: Span, + ) -> Expectation<'db> { match *self { Expectation::HasType(ety) => { - let ety = table.try_structurally_resolve_type(ety); + let ety = table.try_structurally_resolve_type(span, ety); if ety.is_ty_var() { Expectation::None } else { Expectation::HasType(ety) } } Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety), diff --git a/crates/hir-ty/src/infer/autoderef.rs b/crates/hir-ty/src/infer/autoderef.rs index a6c7b2dbb9..0ba3b3dd05 100644 --- a/crates/hir-ty/src/infer/autoderef.rs +++ b/crates/hir-ty/src/infer/autoderef.rs @@ -5,7 +5,7 @@ use std::iter; use rustc_ast_ir::Mutability; use crate::{ - Adjust, Adjustment, OverloadedDeref, + Adjust, Adjustment, OverloadedDeref, Span, autoderef::{Autoderef, AutoderefCtx, AutoderefKind, GeneralAutoderef}, infer::unify::InferenceTable, next_solver::{ @@ -15,12 +15,16 @@ use crate::{ }; impl<'db> InferenceTable<'db> { - pub(crate) fn autoderef(&self, base_ty: Ty<'db>) -> Autoderef<'_, 'db, usize> { - Autoderef::new(&self.infer_ctxt, self.param_env, base_ty) + pub(crate) fn autoderef(&self, base_ty: Ty<'db>, span: Span) -> Autoderef<'_, 'db, usize> { + Autoderef::new(&self.infer_ctxt, self.param_env, base_ty, span) } - pub(crate) fn autoderef_with_tracking(&self, base_ty: Ty<'db>) -> Autoderef<'_, 'db> { - Autoderef::new_with_tracking(&self.infer_ctxt, self.param_env, base_ty) + pub(crate) fn autoderef_with_tracking( + &self, + base_ty: Ty<'db>, + span: Span, + ) -> Autoderef<'_, 'db> { + Autoderef::new_with_tracking(&self.infer_ctxt, self.param_env, base_ty, span) } } diff --git a/crates/hir-ty/src/infer/callee.rs b/crates/hir-ty/src/infer/callee.rs index 9fe566b8fe..9c134cb75f 100644 --- a/crates/hir-ty/src/infer/callee.rs +++ b/crates/hir-ty/src/infer/callee.rs @@ -43,9 +43,11 @@ impl<'db> InferenceContext<'_, 'db> { ) -> Ty<'db> { let original_callee_ty = self.infer_expr_no_expect(callee_expr, ExprIsRead::Yes); - let expr_ty = self.table.try_structurally_resolve_type(original_callee_ty); + let expr_ty = + self.table.try_structurally_resolve_type(callee_expr.into(), original_callee_ty); - let mut autoderef = GeneralAutoderef::new_from_inference_context(self, expr_ty); + let mut autoderef = + GeneralAutoderef::new_from_inference_context(self, expr_ty, callee_expr.into()); let mut result = None; let mut error_reported = false; while result.is_none() && autoderef.next().is_some() { @@ -95,7 +97,7 @@ impl<'db> InferenceContext<'_, 'db> { }; // we must check that return type of called functions is WF: - self.table.register_wf_obligation(output.into(), ObligationCause::new()); + self.table.register_wf_obligation(output.into(), ObligationCause::new(call_expr)); output } @@ -108,7 +110,8 @@ impl<'db> InferenceContext<'_, 'db> { error_reported: &mut bool, ) -> Option<CallStep<'db>> { let final_ty = autoderef.final_ty(); - let adjusted_ty = autoderef.ctx().table.try_structurally_resolve_type(final_ty); + let adjusted_ty = + autoderef.ctx().table.try_structurally_resolve_type(callee_expr.into(), final_ty); // If the callee is a function pointer or a closure, then we're all set. match adjusted_ty.kind() { @@ -242,8 +245,8 @@ impl<'db> InferenceContext<'_, 'db> { // is implemented, and use this information for diagnostic. autoderef .ctx() - .try_overloaded_call_traits(adjusted_ty, Some(arg_exprs)) - .or_else(|| autoderef.ctx().try_overloaded_call_traits(adjusted_ty, None)) + .try_overloaded_call_traits(call_expr, adjusted_ty, Some(arg_exprs)) + .or_else(|| autoderef.ctx().try_overloaded_call_traits(call_expr, adjusted_ty, None)) .map(|(autoref, method)| { let adjustments = autoderef.adjust_steps_as_infer_ok(); let mut adjustments = autoderef.ctx().table.register_infer_ok(adjustments); @@ -255,6 +258,7 @@ impl<'db> InferenceContext<'_, 'db> { fn try_overloaded_call_traits( &mut self, + call_expr: ExprId, adjusted_ty: Ty<'db>, opt_arg_exprs: Option<&[ExprId]>, ) -> Option<(Option<Adjustment>, MethodCallee<'db>)> { @@ -311,7 +315,7 @@ impl<'db> InferenceContext<'_, 'db> { // one which may apply. So if we treat opaques as inference variables // `Box<impl FnOnce()>: Fn` is considered ambiguous and chosen. if let Some(ok) = self.table.lookup_method_for_operator( - ObligationCause::new(), + ObligationCause::new(call_expr), method_name, trait_def_id, adjusted_ty, @@ -464,8 +468,9 @@ impl<'db> InferenceContext<'_, 'db> { && let Some(ty) = fn_sig.inputs().last().copied() && let Some(tuple_trait) = self.lang_items.Tuple { - self.table.register_bound(ty, tuple_trait, ObligationCause::new()); - self.require_type_is_sized(ty); + let span = arg_exprs.last().copied().unwrap_or(call_expr); + self.table.register_bound(ty, tuple_trait, ObligationCause::new(span)); + self.require_type_is_sized(ty, span.into()); } fn_sig.output() @@ -538,7 +543,7 @@ impl<'a, 'db> DeferredCallResolution<'db> { assert!(ctx.infcx().closure_kind(self.closure_ty).is_some()); // We may now know enough to figure out fn vs fnmut etc. - match ctx.try_overloaded_call_traits(self.closure_ty, None) { + match ctx.try_overloaded_call_traits(self.call_expr, self.closure_ty, None) { Some((autoref, method_callee)) => { // One problem is that when we get here, we are going // to have a newly instantiated function signature diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs index daf954c217..1dade4dfd7 100644 --- a/crates/hir-ty/src/infer/cast.rs +++ b/crates/hir-ty/src/infer/cast.rs @@ -125,8 +125,9 @@ impl<'db> CastCheck<'db> { &mut self, ctx: &mut InferenceContext<'_, 'db>, ) -> Result<(), InferenceDiagnostic> { - self.expr_ty = ctx.table.try_structurally_resolve_type(self.expr_ty); - self.cast_ty = ctx.table.try_structurally_resolve_type(self.cast_ty); + self.expr_ty = + ctx.table.try_structurally_resolve_type(self.source_expr.into(), self.expr_ty); + self.cast_ty = ctx.table.try_structurally_resolve_type(self.expr.into(), self.cast_ty); // This should always come first so that we apply the coercion, which impacts infer vars. if ctx @@ -199,7 +200,8 @@ impl<'db> CastCheck<'db> { }, // array-ptr-cast CastTy::Ptr(t, m) => { - let t = ctx.table.try_structurally_resolve_type(t); + let t = + ctx.table.try_structurally_resolve_type(self.expr.into(), t); if !ctx.table.type_is_sized_modulo_regions(t) { return Err(CastError::IllegalCast); } @@ -262,8 +264,8 @@ impl<'db> CastCheck<'db> { t_cast: Ty<'db>, m_cast: Mutability, ) -> Result<(), CastError> { - let t_expr = ctx.table.try_structurally_resolve_type(t_expr); - let t_cast = ctx.table.try_structurally_resolve_type(t_cast); + let t_expr = ctx.table.try_structurally_resolve_type(self.expr.into(), t_expr); + let t_cast = ctx.table.try_structurally_resolve_type(self.expr.into(), t_cast); if m_expr >= m_cast && let TyKind::Array(ety, _) = t_expr.kind() @@ -306,8 +308,8 @@ impl<'db> CastCheck<'db> { src: Ty<'db>, dst: Ty<'db>, ) -> Result<(), CastError> { - let src_kind = pointer_kind(src, ctx).map_err(|_| CastError::Unknown)?; - let dst_kind = pointer_kind(dst, ctx).map_err(|_| CastError::Unknown)?; + let src_kind = pointer_kind(self.expr, src, ctx).map_err(|_| CastError::Unknown)?; + let dst_kind = pointer_kind(self.expr, dst, ctx).map_err(|_| CastError::Unknown)?; match (src_kind, dst_kind) { (Some(PointerKind::Error), _) | (_, Some(PointerKind::Error)) => Ok(()), @@ -372,7 +374,7 @@ impl<'db> CastCheck<'db> { // This is `fcx.demand_eqtype`, but inlined to give a better error. if ctx .table - .at(&ObligationCause::dummy()) + .at(&ObligationCause::new(self.expr)) .eq(src_obj, dst_obj) .map(|infer_ok| ctx.table.register_infer_ok(infer_ok)) .is_err() @@ -457,7 +459,7 @@ impl<'db> CastCheck<'db> { ctx: &mut InferenceContext<'_, 'db>, expr_ty: Ty<'db>, ) -> Result<(), CastError> { - match pointer_kind(expr_ty, ctx).map_err(|_| CastError::Unknown)? { + match pointer_kind(self.expr, expr_ty, ctx).map_err(|_| CastError::Unknown)? { // None => Err(CastError::UnknownExprPtrKind), None => Ok(()), Some(PointerKind::Error) => Ok(()), @@ -471,7 +473,7 @@ impl<'db> CastCheck<'db> { ctx: &mut InferenceContext<'_, 'db>, cast_ty: Ty<'db>, ) -> Result<(), CastError> { - match pointer_kind(cast_ty, ctx).map_err(|_| CastError::Unknown)? { + match pointer_kind(self.expr, cast_ty, ctx).map_err(|_| CastError::Unknown)? { // None => Err(CastError::UnknownCastPtrKind), None => Ok(()), Some(PointerKind::Error) => Ok(()), @@ -487,7 +489,7 @@ impl<'db> CastCheck<'db> { ctx: &mut InferenceContext<'_, 'db>, cast_ty: Ty<'db>, ) -> Result<(), CastError> { - match pointer_kind(cast_ty, ctx).map_err(|_| CastError::Unknown)? { + match pointer_kind(self.expr, cast_ty, ctx).map_err(|_| CastError::Unknown)? { // None => Err(CastError::UnknownCastPtrKind), None => Ok(()), Some(PointerKind::Error) => Ok(()), @@ -516,10 +518,11 @@ enum PointerKind<'db> { } fn pointer_kind<'db>( + expr: ExprId, ty: Ty<'db>, ctx: &mut InferenceContext<'_, 'db>, ) -> Result<Option<PointerKind<'db>>, ()> { - let ty = ctx.table.try_structurally_resolve_type(ty); + let ty = ctx.table.try_structurally_resolve_type(expr.into(), ty); if ctx.table.type_is_sized_modulo_regions(ty) { return Ok(Some(PointerKind::Thin)); @@ -540,14 +543,14 @@ fn pointer_kind<'db>( let last_field_ty = ctx.db.field_types(id.into())[last_field] .get() .instantiate(ctx.interner(), subst); - pointer_kind(last_field_ty, ctx) + pointer_kind(expr, last_field_ty, ctx) } else { Ok(Some(PointerKind::Thin)) } } TyKind::Tuple(subst) => match subst.iter().next_back() { None => Ok(Some(PointerKind::Thin)), - Some(ty) => pointer_kind(ty, ctx), + Some(ty) => pointer_kind(expr, ty, ctx), }, TyKind::Foreign(_) => Ok(Some(PointerKind::Thin)), TyKind::Alias(..) => Ok(Some(PointerKind::OfAlias)), diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index f90f135919..218d8e2f3e 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -18,7 +18,7 @@ use rustc_type_ir::{ use tracing::debug; use crate::{ - FnAbi, + FnAbi, Span, db::{InternedClosure, InternedClosureId, InternedCoroutineClosureId, InternedCoroutineId}, infer::{BreakableKind, Diverges, coerce::CoerceMany, pat::PatOrigin}, next_solver::{ @@ -80,14 +80,14 @@ impl<'db> InferenceContext<'_, 'db> { // type, and see if can glean a closure kind from there. let (expected_sig, expected_kind) = match expected.to_option(&mut self.table) { Some(ty) => { - let ty = self.table.try_structurally_resolve_type(ty); + let ty = self.table.try_structurally_resolve_type(closure_expr.into(), ty); self.deduce_closure_signature(closure_expr, ty, closure_kind) } None => (None, None), }; let ClosureSignatures { bound_sig, mut liberated_sig } = - self.sig_of_closure(closure_expr, arg_types, ret_type, expected_sig); + self.sig_of_closure(closure_expr, args, arg_types, ret_type, expected_sig); debug!(?bound_sig, ?liberated_sig); @@ -143,7 +143,7 @@ impl<'db> InferenceContext<'_, 'db> { ClosureKind::OldCoroutine(_) | ClosureKind::Coroutine { kind: CoroutineKind::Gen, .. } => { let yield_ty = self.table.next_ty_var(closure_expr.into()); - self.require_type_is_sized(yield_ty); + self.require_type_is_sized(yield_ty, closure_expr.into()); yield_ty } ClosureKind::Coroutine { kind: CoroutineKind::Async, .. } => { @@ -151,7 +151,7 @@ impl<'db> InferenceContext<'_, 'db> { } ClosureKind::Coroutine { kind: CoroutineKind::AsyncGen, .. } => { let yield_ty = self.table.next_ty_var(closure_expr.into()); - self.require_type_is_sized(yield_ty); + self.require_type_is_sized(yield_ty, closure_expr.into()); self.poll_option_ty(yield_ty) } _ => unreachable!(), @@ -475,7 +475,7 @@ impl<'db> InferenceContext<'_, 'db> { _ = self .table .infer_ctxt - .at(&ObligationCause::new(), self.table.param_env) + .at(&ObligationCause::new(closure_expr), self.table.param_env) .eq(inferred_fnptr_sig, generalized_fnptr_sig) .map(|infer_ok| self.table.register_infer_ok(infer_ok)); @@ -681,14 +681,21 @@ impl<'db> InferenceContext<'_, 'db> { fn sig_of_closure( &mut self, closure_expr: ExprId, - decl_inputs: &[Option<TypeRefId>], - decl_output: Option<TypeRefId>, + decl_inputs: &[PatId], + decl_input_tys: &[Option<TypeRefId>], + decl_output_ty: Option<TypeRefId>, expected_sig: Option<PolyFnSig<'db>>, ) -> ClosureSignatures<'db> { if let Some(e) = expected_sig { - self.sig_of_closure_with_expectation(closure_expr, decl_inputs, decl_output, e) + self.sig_of_closure_with_expectation( + closure_expr, + decl_inputs, + decl_input_tys, + decl_output_ty, + e, + ) } else { - self.sig_of_closure_no_expectation(closure_expr, decl_inputs, decl_output) + self.sig_of_closure_no_expectation(closure_expr, decl_input_tys, decl_output_ty) } } @@ -755,18 +762,25 @@ impl<'db> InferenceContext<'_, 'db> { fn sig_of_closure_with_expectation( &mut self, closure_expr: ExprId, - decl_inputs: &[Option<TypeRefId>], - decl_output: Option<TypeRefId>, + decl_inputs: &[PatId], + decl_input_tys: &[Option<TypeRefId>], + decl_output_ty: Option<TypeRefId>, expected_sig: PolyFnSig<'db>, ) -> ClosureSignatures<'db> { // Watch out for some surprises and just ignore the // expectation if things don't see to match up with what we // expect. if expected_sig.c_variadic() { - return self.sig_of_closure_no_expectation(closure_expr, decl_inputs, decl_output); - } else if expected_sig.skip_binder().inputs_and_output.len() != decl_inputs.len() + 1 { - return self - .sig_of_closure_with_mismatched_number_of_arguments(decl_inputs, decl_output); + return self.sig_of_closure_no_expectation( + closure_expr, + decl_input_tys, + decl_output_ty, + ); + } else if expected_sig.skip_binder().inputs_and_output.len() != decl_input_tys.len() + 1 { + return self.sig_of_closure_with_mismatched_number_of_arguments( + decl_input_tys, + decl_output_ty, + ); } // Create a `PolyFnSig`. Note the oddity that late bound @@ -798,11 +812,14 @@ impl<'db> InferenceContext<'_, 'db> { match self.merge_supplied_sig_with_expectation( closure_expr, decl_inputs, - decl_output, + decl_input_tys, + decl_output_ty, closure_sigs, ) { Ok(infer_ok) => self.table.register_infer_ok(infer_ok), - Err(_) => self.sig_of_closure_no_expectation(closure_expr, decl_inputs, decl_output), + Err(_) => { + self.sig_of_closure_no_expectation(closure_expr, decl_input_tys, decl_output_ty) + } } } @@ -822,15 +839,17 @@ impl<'db> InferenceContext<'_, 'db> { fn merge_supplied_sig_with_expectation( &mut self, closure_expr: ExprId, - decl_inputs: &[Option<TypeRefId>], - decl_output: Option<TypeRefId>, + decl_inputs: &[PatId], + decl_input_tys: &[Option<TypeRefId>], + decl_output_ty: Option<TypeRefId>, mut expected_sigs: ClosureSignatures<'db>, ) -> InferResult<'db, ClosureSignatures<'db>> { // Get the signature S that the user gave. // // (See comment on `sig_of_closure_with_expectation` for the // meaning of these letters.) - let supplied_sig = self.supplied_sig_of_closure(closure_expr, decl_inputs, decl_output); + let supplied_sig = + self.supplied_sig_of_closure(closure_expr, decl_input_tys, decl_output_ty); debug!(?supplied_sig); @@ -858,19 +877,21 @@ impl<'db> InferenceContext<'_, 'db> { // The liberated version of this signature should be a subtype // of the liberated form of the expectation. - for (supplied_ty, expected_ty) in iter::zip( - supplied_sig.inputs().iter().copied(), + for ((decl_input, supplied_ty), expected_ty) in iter::zip( + iter::zip(decl_inputs, supplied_sig.inputs().iter().copied()), expected_sigs.liberated_sig.inputs().iter().copied(), ) { // Check that E' = S'. - let cause = ObligationCause::new(); + let cause = ObligationCause::new(*decl_input); let InferOk { value: (), obligations } = table.infer_ctxt.at(&cause, table.param_env).eq(expected_ty, supplied_ty)?; all_obligations.extend(obligations); } let supplied_output_ty = supplied_sig.output(); - let cause = ObligationCause::new(); + let cause = ObligationCause::new( + decl_output_ty.map(Span::TypeRefId).unwrap_or(closure_expr.into()), + ); let InferOk { value: (), obligations } = table .infer_ctxt diff --git a/crates/hir-ty/src/infer/closure/analysis.rs b/crates/hir-ty/src/infer/closure/analysis.rs index eb4eb8cce3..ce7931bb3c 100644 --- a/crates/hir-ty/src/infer/closure/analysis.rs +++ b/crates/hir-ty/src/infer/closure/analysis.rs @@ -52,7 +52,7 @@ use span::Edition; use tracing::{debug, instrument}; use crate::{ - FnAbi, + FnAbi, Span, infer::{ CaptureInfo, CaptureSourceStack, CapturedPlace, InferenceContext, UpvarCapture, closure::analysis::expr_use_visitor::{ @@ -920,12 +920,12 @@ impl<'a, 'db> InferenceContext<'a, 'db> { self.result.closures_data.insert(closure_def_id, closure_data); } - fn normalize_capture_place(&self, place: Place) -> Place { + fn normalize_capture_place(&self, span: Span, place: Place) -> Place { let mut place = self.infcx().resolve_vars_if_possible(place); // In the new solver, types in HIR `Place`s can contain unnormalized aliases, // which can ICE later (e.g. when projecting fields for diagnostics). - let cause = ObligationCause::misc(); + let cause = ObligationCause::new(span); let at = self.table.at(&cause); match normalize::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( at, @@ -1011,7 +1011,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // Normalize eagerly when inserting into `capture_information`, so all downstream // capture analysis can assume a normalized `Place`. - self.normalize_capture_place(place) + self.normalize_capture_place(var_hir_id.into(), place) } /// A captured place is mutable if @@ -1215,7 +1215,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { let mut dummy_capture_info = CaptureInfo { sources: SmallVec::new(), capture_kind: dummy_capture_kind }; - let place = ctx.normalize_capture_place(place_with_id.place.clone()); + let place = ctx.normalize_capture_place(place_with_id.span(), place_with_id.place.clone()); let place = restrict_capture_precision(place, &mut dummy_capture_info); @@ -1231,7 +1231,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { }; assert_eq!(self.closure_def_id, upvar_closure); - let place = ctx.normalize_capture_place(place_with_id.place.clone()); + let place = ctx.normalize_capture_place(place_with_id.span(), place_with_id.place.clone()); self.capture_information.push(( place, @@ -1246,7 +1246,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { }; assert_eq!(self.closure_def_id, upvar_closure); - let place = ctx.normalize_capture_place(place_with_id.place.clone()); + let place = ctx.normalize_capture_place(place_with_id.span(), place_with_id.place.clone()); self.capture_information.push(( place, @@ -1271,7 +1271,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { let mut capture_info = CaptureInfo { sources: place_with_id.origins.iter().cloned().collect(), capture_kind }; - let place = ctx.normalize_capture_place(place_with_id.place.clone()); + let place = ctx.normalize_capture_place(place_with_id.span(), place_with_id.place.clone()); // We only want repr packed restriction to be applied to reading references into a packed // struct, and not when the data is being moved. Therefore we call this method here instead diff --git a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index b234e69197..44dc1a63d1 100644 --- a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -14,22 +14,19 @@ use hir_def::{ }, resolver::ValueNs, }; -use rustc_ast_ir::{try_visit, visit::VisitorResult}; -use rustc_type_ir::{ - FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, - inherent::{IntoKind, Ty as _}, -}; +use macros::{TypeFoldable, TypeVisitable}; +use rustc_type_ir::inherent::{IntoKind, Ty as _}; use smallvec::{SmallVec, smallvec}; use syntax::ast::{BinaryOp, UnaryOp}; use tracing::{debug, instrument, trace}; use crate::{ - Adjust, Adjustment, AutoBorrow, + Adjust, Adjustment, AutoBorrow, Span, infer::{ ByRef, CaptureSourceStack, InferenceContext, UpvarCapture, closure::analysis::BorrowKind, }, method_resolution::CandidateId, - next_solver::{DbInterner, ErrorGuaranteed, StoredTy, Ty, TyKind}, + next_solver::{ErrorGuaranteed, StoredTy, Ty, TyKind}, upvars::UpvarsRef, utils::EnumerateAndAdjustIterator, }; @@ -71,12 +68,13 @@ pub enum PlaceBase { Upvar { closure: ExprId, var_id: BindingId }, } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] pub struct Projection { /// Type after the projection is applied. pub ty: StoredTy, /// Defines the kind of access made by the projection. + #[type_visitable(ignore)] pub kind: ProjectionKind, } @@ -84,61 +82,17 @@ pub struct Projection { /// always correspond to a syntactic place expression. For example, when /// processing a pattern, a `Place` can be used to refer to the sub-value /// currently being inspected. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] pub struct Place { /// The type of the `PlaceBase` pub base_ty: StoredTy, /// The "outermost" place that holds this value. + #[type_visitable(ignore)] pub base: PlaceBase, /// How this place is derived from the base place. pub projections: Vec<Projection>, } -impl<'db> TypeVisitable<DbInterner<'db>> for Place { - fn visit_with<V: TypeVisitor<DbInterner<'db>>>(&self, visitor: &mut V) -> V::Result { - let Self { base_ty, base: _, projections } = self; - try_visit!(base_ty.as_ref().visit_with(visitor)); - for proj in projections { - let Projection { ty, kind: _ } = proj; - try_visit!(ty.as_ref().visit_with(visitor)); - } - V::Result::output() - } -} - -impl<'db> TypeFoldable<DbInterner<'db>> for Place { - fn try_fold_with<F: FallibleTypeFolder<DbInterner<'db>>>( - self, - folder: &mut F, - ) -> Result<Self, F::Error> { - let Self { base_ty, base, projections } = self; - let base_ty = base_ty.as_ref().try_fold_with(folder)?.store(); - let projections = projections - .into_iter() - .map(|proj| { - let Projection { ty, kind } = proj; - let ty = ty.as_ref().try_fold_with(folder)?.store(); - Ok(Projection { ty, kind }) - }) - .collect::<Result<_, _>>()?; - Ok(Self { base_ty, base, projections }) - } - - fn fold_with<F: TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self { - let Self { base_ty, base, projections } = self; - let base_ty = base_ty.as_ref().fold_with(folder).store(); - let projections = projections - .into_iter() - .map(|proj| { - let Projection { ty, kind } = proj; - let ty = ty.as_ref().fold_with(folder).store(); - Projection { ty, kind } - }) - .collect(); - Self { base_ty, base, projections } - } -} - impl Place { /// Returns an iterator of the types that have to be dereferenced to access /// the `Place`. @@ -216,6 +170,13 @@ impl PlaceWithOrigin { origin_stack.push(origin); } } + + pub(crate) fn span(&self) -> Span { + match self.origins.first() { + Some(origin) => origin.final_source().into(), + None => Span::Dummy, + } + } } /// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs index b2bed0ce2b..15265b9104 100644 --- a/crates/hir-ty/src/infer/coerce.rs +++ b/crates/hir-ty/src/infer/coerce.rs @@ -377,7 +377,8 @@ where let mut first_error = None; let mut r_borrow_var = None; - let mut autoderef = Autoderef::new_with_tracking(self.infcx(), self.param_env(), a); + let mut autoderef = + Autoderef::new_with_tracking(self.infcx(), self.param_env(), a, self.cause.span()); let mut found = None; for (referent_ty, autoderefs) in autoderef.by_ref() { @@ -897,11 +898,11 @@ impl<'db> InferenceContext<'_, 'db> { allow_two_phase: AllowTwoPhase, expr_is_read: ExprIsRead, ) -> RelateResult<'db, Ty<'db>> { - let source = self.table.try_structurally_resolve_type(expr_ty); - target = self.table.try_structurally_resolve_type(target); + let source = self.table.try_structurally_resolve_type(expr.into(), expr_ty); + target = self.table.try_structurally_resolve_type(expr.into(), target); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); - let cause = ObligationCause::with_span(expr.into()); + let cause = ObligationCause::new(expr); let coerce_never = self.expr_guaranteed_to_constitute_read_for_never(expr, expr_is_read); let mut coerce = Coerce { delegate: InferenceCoercionDelegate(self), @@ -930,8 +931,8 @@ impl<'db> InferenceContext<'_, 'db> { new: ExprId, new_ty: Ty<'db>, ) -> RelateResult<'db, Ty<'db>> { - let prev_ty = self.table.try_structurally_resolve_type(prev_ty); - let new_ty = self.table.try_structurally_resolve_type(new_ty); + let prev_ty = self.table.try_structurally_resolve_type(new.into(), prev_ty); + let new_ty = self.table.try_structurally_resolve_type(new.into(), new_ty); debug!( "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)", prev_ty, @@ -977,7 +978,7 @@ impl<'db> InferenceContext<'_, 'db> { // We need to eagerly handle nested obligations due to lazy norm. let mut ocx = ObligationCtxt::new(&table.infer_ctxt); let value = ocx.lub( - &ObligationCause::with_span(new.into()), + &ObligationCause::new(new), table.param_env, prev_ty, new_ty, @@ -1029,7 +1030,7 @@ impl<'db> InferenceContext<'_, 'db> { let sig = self .table .infer_ctxt - .at(&ObligationCause::with_span(new.into()), self.table.param_env) + .at(&ObligationCause::new(new), self.table.param_env) .lub(a_sig, b_sig) .map(|ok| self.table.register_infer_ok(ok))?; @@ -1075,7 +1076,7 @@ impl<'db> InferenceContext<'_, 'db> { // operate on values and not places, so a never coercion is valid. let mut coerce = Coerce { delegate: InferenceCoercionDelegate(self), - cause: ObligationCause::with_span(new.into()), + cause: ObligationCause::new(new), allow_two_phase: AllowTwoPhase::No, coerce_never: true, use_lub: true, @@ -1111,7 +1112,7 @@ impl<'db> InferenceContext<'_, 'db> { .commit_if_ok(|table| { table .infer_ctxt - .at(&ObligationCause::with_span(new.into()), table.param_env) + .at(&ObligationCause::new(new), table.param_env) .lub(prev_ty, new_ty) }) .unwrap_err()) @@ -1459,7 +1460,7 @@ fn coerce<'db>( let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); let ((ty1_with_vars, ty2_with_vars), vars) = infcx.instantiate_canonical(Span::Dummy, tys); - let cause = ObligationCause::new(); + let cause = ObligationCause::dummy(); // FIXME: Target features. let target_features = TargetFeatures::default(); let mut coerce = Coerce { diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index c59c919c51..a03e891114 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -327,7 +327,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), @@ -346,14 +346,20 @@ impl<'db> InferenceContext<'_, 'db> { 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, @@ -364,7 +370,7 @@ impl<'db> InferenceContext<'_, 'db> { coerce.coerce_forced_unit( self, tgt_expr, - &ObligationCause::new(), + &ObligationCause::new(tgt_expr), true, ExprIsRead::Yes, ); @@ -461,7 +467,7 @@ impl<'db> InferenceContext<'_, 'db> { 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. @@ -485,7 +491,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, @@ -536,10 +542,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, ); @@ -598,7 +605,7 @@ impl<'db> InferenceContext<'_, 'db> { 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 } => self.infer_await_expr(*expr), + 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 = @@ -751,7 +758,7 @@ 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() @@ -964,14 +971,14 @@ impl<'db> InferenceContext<'_, 'db> { ty } - fn infer_await_expr(&mut self, awaitee: ExprId) -> Ty<'db> { + 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()); + 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]) } @@ -1002,7 +1009,7 @@ impl<'db> InferenceContext<'_, 'db> { self.check_record_expr_fields(adt_ty, expected, expr, variant, fields, base_expr); - self.require_type_is_sized(adt_ty); + self.require_type_is_sized(adt_ty, expr.into()); adt_ty } @@ -1017,12 +1024,12 @@ impl<'db> InferenceContext<'_, 'db> { ) { let interner = self.interner(); - let adt_ty = self.table.try_structurally_resolve_type(adt_ty); + 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(), self.table.param_env, expected, adt_ty)?; + ocx.sup(&ObligationCause::new(expr), self.table.param_env, expected, adt_ty)?; if !ocx.try_evaluate_obligations().is_empty() { return Err(TypeError::Mismatch); } @@ -1084,7 +1091,7 @@ impl<'db> InferenceContext<'_, 'db> { // 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()); + 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. @@ -1131,7 +1138,7 @@ impl<'db> InferenceContext<'_, 'db> { if remaining_fields.remove(&field.name).is_some() { let target_ty = variant_field_tys[field_idx].get().instantiate(interner, args); - let cause = ObligationCause::new(); + let cause = ObligationCause::new(expr); match self.table.at(&cause).sup(target_ty, fru_ty) { Ok(InferOk { obligations, value: () }) => { self.table.register_predicates(obligations) @@ -1337,7 +1344,7 @@ impl<'db> InferenceContext<'_, 'db> { ) -> Ty<'db> { let elem_ty = match expected .to_option(&mut self.table) - .map(|t| self.table.try_structurally_resolve_type(t).kind()) + .map(|t| self.table.try_structurally_resolve_type(expr.into(), t).kind()) { Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st, _ => self.table.next_ty_var(expr.into()), @@ -1356,7 +1363,7 @@ impl<'db> InferenceContext<'_, 'db> { let cur_elem_ty = self.infer_expr_inner(expr, &expected, ExprIsRead::Yes); coerce.coerce( self, - &ObligationCause::new(), + &ObligationCause::new(expr), expr, cur_elem_ty, ExprIsRead::Yes, @@ -1402,7 +1409,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); } @@ -1416,7 +1429,7 @@ impl<'db> InferenceContext<'_, 'db> { coerce.coerce_forced_unit( self, ret, - &ObligationCause::new(), + &ObligationCause::new(ret), true, ExprIsRead::Yes, ); @@ -1600,11 +1613,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() { @@ -1692,7 +1706,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); @@ -1761,7 +1775,7 @@ impl<'db> InferenceContext<'_, 'db> { CallableDefId::StructId(it) => it.into(), CallableDefId::EnumVariantId(it) => it.loc(self.db).parent.into(), }; - self.add_required_obligations_for_value_path(def_id, args); + self.add_required_obligations_for_value_path(tgt_expr.into(), def_id, args); } self.check_call_arguments( @@ -1787,7 +1801,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, @@ -1809,15 +1823,15 @@ 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(tgt_expr.into(), receiver.into(), |ctx| { @@ -1961,13 +1975,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()), )); @@ -2088,7 +2102,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 diff --git a/crates/hir-ty/src/infer/op.rs b/crates/hir-ty/src/infer/op.rs index 753a6513f8..0127fd6cdb 100644 --- a/crates/hir-ty/src/infer/op.rs +++ b/crates/hir-ty/src/infer/op.rs @@ -194,6 +194,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // particularly for things like `String + &String`. let rhs_ty_var = self.table.next_ty_var(rhs_expr.into()); let result = self.lookup_op_method( + expr, lhs_ty, Some((rhs_expr, rhs_ty_var)), self.lang_item_for_bin_op(op), @@ -265,7 +266,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { operand_ty: Ty<'db>, op: UnaryOp, ) -> Ty<'db> { - match self.lookup_op_method(operand_ty, None, self.lang_item_for_unop(op)) { + match self.lookup_op_method(ex, operand_ty, None, self.lang_item_for_unop(op)) { Ok(method) => { self.write_method_resolution(ex, method.def_id, method.args); method.sig.output() @@ -279,6 +280,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { fn lookup_op_method( &mut self, + expr: ExprId, lhs_ty: Ty<'db>, opt_rhs: Option<(ExprId, Ty<'db>)>, (opname, trait_did): (Symbol, Option<TraitId>), @@ -294,7 +296,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { ); let opt_rhs_ty = opt_rhs.map(|it| it.1); - let cause = ObligationCause::new(); + let cause = ObligationCause::new(expr); // We don't consider any other candidates if this lookup fails // so we can freely treat opaque types as inference variables here diff --git a/crates/hir-ty/src/infer/opaques.rs b/crates/hir-ty/src/infer/opaques.rs index 02bce22d6d..178b3fcbf5 100644 --- a/crates/hir-ty/src/infer/opaques.rs +++ b/crates/hir-ty/src/infer/opaques.rs @@ -4,6 +4,7 @@ use rustc_type_ir::{TypeVisitableExt, fold_regions}; use tracing::{debug, instrument}; use crate::{ + Span, infer::InferenceContext, next_solver::{ EarlyBinder, OpaqueTypeKey, SolverDefId, TypingMode, @@ -135,7 +136,8 @@ impl<'db> InferenceContext<'_, 'db> { return UsageKind::UnconstrainedHiddenType(hidden_type); } - let cause = ObligationCause::new(); + // FIXME: This should not use a dummy span. + let cause = ObligationCause::new(Span::Dummy); let at = self.table.infer_ctxt.at(&cause, self.table.param_env); let hidden_type = match at.deeply_normalize(hidden_type) { Ok(hidden_type) => hidden_type, diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index a7b82dad4f..97165b9f07 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -309,7 +309,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { Pat::TupleStruct { path, .. } => Some(self.resolve_tuple_struct_pat(pat_id, path)), _ => None, }; - let adjust_mode = self.calc_adjust_mode(pat, opt_path_res); + let adjust_mode = self.calc_adjust_mode(pat_id, pat, opt_path_res); let ty = self.infer_pat_inner(pat_id, opt_path_res, adjust_mode, expected, pat_info); let ty = self.insert_type_vars_shallow(ty); self.write_pat_ty(pat_id, ty); @@ -321,6 +321,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { { let infer_ok = self.register_deref_mut_bounds_if_needed( pat_id, + pat_id, derefed_tys.iter().filter_map(|adjust| match adjust.kind { PatAdjust::OverloadedDeref => Some(adjust.source.as_ref()), PatAdjust::BuiltinDeref => None, @@ -393,7 +394,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { let expected = if let AdjustMode::Peel { .. } = adjust_mode && pat_info.pat_origin.default_binding_modes() { - self.table.try_structurally_resolve_type(expected) + self.table.try_structurally_resolve_type(pat.into(), expected) } else { expected }; @@ -432,7 +433,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // The scrutinee is a smart pointer; implicitly dereference it. This adds a // requirement that `expected: DerefPure`. - let inner_ty = self.deref_pat_target(expected); + let inner_ty = self.deref_pat_target(pat, expected); // Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any // `ref mut` bindings. See `Self::register_deref_mut_bounds_if_needed`. @@ -604,6 +605,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { /// When the pattern contains a path, `opt_path_res` must be `Some(path_res)`. fn calc_adjust_mode( &mut self, + pat_id: PatId, pat: &Pat, opt_path_res: Option<Result<ResolvedPat<'db>, ()>>, ) -> AdjustMode { @@ -640,7 +642,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { let mut peeled_ty = lit_ty; let mut pat_ref_layers = 0; while let TyKind::Ref(_, inner_ty, mutbl) = - self.table.try_structurally_resolve_type(peeled_ty).kind() + self.table.try_structurally_resolve_type(pat_id.into(), peeled_ty).kind() { // We rely on references at the head of constants being immutable. debug_assert!(mutbl.is_not()); @@ -763,7 +765,10 @@ impl<'a, 'db> InferenceContext<'a, 'db> { match expected.kind() { // Allow `b"...": &[u8]` TyKind::Ref(_, inner_ty, _) - if self.table.try_structurally_resolve_type(inner_ty).is_slice() => + if self + .table + .try_structurally_resolve_type(expr.into(), inner_ty) + .is_slice() => { trace!(?expr, "polymorphic byte string lit"); pat_ty = self.types.types.static_u8_slice; @@ -788,7 +793,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // string literal patterns to have type `str`. This is accounted for when lowering to MIR. if self.features.deref_patterns && matches!(literal, Literal::String(_)) - && self.table.try_structurally_resolve_type(expected).is_str() + && self.table.try_structurally_resolve_type(expr.into(), expected).is_str() { pat_ty = self.types.types.str; } @@ -825,7 +830,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // be peeled to `str` while ty here is still `&str`, if we don't // err early here, a rather confusing unification error will be // emitted instead). - let ty = self.table.try_structurally_resolve_type(ty); + let ty = self.table.try_structurally_resolve_type(expr.into(), ty); let fail = !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error()); Some((fail, ty, expr)) @@ -1118,7 +1123,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; let pat_ty = Ty::new(interner, TyKind::Tuple(element_tys)); if self.demand_eqtype(pat.into(), expected, pat_ty).is_err() { let expected = if let TyKind::Tuple(tys) = - self.table.try_structurally_resolve_type(expected).kind() + self.table.try_structurally_resolve_type(Span::Dummy, expected).kind() { for (expected_var, found) in iter::zip(element_tys, tys) { // Constrain the infer var so that the type mismatch error message, which contains it, @@ -1265,15 +1270,21 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; box_ty } - fn _infer_deref_pat(&mut self, inner: PatId, expected: Ty<'db>, pat_info: PatInfo) -> Ty<'db> { - let target_ty = self.deref_pat_target(expected); + fn _infer_deref_pat( + &mut self, + pat: PatId, + inner: PatId, + expected: Ty<'db>, + pat_info: PatInfo, + ) -> Ty<'db> { + let target_ty = self.deref_pat_target(pat, expected); self.infer_pat(inner, target_ty, pat_info); - let infer_ok = self.register_deref_mut_bounds_if_needed(inner, [expected]); + let infer_ok = self.register_deref_mut_bounds_if_needed(pat, inner, [expected]); self.table.register_infer_ok(infer_ok); expected } - fn deref_pat_target(&mut self, source_ty: Ty<'db>) -> Ty<'db> { + fn deref_pat_target(&mut self, pat: PatId, source_ty: Ty<'db>) -> Ty<'db> { let (Some(deref_pure), Some(deref_target)) = (self.lang_items.DerefPure, self.lang_items.DerefTarget) else { @@ -1281,10 +1292,10 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; }; // Register a `DerefPure` bound, which is required by all `deref!()` pats. let interner = self.interner(); - self.table.register_bound(source_ty, deref_pure, ObligationCause::new()); + self.table.register_bound(source_ty, deref_pure, ObligationCause::new(pat)); // The expected type for the deref pat's inner pattern is `<expected as Deref>::Target`. let target_ty = Ty::new_projection(interner, deref_target.into(), [source_ty]); - self.table.try_structurally_resolve_type(target_ty) + self.table.try_structurally_resolve_type(pat.into(), target_ty) } /// Check if the interior of a deref pattern (either explicit or implicit) has any `ref mut` @@ -1293,6 +1304,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; /// account for `ref mut` binding modes inherited from implicitly dereferencing `&mut` refs. fn register_deref_mut_bounds_if_needed( &self, + pat: PatId, inner: PatId, derefed_tys: impl IntoIterator<Item = Ty<'db>>, ) -> InferOk<'db, ()> { @@ -1303,7 +1315,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; for mutably_derefed_ty in derefed_tys { infer_ok.obligations.push(Obligation::new( interner, - ObligationCause::new(), + ObligationCause::new(pat), self.table.param_env, TraitRef::new(interner, deref_mut.into(), [mutably_derefed_ty]), )); @@ -1350,7 +1362,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(); } - expected = self.table.try_structurally_resolve_type(expected); + expected = self.table.try_structurally_resolve_type(pat.into(), expected); // Determine whether we're consuming an inherited reference and resetting the default // binding mode, based on edition and enabled experimental features. if let ByRef::Yes(inh_mut) = pat_info.binding_mode { @@ -1574,7 +1586,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; expected: Ty<'db>, pat_info: PatInfo, ) -> Ty<'db> { - let expected = self.table.try_structurally_resolve_type(expected); + let expected = self.table.try_structurally_resolve_type(pat.into(), expected); // If the pattern is irrefutable and `expected` is an infer ty, we try to equate it // to an array if the given pattern allows it. See issue #76342 diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index c020c9812b..4df38e96ee 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -40,7 +40,7 @@ impl<'db> InferenceContext<'_, 'db> { }; let args = self.insert_type_vars(substs, id.into()); - self.add_required_obligations_for_value_path(generic_def, args); + self.add_required_obligations_for_value_path(id, generic_def, args); let ty = self.db.value_ty(value_def)?.instantiate(self.interner(), args); let ty = self.process_remote_user_written_ty(ty); @@ -226,6 +226,7 @@ impl<'db> InferenceContext<'_, 'db> { pub(super) fn add_required_obligations_for_value_path( &mut self, + node: ExprOrPatId, def: GenericDefId, subst: GenericArgs<'db>, ) { @@ -234,7 +235,7 @@ impl<'db> InferenceContext<'_, 'db> { let param_env = self.table.param_env; self.table.register_predicates(clauses_as_obligations( predicates.iter_instantiated(interner, subst.as_slice()), - ObligationCause::new(), + ObligationCause::new(node), param_env, )); } @@ -348,7 +349,7 @@ impl<'db> InferenceContext<'_, 'db> { name: &Name, id: ExprOrPatId, ) -> Option<(ValueNs, GenericArgs<'db>)> { - let ty = self.table.try_structurally_resolve_type(ty); + let ty = self.table.try_structurally_resolve_type(id.into(), ty); let (enum_id, subst) = match ty.as_adt() { Some((AdtId::EnumId(e), subst)) => (e, subst), _ => return None, diff --git a/crates/hir-ty/src/infer/place_op.rs b/crates/hir-ty/src/infer/place_op.rs index 63841af682..968d793615 100644 --- a/crates/hir-ty/src/infer/place_op.rs +++ b/crates/hir-ty/src/infer/place_op.rs @@ -90,7 +90,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // autoderef that normal method probing does. They could likely be // consolidated. - let mut autoderef = InferenceContextAutoderef::new_from_inference_context(self, base_ty); + let mut autoderef = + InferenceContextAutoderef::new_from_inference_context(self, base_ty, base_expr.into()); let mut result = None; while result.is_none() && autoderef.next().is_some() { result = Self::try_index_step(expr, base_expr, index_expr, &mut autoderef, idx_ty); @@ -126,7 +127,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { let ctx = autoderef.ctx(); ctx.table.register_predicate(Obligation::new( ctx.interner(), - ObligationCause::new(), + ObligationCause::new(base_expr), ctx.table.param_env, ClauseKind::ConstArgHasType(ct, ctx.types.types.usize), )); @@ -206,7 +207,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // opaque types as rigid here to support `impl Deref<Target = impl Index<usize>>`. let treat_opaques = TreatNotYetDefinedOpaques::AsInfer; self.table.lookup_method_for_operator( - ObligationCause::with_span(expr.into()), + ObligationCause::new(expr), imm_op, imm_tr, base_ty, @@ -239,7 +240,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // of the opaque. let treat_opaques = TreatNotYetDefinedOpaques::AsInfer; table.lookup_method_for_operator( - ObligationCause::with_span(expr.into()), + ObligationCause::new(expr), mut_op, mut_tr, base_ty, diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index ab5a7c3fc7..c089335708 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -320,11 +320,11 @@ impl<'db> InferenceTable<'db> { /// In case there is still ambiguity, the returned type may be an inference /// variable. This is different from `structurally_resolve_type` which errors /// in this case. - pub(crate) fn try_structurally_resolve_type(&mut self, ty: Ty<'db>) -> Ty<'db> { + pub(crate) fn try_structurally_resolve_type(&mut self, span: Span, ty: Ty<'db>) -> Ty<'db> { if let TyKind::Alias(..) = ty.kind() { let result = self .infer_ctxt - .at(&ObligationCause::misc(), self.param_env) + .at(&ObligationCause::new(span), self.param_env) .structurally_normalize_ty(ty, &mut self.fulfillment_cx); match result { Ok(normalized_ty) => normalized_ty, @@ -396,22 +396,18 @@ impl<'db> InferenceTable<'db> { /// checking later, during regionck, that `arg` is well-formed. pub(crate) fn register_wf_obligation(&mut self, term: Term<'db>, cause: ObligationCause) { - let _ = (term, cause); - // FIXME: We don't currently register an obligation here because we don't implement - // wf checking anyway and this function is currently often passed dummy spans, which could - // prevent reporting "type annotation needed" errors. - // self.register_predicate(Obligation::new( - // self.interner(), - // cause, - // self.param_env, - // ClauseKind::WellFormed(term), - // )); + self.register_predicate(Obligation::new( + self.interner(), + cause, + self.param_env, + ClauseKind::WellFormed(term), + )); } /// Registers obligations that all `args` are well-formed. - pub(crate) fn add_wf_bounds(&mut self, args: GenericArgs<'db>) { + pub(crate) fn add_wf_bounds(&mut self, span: Span, args: GenericArgs<'db>) { for term in args.iter().filter_map(|it| it.as_term()) { - self.register_wf_obligation(term, ObligationCause::new()); + self.register_wf_obligation(term, ObligationCause::new(span)); } } @@ -425,7 +421,7 @@ impl<'db> InferenceTable<'db> { /// Whenever you lower a user-written type, you should call this. pub(crate) fn process_user_written_ty(&mut self, span: Span, ty: Ty<'db>) -> Ty<'db> { let ty = self.insert_type_vars(ty, span); - self.try_structurally_resolve_type(ty) + self.try_structurally_resolve_type(span, ty) } /// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation, @@ -435,8 +431,7 @@ impl<'db> InferenceTable<'db> { // See https://github.com/rust-lang/rust/blob/cdb45c87e2cd43495379f7e867e3cc15dcee9f93/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs#L487-L495: // Even though the new solver only lazily normalizes usually, here we eagerly normalize so that not everything needs // to normalize before inspecting the `TyKind`. - // FIXME(next-solver): We should not deeply normalize here, only shallowly. - self.try_structurally_resolve_type(ty) + self.try_structurally_resolve_type(Span::Dummy, ty) } } @@ -700,7 +695,8 @@ pub(super) mod resolve_completely { T: Into<Term<'db>> + TypeSuperFoldable<DbInterner<'db>> + Copy, { let value = if self.should_normalize { - let cause = ObligationCause::new(); + // FIXME: This should not use a dummy span. + let cause = ObligationCause::new(Span::Dummy); let at = self.ctx.table.at(&cause); let universes = vec![None; outer_exclusive_binder(value).as_usize()]; match deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index c77c1b98d3..c6075b03da 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -63,7 +63,7 @@ use std::{hash::Hash, ops::ControlFlow}; use hir_def::{ CallableDefId, ExpressionStoreOwnerId, GenericDefId, LifetimeParamId, TypeAliasId, TypeOrConstParamId, TypeParamId, - hir::{ExprId, ExprOrPatId, PatId}, + hir::{BindingId, ExprId, ExprOrPatId, PatId}, resolver::TypeNs, type_ref::{Rawness, TypeRefId}, }; @@ -678,11 +678,12 @@ pub fn known_const_to_ast<'db>( pub enum Span { ExprId(ExprId), PatId(PatId), + BindingId(BindingId), TypeRefId(TypeRefId), /// An unimportant location. Errors on this will be suppressed. Dummy, } -impl_from!(ExprId, PatId, TypeRefId for Span); +impl_from!(ExprId, PatId, BindingId, TypeRefId for Span); impl From<ExprOrPatId> for Span { fn from(value: ExprOrPatId) -> Self { diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 1f2ede3324..86477f2c0b 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -316,7 +316,7 @@ impl<'db> InferenceTable<'db> { let bounds = GenericPredicates::query_all(self.db, method_item.into()); let bounds = clauses_as_obligations( bounds.iter_instantiated(interner, args.as_slice()), - ObligationCause::new(), + cause, self.param_env, ); diff --git a/crates/hir-ty/src/method_resolution/confirm.rs b/crates/hir-ty/src/method_resolution/confirm.rs index a29e3db18d..6601ff7a01 100644 --- a/crates/hir-ty/src/method_resolution/confirm.rs +++ b/crates/hir-ty/src/method_resolution/confirm.rs @@ -39,7 +39,7 @@ use crate::{ struct ConfirmContext<'a, 'b, 'db> { ctx: &'a mut InferenceContext<'b, 'db>, candidate: FunctionId, - expr: ExprId, + call_expr: ExprId, } #[derive(Debug)] @@ -74,9 +74,9 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { fn new( ctx: &'a mut InferenceContext<'b, 'db>, candidate: FunctionId, - expr: ExprId, + call_expr: ExprId, ) -> ConfirmContext<'a, 'b, 'db> { - ConfirmContext { ctx, candidate, expr } + ConfirmContext { ctx, candidate, call_expr } } #[inline] @@ -181,7 +181,8 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { ) -> (Ty<'db>, Box<[Adjustment]>) { // Commit the autoderefs by calling `autoderef` again, but this // time writing the results into the various typeck results. - let mut autoderef = self.ctx.table.autoderef_with_tracking(unadjusted_self_ty); + let mut autoderef = + self.ctx.table.autoderef_with_tracking(unadjusted_self_ty, self.call_expr.into()); let Some((mut target, n)) = autoderef.nth(pick.autoderefs) else { return (Ty::new_error(self.interner(), ErrorGuaranteed), Box::new([])); }; @@ -191,7 +192,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { self.ctx.table.register_infer_ok(autoderef.adjust_steps_as_infer_ok()); match pick.autoref_or_ptr_adjustment { Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => { - let region = self.infcx().next_region_var(self.expr.into()); + let region = self.infcx().next_region_var(self.call_expr.into()); // Type we're wrapping in a reference, used later for unsizing let base_ty = target; @@ -255,7 +256,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { ) -> GenericArgs<'db> { match pick.kind { probe::InherentImplPick(impl_def_id) => { - self.infcx().fresh_args_for_item(self.expr.into(), impl_def_id.into()) + self.infcx().fresh_args_for_item(self.call_expr.into(), impl_def_id.into()) } probe::ObjectPick(trait_def_id) => { @@ -297,7 +298,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { // the process we will unify the transformed-self-type // of the method with the actual type in order to // unify some of these variables. - self.infcx().fresh_args_for_item(self.expr.into(), trait_def_id.into()) + self.infcx().fresh_args_for_item(self.call_expr.into(), trait_def_id.into()) } probe::WhereClausePick(poly_trait_ref) => { @@ -317,7 +318,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { // yield an object-type (e.g., `&Object` or `Box<Object>` // etc). - let mut autoderef = self.ctx.table.autoderef(self_ty); + let mut autoderef = self.ctx.table.autoderef(self_ty, self.call_expr.into()); // We don't need to gate this behind arbitrary self types // per se, but it does make things a bit more gated. @@ -466,7 +467,11 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { LifetimeElisionKind::Infer, false, None, - &mut LowererCtx { ctx: self.ctx, expr: self.expr, parent_args: parent_args.as_slice() }, + &mut LowererCtx { + ctx: self.ctx, + expr: self.call_expr, + parent_args: parent_args.as_slice(), + }, ) } @@ -480,7 +485,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { "unify_receivers: self_ty={:?} method_self_ty={:?} pick={:?}", self_ty, method_self_ty, pick ); - let cause = ObligationCause::new(); + let cause = ObligationCause::new(self.call_expr); match self.ctx.table.at(&cause).sup(method_self_ty, self_ty) { Ok(infer_ok) => { self.ctx.table.register_infer_ok(infer_ok); @@ -488,7 +493,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { Err(_) => { if self.ctx.features.arbitrary_self_types { self.ctx.result.type_mismatches.get_or_insert_default().insert( - self.expr.into(), + self.call_expr.into(), TypeMismatch { expected: method_self_ty.store(), actual: self_ty.store() }, ); } @@ -513,7 +518,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { let method_predicates = clauses_as_obligations( GenericPredicates::query_all(self.db(), def_id.into()) .iter_instantiated(self.interner(), all_args), - ObligationCause::new(), + ObligationCause::new(self.call_expr), self.ctx.table.param_env, ); @@ -539,13 +544,13 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { // this is a projection from a trait reference, so we have to // make sure that the trait reference inputs are well-formed. - self.ctx.table.add_wf_bounds(all_args); + self.ctx.table.add_wf_bounds(self.call_expr.into(), all_args); // the function type must also be well-formed (this is not // implied by the args being well-formed because of inherent // impls and late-bound regions - see issue #28609). for ty in sig.inputs_and_output { - self.ctx.table.register_wf_obligation(ty.into(), ObligationCause::new()); + self.ctx.table.register_wf_obligation(ty.into(), ObligationCause::new(self.call_expr)); } } @@ -614,7 +619,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { T: TypeFoldable<DbInterner<'db>> + Copy, { self.infcx().instantiate_binder_with_fresh_vars( - self.expr.into(), + self.call_expr.into(), BoundRegionConversionTime::FnCall, value, ) diff --git a/crates/hir-ty/src/method_resolution/probe.rs b/crates/hir-ty/src/method_resolution/probe.rs index 2e4ca139c0..34cd941e91 100644 --- a/crates/hir-ty/src/method_resolution/probe.rs +++ b/crates/hir-ty/src/method_resolution/probe.rs @@ -339,7 +339,7 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> { let ty = self .infcx .instantiate_query_response_and_region_obligations( - &ObligationCause::new(), + &ObligationCause::new(self.receiver_span), self.param_env, &orig_values, ty, @@ -403,7 +403,8 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> { // converted to, in order to find out which of those methods might actually // be callable. let mut autoderef_via_deref = - Autoderef::new(infcx, self.param_env, self_ty).include_raw_pointers(); + Autoderef::new(infcx, self.param_env, self_ty, self.receiver_span) + .include_raw_pointers(); let mut reached_raw_pointer = false; let arbitrary_self_types_enabled = @@ -412,9 +413,10 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> { let reachable_via_deref = autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false)); - let mut autoderef_via_receiver = Autoderef::new(infcx, self.param_env, self_ty) - .include_raw_pointers() - .use_receiver_trait(); + let mut autoderef_via_receiver = + Autoderef::new(infcx, self.param_env, self_ty, self.receiver_span) + .include_raw_pointers() + .use_receiver_trait(); let steps = autoderef_via_receiver .by_ref() .zip(reachable_via_deref) @@ -1270,7 +1272,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { let InferOk { value: self_ty, obligations: instantiate_self_ty_obligations } = self .infcx() .instantiate_query_response_and_region_obligations( - &ObligationCause::new(), + &ObligationCause::new(self.ctx.receiver_span), self.param_env(), self.orig_steps_var_values, &step.self_ty, @@ -1497,8 +1499,12 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { &self, trait_ref: TraitRef<'db>, ) -> SelectionResult<'db, Selection<'db>> { - let obligation = - Obligation::new(self.interner(), ObligationCause::new(), self.param_env(), trait_ref); + let obligation = Obligation::new( + self.interner(), + ObligationCause::new(self.ctx.call_span), + self.param_env(), + trait_ref, + ); self.infcx().select(&obligation) } @@ -1525,7 +1531,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { // up with the `self` parameter of the method. let _ = self .infcx() - .at(&ObligationCause::dummy(), self.param_env()) + .at(&ObligationCause::new(self.ctx.call_span), self.param_env()) .sup(xform_self_ty, self_ty); match self.select_trait_candidate(trait_ref) { Ok(Some(ImplSource::UserDefined(ref impl_data))) => { @@ -1556,7 +1562,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { ) -> ProbeResult { self.infcx().probe(|_| { let mut result = ProbeResult::Match; - let cause = &ObligationCause::new(); + let cause = &ObligationCause::new(self.ctx.call_span); let mut ocx = ObligationCtxt::new(self.infcx()); // Subtle: we're not *really* instantiating the current self type while @@ -1600,7 +1606,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { let impl_bounds = GenericPredicates::query_all(self.db(), impl_def_id.into()); let impl_bounds = clauses_as_obligations( impl_bounds.iter_instantiated(self.interner(), impl_args.as_slice()), - ObligationCause::new(), + ObligationCause::new(self.ctx.call_span), self.param_env(), ); // Convert the bounds into obligations. @@ -1805,7 +1811,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { // reachable. In this case we don't care about opaque // types there. let Ok(ok) = self.infcx().instantiate_query_response_and_region_obligations( - &ObligationCause::new(), + &ObligationCause::new(self.ctx.receiver_span), self.param_env(), self.orig_steps_var_values, &step.self_ty, diff --git a/crates/hir-ty/src/next_solver/infer/traits.rs b/crates/hir-ty/src/next_solver/infer/traits.rs index 523c94b36f..12a6652bf7 100644 --- a/crates/hir-ty/src/next_solver/infer/traits.rs +++ b/crates/hir-ty/src/next_solver/infer/traits.rs @@ -27,13 +27,6 @@ use crate::{ use super::InferCtxt; /// The reason why we incurred this obligation; used for error reporting. -/// -/// Non-misc `ObligationCauseCode`s are stored on the heap. This gives the -/// best trade-off between keeping the type small (which makes copies cheaper) -/// while not doing too many heap allocations. -/// -/// We do not want to intern this as there are a lot of obligation causes which -/// only live for a short period of time. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ObligationCause { span: Span, @@ -41,23 +34,13 @@ pub struct ObligationCause { impl ObligationCause { #[inline] - pub fn new() -> ObligationCause { - ObligationCause { span: Span::Dummy } - } - - #[inline] - pub fn with_span(span: Span) -> ObligationCause { - ObligationCause { span } + pub fn new<S: Into<Span>>(span: S) -> ObligationCause { + ObligationCause { span: span.into() } } #[inline] pub fn dummy() -> ObligationCause { - ObligationCause::new() - } - - #[inline] - pub fn misc() -> ObligationCause { - ObligationCause::new() + ObligationCause::new(Span::Dummy) } #[inline] @@ -66,13 +49,6 @@ impl ObligationCause { } } -impl Default for ObligationCause { - #[inline] - fn default() -> Self { - Self::new() - } -} - /// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for /// which the "impl_source" must be found. The process of finding an "impl_source" is /// called "resolving" the `Obligation`. This process consists of @@ -128,11 +104,11 @@ impl<'db> Elaboratable<DbInterner<'db>> for PredicateObligation<'db> { fn child_with_derived_cause( &self, clause: Clause<'db>, - _span: Span, + span: Span, _parent_trait_pred: PolyTraitPredicate<'db>, _index: usize, ) -> Self { - let cause = ObligationCause::new(); + let cause = ObligationCause::new(span); Obligation { cause, param_env: self.param_env, diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 3259abb536..6a0996fae6 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -851,6 +851,10 @@ impl<'db> AnyDiagnostic<'db> { hir_ty::Span::ExprId(idx) => expr_syntax(idx)?.map(|it| it.wrap_right()), hir_ty::Span::PatId(idx) => pat_syntax(idx)?.map(|it| it.wrap_right()), hir_ty::Span::TypeRefId(idx) => type_syntax(idx)?.map(|it| it.wrap_left()), + hir_ty::Span::BindingId(idx) => { + pat_syntax(source_map.patterns_for_binding(idx)[0])? + .map(|it| it.wrap_right()) + } hir_ty::Span::Dummy => unreachable!( "should never create TypeMustBeKnown diagnostic for dummy spans" ), diff --git a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs index 179f9dcec5..f6293e35d0 100644 --- a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs +++ b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs @@ -205,6 +205,7 @@ trait Foo { fn method(&self, _arg: usize) {} } fn f() { let x; + // ^ error: type annotations needed x.method(); } "#, |