Unnamed repository; edit this file 'description' to name the repository.
Ensure we give spans for obligations everywhere
Chayim Refael Friedman 2 weeks ago
parent 5f6ad1e · commit 3d91761
-rw-r--r--crates/hir-ty/src/autoderef.rs24
-rw-r--r--crates/hir-ty/src/display.rs4
-rw-r--r--crates/hir-ty/src/infer.rs35
-rw-r--r--crates/hir-ty/src/infer/autoderef.rs14
-rw-r--r--crates/hir-ty/src/infer/callee.rs25
-rw-r--r--crates/hir-ty/src/infer/cast.rs31
-rw-r--r--crates/hir-ty/src/infer/closure.rs71
-rw-r--r--crates/hir-ty/src/infer/closure/analysis.rs16
-rw-r--r--crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs69
-rw-r--r--crates/hir-ty/src/infer/coerce.rs23
-rw-r--r--crates/hir-ty/src/infer/expr.rs88
-rw-r--r--crates/hir-ty/src/infer/op.rs6
-rw-r--r--crates/hir-ty/src/infer/opaques.rs4
-rw-r--r--crates/hir-ty/src/infer/pat.rs46
-rw-r--r--crates/hir-ty/src/infer/path.rs7
-rw-r--r--crates/hir-ty/src/infer/place_op.rs9
-rw-r--r--crates/hir-ty/src/infer/unify.rs32
-rw-r--r--crates/hir-ty/src/lib.rs5
-rw-r--r--crates/hir-ty/src/method_resolution.rs2
-rw-r--r--crates/hir-ty/src/method_resolution/confirm.rs35
-rw-r--r--crates/hir-ty/src/method_resolution/probe.rs30
-rw-r--r--crates/hir-ty/src/next_solver/infer/traits.rs34
-rw-r--r--crates/hir/src/diagnostics.rs4
-rw-r--r--crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs1
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();
}
"#,