summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/infer
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
commit218caa410aa38c29984be31a5229b9fa717560ee (patch)
treec54bd55eeb6e4c508940a30e94c0032fbd45d677 /compiler/rustc_infer/src/infer
parentReleasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz
rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--compiler/rustc_infer/src/infer/at.rs18
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs20
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs15
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs6
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs15
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs185
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs113
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs43
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs323
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs14
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs400
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs76
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs195
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_region.rs427
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs85
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs5
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs5
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs14
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs55
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs5
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs111
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs48
-rw-r--r--compiler/rustc_infer/src/infer/note.rs203
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs58
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/table.rs5
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs32
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs8
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs124
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs73
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs4
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs10
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs18
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs4
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs15
-rw-r--r--compiler/rustc_infer/src/infer/type_variable.rs2
-rw-r--r--compiler/rustc_infer/src/infer/undo_log.rs8
38 files changed, 1062 insertions, 1686 deletions
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 4429e4f43..d816a9ed3 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -411,7 +411,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
}
}
-impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> {
+impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
fn to_trace(
tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
@@ -419,11 +419,23 @@ impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> {
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
- let a_ty = tcx.mk_projection(a.item_def_id, a.substs);
- let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
+ let a_ty = tcx.mk_projection(a.def_id, a.substs);
+ let b_ty = tcx.mk_projection(b.def_id, b.substs);
TypeTrace {
cause: cause.clone(),
values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())),
}
}
}
+
+impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
+ fn to_trace(
+ _: TyCtxt<'tcx>,
+ cause: &ObligationCause<'tcx>,
+ a_is_expected: bool,
+ a: Self,
+ b: Self,
+ ) -> TypeTrace<'tcx> {
+ TypeTrace { cause: cause.clone(), values: Sigs(ExpectedFound::new(a_is_expected, a, b)) }
+ }
+}
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 3dc0d60b1..091635e6c 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -6,8 +6,7 @@
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
use crate::infer::canonical::{
- Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Canonicalized,
- OriginalQueryValues,
+ Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
};
use crate::infer::InferCtxt;
use rustc_middle::ty::flags::FlagComputation;
@@ -40,7 +39,7 @@ impl<'tcx> InferCtxt<'tcx> {
&self,
value: V,
query_state: &mut OriginalQueryValues<'tcx>,
- ) -> Canonicalized<'tcx, V>
+ ) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
@@ -59,7 +58,7 @@ impl<'tcx> InferCtxt<'tcx> {
&self,
value: V,
query_state: &mut OriginalQueryValues<'tcx>,
- ) -> Canonicalized<'tcx, V>
+ ) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
@@ -99,7 +98,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// out the [chapter in the rustc dev guide][c].
///
/// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result
- pub fn canonicalize_response<V>(&self, value: V) -> Canonicalized<'tcx, V>
+ pub fn canonicalize_response<V>(&self, value: V) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
@@ -113,7 +112,7 @@ impl<'tcx> InferCtxt<'tcx> {
)
}
- pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonicalized<'tcx, V>
+ pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
@@ -135,7 +134,7 @@ impl<'tcx> InferCtxt<'tcx> {
&self,
value: V,
query_state: &mut OriginalQueryValues<'tcx>,
- ) -> Canonicalized<'tcx, V>
+ ) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
@@ -453,10 +452,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
| ty::Dynamic(..)
| ty::Never
| ty::Tuple(..)
- | ty::Projection(..)
+ | ty::Alias(..)
| ty::Foreign(..)
- | ty::Param(..)
- | ty::Opaque(..) => {
+ | ty::Param(..) => {
if t.flags().intersects(self.needs_canonical_flags) {
t.super_fold_with(self)
} else {
@@ -525,7 +523,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
tcx: TyCtxt<'tcx>,
canonicalize_region_mode: &dyn CanonicalizeMode,
query_state: &mut OriginalQueryValues<'tcx>,
- ) -> Canonicalized<'tcx, V>
+ ) -> Canonical<'tcx, V>
where
V: TypeFoldable<'tcx>,
{
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 996b1c40e..3d49182f0 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -9,7 +9,7 @@
use crate::infer::canonical::substitute::{substitute_value, CanonicalExt};
use crate::infer::canonical::{
- Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues,
+ Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
};
use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
@@ -57,7 +57,7 @@ impl<'tcx> InferCtxt<'tcx> {
inference_vars: CanonicalVarValues<'tcx>,
answer: T,
fulfill_cx: &mut dyn TraitEngine<'tcx>,
- ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>>
+ ) -> Fallible<CanonicalQueryResponse<'tcx, T>>
where
T: Debug + TypeFoldable<'tcx>,
Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
@@ -151,11 +151,12 @@ impl<'tcx> InferCtxt<'tcx> {
})
}
- fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
- self.inner
- .borrow_mut()
- .opaque_type_storage
- .take_opaque_types()
+ /// FIXME: This method should only be used for canonical queries and therefore be private.
+ ///
+ /// As the new solver does canonicalization slightly differently, this is also used there
+ /// for now. This should hopefully change fairly soon.
+ pub fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
+ std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
.into_iter()
.map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty))
.collect()
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index cf895ed0d..72676b718 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -219,7 +219,7 @@ impl<'tcx> InferCtxt<'tcx> {
///
/// As `3 + 4` contains `N` in its substs, this must not succeed.
///
- /// See `src/test/ui/const-generics/occurs-check/` for more examples where this is relevant.
+ /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
#[instrument(level = "debug", skip(self))]
fn unify_const_variable(
&self,
@@ -331,7 +331,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown());
// Generalize type of `a_ty` appropriately depending on the
- // direction. As an example, assume:
+ // direction. As an example, assume:
//
// - `a_ty == &'x ?1`, where `'x` is some free region and `?1` is an
// inference variable,
@@ -675,7 +675,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
// relatable.
Ok(t)
}
- ty::Opaque(def_id, substs) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
let s = self.relate(substs, substs)?;
Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) })
}
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 8682f4d3b..46e7813d9 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -100,11 +100,15 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
}
- (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+ ) if a_def_id == b_def_id => {
self.fields.infcx.super_combine_tys(self, a, b)?;
}
- (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
- if self.fields.define_opaque_types && did.is_local() =>
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+ if self.fields.define_opaque_types && def_id.is_local() =>
{
self.fields.obligations.extend(
infcx
@@ -178,6 +182,11 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
where
T: Relate<'tcx>,
{
+ // A binder is equal to itself if it's structually equal to itself
+ if a == b {
+ return Ok(a);
+ }
+
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
self.fields.higher_ranked_sub(b, a, self.a_is_expected)?;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 987559d7e..28fd03b87 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1,4 +1,3 @@
-// ignore-tidy-filelength
//! Error Reporting Code for the inference engine
//!
//! Because of the way inference, and in particular region inference,
@@ -56,6 +55,7 @@ use crate::infer::ExpectedFound;
use crate::traits::error_reporting::report_object_safety_error;
use crate::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
+ PredicateObligation,
};
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -92,8 +92,12 @@ pub mod nice_region_error;
pub struct TypeErrCtxt<'a, 'tcx> {
pub infcx: &'a InferCtxt<'tcx>,
pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
- pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
pub fallback_has_occurred: bool,
+
+ pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
+
+ pub autoderef_steps:
+ Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
}
impl TypeErrCtxt<'_, '_> {
@@ -184,7 +188,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
let text = if br.has_name() {
format!("the lifetime `{}` as defined here", br.name)
} else {
- format!("the anonymous lifetime as defined here")
+ "the anonymous lifetime as defined here".to_string()
};
(text, sp)
}
@@ -203,7 +207,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
sp = param.span;
}
let text = if name == kw::UnderscoreLifetime {
- format!("the anonymous lifetime as defined here")
+ "the anonymous lifetime as defined here".to_string()
} else {
format!("the lifetime `{}` as defined here", name)
};
@@ -303,6 +307,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
None,
format!("captures `{}`", hidden_region),
None,
+ Some(reg_info.def_id),
)
}
}
@@ -310,7 +315,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
// Ugh. This is a painful case: the hidden region is not one
// that we can easily summarize or explain. This can happen
// in a case like
- // `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`:
+ // `tests/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`:
//
// ```
// fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> {
@@ -339,11 +344,13 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
impl<'tcx> InferCtxt<'tcx> {
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
let (def_id, substs) = match *ty.kind() {
- ty::Opaque(def_id, substs) => (def_id, substs),
- ty::Projection(data)
- if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ if matches!(
+ self.tcx.def_kind(def_id),
+ DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
+ ) =>
{
- (data.item_def_id, data.substs)
+ (def_id, substs)
}
_ => return None,
};
@@ -357,7 +364,7 @@ impl<'tcx> InferCtxt<'tcx> {
.kind()
.map_bound(|kind| match kind {
ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate))
- if projection_predicate.projection_ty.item_def_id == item_def_id =>
+ if projection_predicate.projection_ty.def_id == item_def_id =>
{
projection_predicate.term.ty()
}
@@ -727,7 +734,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
format!("this and all prior arms are found to be of type `{}`", t),
);
}
- let outer_error_span = if any_multiline_arm {
+ let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) {
// Cover just `match` and the scrutinee expression, not
// the entire match body, to reduce diagram noise.
cause.span.shrink_to_lo().to(scrut_span)
@@ -735,7 +742,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
cause.span
};
let msg = "`match` arms have incompatible types";
- err.span_label(outer_error_span, msg);
+ err.span_label(outer, msg);
self.suggest_remove_semi_or_return_binding(
err,
prior_arm_block_id,
@@ -1393,7 +1400,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
/// `swap_secondary_and_primary` is used to make projection errors in particular nicer by using
/// the message in `secondary_span` as the primary label, and apply the message that would
/// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on
- /// E0271, like `src/test/ui/issues/issue-39970.stderr`.
+ /// E0271, like `tests/ui/issues/issue-39970.stderr`.
#[instrument(
level = "debug",
skip(self, diag, secondary_span, swap_secondary_and_primary, prefer_label)
@@ -1426,8 +1433,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
impl<'tcx> OpaqueTypesVisitor<'tcx> {
fn visit_expected_found(
tcx: TyCtxt<'tcx>,
- expected: Ty<'tcx>,
- found: Ty<'tcx>,
+ expected: impl TypeVisitable<'tcx>,
+ found: impl TypeVisitable<'tcx>,
ignore_span: Span,
) -> Self {
let mut types_visitor = OpaqueTypesVisitor {
@@ -1567,6 +1574,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
_ => (false, Mismatch::Fixed("type")),
}
}
+ ValuePairs::Sigs(infer::ExpectedFound { expected, found }) => {
+ OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
+ .report(diag);
+ (false, Mismatch::Fixed("signature"))
+ }
ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
(false, Mismatch::Fixed("trait"))
}
@@ -1730,7 +1742,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let extra = expected == found;
let sort_string = |ty: Ty<'tcx>, path: Option<PathBuf>| {
let mut s = match (extra, ty.kind()) {
- (true, ty::Opaque(def_id, _)) => {
+ (true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => {
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
format!(
@@ -1740,12 +1752,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pos.col.to_usize() + 1,
)
}
- (true, ty::Projection(proj))
- if self.tcx.def_kind(proj.item_def_id)
+ (true, ty::Alias(ty::Projection, proj))
+ if self.tcx.def_kind(proj.def_id)
== DefKind::ImplTraitPlaceholder =>
{
let sm = self.tcx.sess.source_map();
- let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
+ let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
format!(
" (trait associated opaque type at <{}:{}:{}>)",
sm.filename_for_diagnostics(&pos.file.name),
@@ -1770,9 +1782,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// like when you have two references but one is `usize` and the other
// is `f32`. In those cases we still want to show the `note`. If the
// value from `ef` is `Infer(_)`, then we ignore it.
- if !ef.expected.is_ty_infer() {
+ if !ef.expected.is_ty_or_numeric_infer() {
ef.expected != values.expected
- } else if !ef.found.is_ty_infer() {
+ } else if !ef.found.is_ty_or_numeric_infer() {
ef.found != values.found
} else {
false
@@ -1834,7 +1846,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// In some (most?) cases cause.body_id points to actual body, but in some cases
// it's an actual definition. According to the comments (e.g. in
- // rustc_hir_analysis/check/compare_method.rs:compare_predicate_entailment) the latter
+ // rustc_hir_analysis/check/compare_impl_item.rs:compare_predicate_entailment) the latter
// is relied upon by some other code. This might (or might not) need cleanup.
let body_owner_def_id =
self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
@@ -1911,6 +1923,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
(ty::Tuple(fields), _) => {
self.emit_tuple_wrap_err(&mut err, span, found, fields)
}
+ // If a byte was expected and the found expression is a char literal
+ // containing a single ASCII character, perhaps the user meant to write `b'c'` to
+ // specify a byte literal
+ (ty::Uint(ty::UintTy::U8), ty::Char) => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+ && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+ && code.chars().next().map_or(false, |c| c.is_ascii())
+ {
+ err.span_suggestion(
+ span,
+ "if you meant to write a byte literal, prefix with `b`",
+ format!("b'{}'", escape_literal(code)),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
// If a character was expected and the found expression is a string literal
// containing a single character, perhaps the user meant to write `'c'` to
// specify a character literal (issue #92479)
@@ -2038,6 +2066,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
ret => ret,
}
}
+ infer::Sigs(exp_found) => {
+ let exp_found = self.resolve_vars_if_possible(exp_found);
+ if exp_found.references_error() {
+ return None;
+ }
+ let (exp, fnd) = self.cmp_fn_sig(
+ &ty::Binder::dummy(exp_found.expected),
+ &ty::Binder::dummy(exp_found.found),
+ );
+ Some((exp, fnd, None, None))
+ }
}
}
@@ -2126,18 +2165,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// suggest adding an explicit lifetime bound to it.
let generics = self.tcx.generics_of(generic_param_scope);
// type_param_span is (span, has_bounds)
+ let mut is_synthetic = false;
+ let mut ast_generics = None;
let type_param_span = match bound_kind {
GenericKind::Param(ref param) => {
// Account for the case where `param` corresponds to `Self`,
// which doesn't have the expected type argument.
if !(generics.has_self && param.index == 0) {
let type_param = generics.type_param(param, self.tcx);
+ is_synthetic = type_param.kind.is_synthetic();
type_param.def_id.as_local().map(|def_id| {
// Get the `hir::Param` to verify whether it already has any bounds.
// We do this to avoid suggesting code that ends up as `T: 'a'b`,
// instead we suggest `T: 'a + 'b` in that case.
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id);
+ ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id);
let bounds =
ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id));
// `sp` only covers `T`, change it so that it covers
@@ -2169,18 +2211,71 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
.unwrap_or("'lt".to_string())
};
- let add_lt_sugg = generics
- .params
- .first()
- .and_then(|param| param.def_id.as_local())
- .map(|def_id| (self.tcx.def_span(def_id).shrink_to_lo(), format!("{}, ", new_lt)));
+ let mut add_lt_suggs: Vec<Option<_>> = vec![];
+ if is_synthetic {
+ if let Some(ast_generics) = ast_generics {
+ let named_lifetime_param_exist = ast_generics.params.iter().any(|p| {
+ matches!(
+ p.kind,
+ hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
+ )
+ });
+ if named_lifetime_param_exist && let [param, ..] = ast_generics.params
+ {
+ add_lt_suggs.push(Some((
+ self.tcx.def_span(param.def_id).shrink_to_lo(),
+ format!("{new_lt}, "),
+ )));
+ } else {
+ add_lt_suggs
+ .push(Some((ast_generics.span.shrink_to_hi(), format!("<{new_lt}>"))));
+ }
+ }
+ } else {
+ if let [param, ..] = &generics.params[..] && let Some(def_id) = param.def_id.as_local()
+ {
+ add_lt_suggs
+ .push(Some((self.tcx.def_span(def_id).shrink_to_lo(), format!("{new_lt}, "))));
+ }
+ }
+
+ if let Some(ast_generics) = ast_generics {
+ for p in ast_generics.params {
+ if p.is_elided_lifetime() {
+ if self
+ .tcx
+ .sess
+ .source_map()
+ .span_to_prev_source(p.span.shrink_to_hi())
+ .ok()
+ .map_or(false, |s| *s.as_bytes().last().unwrap() == b'&')
+ {
+ add_lt_suggs
+ .push(Some(
+ (
+ p.span.shrink_to_hi(),
+ if let Ok(snip) = self.tcx.sess.source_map().span_to_next_source(p.span)
+ && snip.starts_with(' ')
+ {
+ format!("{new_lt}")
+ } else {
+ format!("{new_lt} ")
+ }
+ )
+ ));
+ } else {
+ add_lt_suggs.push(Some((p.span.shrink_to_hi(), format!("<{new_lt}>"))));
+ }
+ }
+ }
+ }
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
- GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
- GenericKind::Opaque(def_id, substs) => {
- format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs))
- }
+ GenericKind::Alias(ref p) => match p.kind(self.tcx) {
+ ty::AliasKind::Projection => format!("the associated type `{}`", p),
+ ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
+ },
};
if let Some(SubregionOrigin::CompareImplItemObligation {
@@ -2202,15 +2297,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
type_param_span: Option<(Span, bool)>,
bound_kind: GenericKind<'tcx>,
sub: S,
- add_lt_sugg: Option<(Span, String)>,
+ add_lt_suggs: Vec<Option<(Span, String)>>,
) {
let msg = "consider adding an explicit lifetime bound";
if let Some((sp, has_lifetimes)) = type_param_span {
let suggestion =
if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) };
let mut suggestions = vec![(sp, suggestion)];
- if let Some(add_lt_sugg) = add_lt_sugg {
- suggestions.push(add_lt_sugg);
+ for add_lt_sugg in add_lt_suggs {
+ if let Some(add_lt_sugg) = add_lt_sugg {
+ suggestions.push(add_lt_sugg);
+ }
}
err.multipart_suggestion_verbose(
format!("{msg}..."),
@@ -2234,9 +2331,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
let mut sugg =
vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))];
- if let Some(lt) = add_lt_sugg.clone() {
- sugg.push(lt);
- sugg.rotate_right(1);
+ for add_lt_sugg in add_lt_suggs.clone() {
+ if let Some(lt) = add_lt_sugg {
+ sugg.push(lt);
+ sugg.rotate_right(1);
+ }
}
// `MaybeIncorrect` due to issue #41966.
err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
@@ -2340,7 +2439,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// for the bound is not suitable for suggestions when `-Zverbose` is set because it
// uses `Debug` output, so we handle it specially here so that suggestions are
// always correct.
- binding_suggestion(&mut err, type_param_span, bound_kind, name, None);
+ binding_suggestion(&mut err, type_param_span, bound_kind, name, vec![]);
err
}
@@ -2353,7 +2452,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
"{} may not live long enough",
labeled_user_string
);
- binding_suggestion(&mut err, type_param_span, bound_kind, "'static", None);
+ binding_suggestion(&mut err, type_param_span, bound_kind, "'static", vec![]);
err
}
@@ -2383,7 +2482,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// fn get_later<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
// suggest:
// fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
- ty::Closure(_, _substs) | ty::Opaque(_, _substs) if return_impl_trait => {
+ ty::Closure(..) | ty::Alias(ty::Opaque, ..) if return_impl_trait => {
new_binding_suggestion(&mut err, type_param_span);
}
_ => {
@@ -2392,7 +2491,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
type_param_span,
bound_kind,
new_lt,
- add_lt_sugg,
+ add_lt_suggs,
);
}
}
@@ -2765,7 +2864,7 @@ impl TyCategory {
pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
match *ty.kind() {
ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
- ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => Some((Self::Opaque, def_id)),
ty::Generator(def_id, ..) => {
Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 8ff1639a3..b8c843a8a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -20,7 +20,7 @@ use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
use rustc_middle::ty::{self, DefIdTree, InferConst};
use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
-use rustc_span::symbol::{kw, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, Span};
use std::borrow::Cow;
use std::iter;
@@ -78,8 +78,8 @@ impl InferenceDiagnosticsData {
}
fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str {
- if in_type.is_ty_infer() {
- "empty"
+ if in_type.is_ty_or_numeric_infer() {
+ ""
} else if self.name == "_" {
// FIXME: Consider specializing this message if there is a single `_`
// in the type.
@@ -183,13 +183,24 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
printer
}
-fn ty_to_string<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
+fn ty_to_string<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ called_method_def_id: Option<DefId>,
+) -> String {
let printer = fmt_printer(infcx, Namespace::TypeNS);
let ty = infcx.resolve_vars_if_possible(ty);
- match ty.kind() {
+ match (ty.kind(), called_method_def_id) {
// We don't want the regular output for `fn`s because it includes its path in
// invalid pseudo-syntax, we want the `fn`-pointer output instead.
- ty::FnDef(..) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
+ (ty::FnDef(..), _) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
+ (_, Some(def_id))
+ if ty.is_ty_or_numeric_infer()
+ && infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) =>
+ {
+ "Vec<_>".to_string()
+ }
+ _ if ty.is_ty_or_numeric_infer() => "/* Type */".to_string(),
// FIXME: The same thing for closures, but this only works when the closure
// does not capture anything.
//
@@ -213,7 +224,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
.map(|args| {
args.tuple_fields()
.iter()
- .map(|arg| ty_to_string(infcx, arg))
+ .map(|arg| ty_to_string(infcx, arg, None))
.collect::<Vec<_>>()
.join(", ")
})
@@ -221,7 +232,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
let ret = if fn_sig.output().skip_binder().is_unit() {
String::new()
} else {
- format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder()))
+ format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder(), None))
};
format!("fn({}){}", args, ret)
}
@@ -368,6 +379,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+ #[instrument(level = "debug", skip(self, error_code))]
pub fn emit_inference_failure_err(
&self,
body_id: Option<hir::BodyId>,
@@ -406,7 +418,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut infer_subdiags = Vec::new();
let mut multi_suggestions = Vec::new();
match kind {
- InferSourceKind::LetBinding { insert_span, pattern_name, ty } => {
+ InferSourceKind::LetBinding { insert_span, pattern_name, ty, def_id } => {
infer_subdiags.push(SourceKindSubdiag::LetLike {
span: insert_span,
name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new),
@@ -415,7 +427,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
prefix: arg_data.kind.try_get_prefix().unwrap_or_default(),
arg_name: arg_data.name,
kind: if pattern_name.is_some() { "with_pattern" } else { "other" },
- type_name: ty_to_string(self, ty),
+ type_name: ty_to_string(self, ty, def_id),
});
}
InferSourceKind::ClosureArg { insert_span, ty } => {
@@ -427,7 +439,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
prefix: arg_data.kind.try_get_prefix().unwrap_or_default(),
arg_name: arg_data.name,
kind: "closure",
- type_name: ty_to_string(self, ty),
+ type_name: ty_to_string(self, ty, None),
});
}
InferSourceKind::GenericArg {
@@ -456,33 +468,39 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
parent_name,
});
- let args = fmt_printer(self, Namespace::TypeNS)
- .comma_sep(generic_args.iter().copied().map(|arg| {
- if arg.is_suggestable(self.tcx, true) {
- return arg;
- }
+ let args = if self.infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn)
+ == Some(generics_def_id)
+ {
+ "Vec<_>".to_string()
+ } else {
+ fmt_printer(self, Namespace::TypeNS)
+ .comma_sep(generic_args.iter().copied().map(|arg| {
+ if arg.is_suggestable(self.tcx, true) {
+ return arg;
+ }
- match arg.unpack() {
- GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
- GenericArgKind::Type(_) => self
- .next_ty_var(TypeVariableOrigin {
- span: rustc_span::DUMMY_SP,
- kind: TypeVariableOriginKind::MiscVariable,
- })
- .into(),
- GenericArgKind::Const(arg) => self
- .next_const_var(
- arg.ty(),
- ConstVariableOrigin {
+ match arg.unpack() {
+ GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
+ GenericArgKind::Type(_) => self
+ .next_ty_var(TypeVariableOrigin {
span: rustc_span::DUMMY_SP,
- kind: ConstVariableOriginKind::MiscVariable,
- },
- )
- .into(),
- }
- }))
- .unwrap()
- .into_buffer();
+ kind: TypeVariableOriginKind::MiscVariable,
+ })
+ .into(),
+ GenericArgKind::Const(arg) => self
+ .next_const_var(
+ arg.ty(),
+ ConstVariableOrigin {
+ span: rustc_span::DUMMY_SP,
+ kind: ConstVariableOriginKind::MiscVariable,
+ },
+ )
+ .into(),
+ }
+ }))
+ .unwrap()
+ .into_buffer()
+ };
if !have_turbofish {
infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
@@ -520,7 +538,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
));
}
InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
- let ty_info = ty_to_string(self, ty);
+ let ty_info = ty_to_string(self, ty, None);
multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
ty_info,
data,
@@ -608,6 +626,7 @@ enum InferSourceKind<'tcx> {
insert_span: Span,
pattern_name: Option<Ident>,
ty: Ty<'tcx>,
+ def_id: Option<DefId>,
},
ClosureArg {
insert_span: Span,
@@ -661,8 +680,8 @@ impl<'tcx> InferSourceKind<'tcx> {
| InferSourceKind::ClosureReturn { ty, .. } => {
if ty.is_closure() {
("closure", closure_as_fn_str(infcx, ty))
- } else if !ty.is_ty_infer() {
- ("normal", ty_to_string(infcx, ty))
+ } else if !ty.is_ty_or_numeric_infer() {
+ ("normal", ty_to_string(infcx, ty, None))
} else {
("other", String::new())
}
@@ -788,10 +807,18 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
/// Uses `fn source_cost` to determine whether this inference source is preferable to
/// previous sources. We generally prefer earlier sources.
#[instrument(level = "debug", skip(self))]
- fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
+ fn update_infer_source(&mut self, mut new_source: InferSource<'tcx>) {
let cost = self.source_cost(&new_source) + self.attempt;
debug!(?cost);
self.attempt += 1;
+ if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source
+ && let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind
+ && ty.is_ty_or_numeric_infer()
+ {
+ // Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of
+ // `let x: _ = iter.collect();`, as this is a very common case.
+ *def_id = Some(did);
+ }
if cost < self.infer_source_cost {
self.infer_source_cost = cost;
self.infer_source = Some(new_source);
@@ -852,7 +879,10 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
match inner.unpack() {
GenericArgKind::Lifetime(_) => {}
GenericArgKind::Type(ty) => {
- if matches!(ty.kind(), ty::Opaque(..) | ty::Closure(..) | ty::Generator(..)) {
+ if matches!(
+ ty.kind(),
+ ty::Alias(ty::Opaque, ..) | ty::Closure(..) | ty::Generator(..)
+ ) {
// Opaque types can't be named by the user right now.
//
// Both the generic arguments of closures and generators can
@@ -1089,6 +1119,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
insert_span: local.pat.span.shrink_to_hi(),
pattern_name: local.pat.simple_ident(),
ty,
+ def_id: None,
},
})
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index d8f540b74..39f4d5022 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -96,8 +96,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
}
}
- hir::TyKind::Rptr(ref lifetime, _) => {
- // the lifetime of the TyRptr
+ hir::TyKind::Ref(ref lifetime, _) => {
+ // the lifetime of the Ref
let hir_id = lifetime.hir_id;
match (self.tcx.named_region(hir_id), self.bound_region) {
// Find the index of the named region that was part of the
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index 8a0e332f9..59fb74eb5 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -9,7 +9,7 @@ mod different_lifetimes;
pub mod find_anon_type;
mod mismatched_static_lifetime;
mod named_anon_conflict;
-mod placeholder_error;
+pub(crate) mod placeholder_error;
mod placeholder_relation;
mod static_impl_trait;
mod trait_impl_difference;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index 3fe7c1598..4e13ec902 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -1,8 +1,11 @@
//! Error Reporting for Anonymous Region Lifetime Errors
//! where one region is named and the other is anonymous.
-use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use crate::{
+ errors::ExplicitLifetimeRequired,
+ infer::error_reporting::nice_region_error::find_anon_type::find_anon_type,
+};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::ty;
use rustc_span::symbol::kw;
@@ -86,31 +89,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
{
return None;
}
-
- let (error_var, span_label_var) = match param.pat.simple_ident() {
- Some(simple_ident) => (
- format!("the type of `{}`", simple_ident),
- format!("the type of `{}`", simple_ident),
- ),
- None => ("parameter type".to_owned(), "type".to_owned()),
+ let named = named.to_string();
+ let err = match param.pat.simple_ident() {
+ Some(simple_ident) => ExplicitLifetimeRequired::WithIdent {
+ span,
+ simple_ident,
+ named,
+ new_ty_span,
+ new_ty,
+ },
+ None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty },
};
-
- let mut diag = struct_span_err!(
- self.tcx().sess,
- span,
- E0621,
- "explicit lifetime required in {}",
- error_var
- );
-
- diag.span_label(span, format!("lifetime `{}` required", named));
- diag.span_suggestion(
- new_ty_span,
- &format!("add explicit lifetime `{}` to {}", named, span_label_var),
- new_ty,
- Applicability::Unspecified,
- );
-
- Some(diag)
+ Some(self.tcx().sess.parse_sess.create_err(err))
}
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index 1f554c81e..99431567e 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -1,10 +1,14 @@
+use crate::errors::{
+ ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
+ TraitPlaceholderMismatch, TyOrSig,
+};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::ValuePairs;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::intern::Interned;
-use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::error::ExpectedFound;
@@ -12,7 +16,43 @@ use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
-use std::fmt::{self, Write};
+use std::fmt;
+
+// HACK(eddyb) maybe move this in a more central location.
+#[derive(Copy, Clone)]
+pub struct Highlighted<'tcx, T> {
+ tcx: TyCtxt<'tcx>,
+ highlight: RegionHighlightMode<'tcx>,
+ value: T,
+}
+
+impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T>
+where
+ T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
+{
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ rustc_errors::DiagnosticArgValue::Str(self.to_string().into())
+ }
+}
+
+impl<'tcx, T> Highlighted<'tcx, T> {
+ fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
+ Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
+ }
+}
+
+impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
+where
+ T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
+ printer.region_highlight_mode = self.highlight;
+
+ let s = self.value.print(printer)?.into_buffer();
+ f.write_str(&s)
+ }
+}
impl<'tcx> NiceRegionError<'_, 'tcx> {
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
@@ -205,34 +245,27 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
actual_substs: SubstsRef<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let span = cause.span();
- let msg = format!(
- "implementation of `{}` is not general enough",
- self.tcx().def_path_str(trait_def_id),
- );
- let mut err = self.tcx().sess.struct_span_err(span, &msg);
-
- let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id)
- | ObligationCauseCode::ExprItemObligation(def_id, ..) =
- *cause.code()
- {
- err.span_label(span, "doesn't satisfy where-clause");
- err.span_label(
- self.tcx().def_span(def_id),
- &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)),
- );
- true
- } else {
- err.span_label(span, &msg);
- false
- };
- let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef {
- def_id: trait_def_id,
- substs: expected_substs,
- });
- let actual_trait_ref = self
+ let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
+ if let ObligationCauseCode::ItemObligation(def_id)
+ | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
+ {
+ (
+ true,
+ Some(span),
+ Some(self.tcx().def_span(def_id)),
+ None,
+ self.tcx().def_path_str(def_id),
+ )
+ } else {
+ (false, None, None, Some(span), String::new())
+ };
+
+ let expected_trait_ref = self
.cx
- .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
+ .resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, expected_substs));
+ let actual_trait_ref =
+ self.cx.resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, actual_substs));
// Search the expected and actual trait references to see (a)
// whether the sub/sup placeholders appear in them (sometimes
@@ -286,8 +319,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
?expected_self_ty_has_vid,
);
- self.explain_actual_impl_that_was_found(
- &mut err,
+ let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
sub_placeholder,
sup_placeholder,
has_sub,
@@ -301,7 +333,15 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
leading_ellipsis,
);
- err
+ self.tcx().sess.create_err(TraitPlaceholderMismatch {
+ span,
+ satisfy_span,
+ where_span,
+ dup_span,
+ def_id,
+ trait_def_id: self.tcx().def_path_str(trait_def_id),
+ actual_impl_expl_notes,
+ })
}
/// Add notes with details about the expected and actual trait refs, with attention to cases
@@ -311,7 +351,6 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
/// due to the number of combinations we have to deal with.
fn explain_actual_impl_that_was_found(
&self,
- err: &mut Diagnostic,
sub_placeholder: Option<Region<'tcx>>,
sup_placeholder: Option<Region<'tcx>>,
has_sub: Option<usize>,
@@ -323,39 +362,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
actual_has_vid: Option<usize>,
any_self_ty_has_vid: bool,
leading_ellipsis: bool,
- ) {
- // HACK(eddyb) maybe move this in a more central location.
- #[derive(Copy, Clone)]
- struct Highlighted<'tcx, T> {
- tcx: TyCtxt<'tcx>,
- highlight: RegionHighlightMode<'tcx>,
- value: T,
- }
-
- impl<'tcx, T> Highlighted<'tcx, T> {
- fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
- Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
- }
- }
-
- impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
- where
- T: for<'a> Print<
- 'tcx,
- FmtPrinter<'a, 'tcx>,
- Error = fmt::Error,
- Output = FmtPrinter<'a, 'tcx>,
- >,
- {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
- printer.region_highlight_mode = self.highlight;
-
- let s = self.value.print(printer)?.into_buffer();
- f.write_str(&s)
- }
- }
-
+ ) -> Vec<ActualImplExplNotes<'tcx>> {
// The weird thing here with the `maybe_highlighting_region` calls and the
// the match inside is meant to be like this:
//
@@ -363,7 +370,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
// in the types are about to print
// - Meanwhile, the `maybe_highlighting_region` calls set up
// highlights so that, if they do appear, we will replace
- // them `'0` and whatever. (This replacement takes place
+ // them `'0` and whatever. (This replacement takes place
// inside the closure given to `maybe_highlighting_region`.)
//
// There is some duplication between the calls -- i.e., the
@@ -382,120 +389,110 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
- err.note(&{
- let passive_voice = match (has_sub, has_sup) {
- (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
- (None, None) => {
- expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
- match expected_has_vid {
- Some(_) => true,
- None => any_self_ty_has_vid,
- }
- }
- };
- let mut note = if same_self_type {
- let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
- self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
-
- if self_ty.value.is_closure()
- && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
- {
- let closure_sig = self_ty.map(|closure| {
- if let ty::Closure(_, substs) = closure.kind() {
- self.tcx().signature_unclosure(
- substs.as_closure().sig(),
- rustc_hir::Unsafety::Normal,
- )
- } else {
- bug!("type is not longer closure");
- }
- });
-
- format!(
- "{}closure with signature `{}` must implement `{}`",
- if leading_ellipsis { "..." } else { "" },
- closure_sig,
- expected_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
- } else {
- format!(
- "{}`{}` must implement `{}`",
- if leading_ellipsis { "..." } else { "" },
- self_ty,
- expected_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
+ let passive_voice = match (has_sub, has_sup) {
+ (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
+ (None, None) => {
+ expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
+ match expected_has_vid {
+ Some(_) => true,
+ None => any_self_ty_has_vid,
}
- } else if passive_voice {
- format!(
- "{}`{}` would have to be implemented for the type `{}`",
- if leading_ellipsis { "..." } else { "" },
+ }
+ };
+
+ let (kind, ty_or_sig, trait_path) = if same_self_type {
+ let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
+ self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
+
+ if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
+ {
+ let closure_sig = self_ty.map(|closure| {
+ if let ty::Closure(_, substs) = closure.kind() {
+ self.tcx().signature_unclosure(
+ substs.as_closure().sig(),
+ rustc_hir::Unsafety::Normal,
+ )
+ } else {
+ bug!("type is not longer closure");
+ }
+ });
+ (
+ ActualImplExpectedKind::Signature,
+ TyOrSig::ClosureSig(closure_sig),
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
- expected_trait_ref.map(|tr| tr.self_ty()),
)
} else {
- format!(
- "{}`{}` must implement `{}`",
- if leading_ellipsis { "..." } else { "" },
- expected_trait_ref.map(|tr| tr.self_ty()),
+ (
+ ActualImplExpectedKind::Other,
+ TyOrSig::Ty(self_ty),
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
)
- };
+ }
+ } else if passive_voice {
+ (
+ ActualImplExpectedKind::Passive,
+ TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
+ expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+ )
+ } else {
+ (
+ ActualImplExpectedKind::Other,
+ TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
+ expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+ )
+ };
- match (has_sub, has_sup) {
- (Some(n1), Some(n2)) => {
- let _ = write!(
- note,
- ", for any two lifetimes `'{}` and `'{}`...",
- std::cmp::min(n1, n2),
- std::cmp::max(n1, n2),
- );
- }
- (Some(n), _) | (_, Some(n)) => {
- let _ = write!(note, ", for any lifetime `'{}`...", n,);
- }
- (None, None) => {
- if let Some(n) = expected_has_vid {
- let _ = write!(note, ", for some specific lifetime `'{}`...", n,);
- }
+ let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
+ (Some(n1), Some(n2)) => {
+ (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))
+ }
+ (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),
+ (None, None) => {
+ if let Some(n) = expected_has_vid {
+ (ActualImplExpectedLifetimeKind::Some, n, 0)
+ } else {
+ (ActualImplExpectedLifetimeKind::Nothing, 0, 0)
}
}
+ };
- note
- });
+ let note_1 = ActualImplExplNotes::new_expected(
+ kind,
+ lt_kind,
+ leading_ellipsis,
+ ty_or_sig,
+ trait_path,
+ lifetime_1,
+ lifetime_2,
+ );
let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
- err.note(&{
- let passive_voice = match actual_has_vid {
- Some(_) => any_self_ty_has_vid,
- None => true,
- };
- let mut note = if same_self_type {
- format!(
- "...but it actually implements `{}`",
- actual_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
- } else if passive_voice {
- format!(
- "...but `{}` is actually implemented for the type `{}`",
- actual_trait_ref.map(|tr| tr.print_only_trait_path()),
- actual_trait_ref.map(|tr| tr.self_ty()),
- )
- } else {
- format!(
- "...but `{}` actually implements `{}`",
- actual_trait_ref.map(|tr| tr.self_ty()),
- actual_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
- };
+ let passive_voice = match actual_has_vid {
+ Some(_) => any_self_ty_has_vid,
+ None => true,
+ };
- if let Some(n) = actual_has_vid {
- let _ = write!(note, ", for some specific lifetime `'{}`", n);
+ let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());
+ let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
+ let has_lifetime = actual_has_vid.is_some();
+ let lifetime = actual_has_vid.unwrap_or_default();
+
+ let note_2 = if same_self_type {
+ ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }
+ } else if passive_voice {
+ ActualImplExplNotes::ButActuallyImplementedForTy {
+ trait_path,
+ ty,
+ has_lifetime,
+ lifetime,
}
+ } else {
+ ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }
+ };
- note
- });
+ vec![note_1, note_2]
}
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
index c42240f21..9534bce54 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
@@ -44,7 +44,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
);
}
(Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
- err.span_note(sub_span, format!("the lifetime defined here..."));
+ err.span_note(sub_span, "the lifetime defined here...");
err.span_note(
sup_span,
format!("...must outlive the lifetime `{sup_symbol}` defined here"),
@@ -55,17 +55,11 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
sub_span,
format!("the lifetime `{sub_symbol}` defined here..."),
);
- err.span_note(
- sup_span,
- format!("...must outlive the lifetime defined here"),
- );
+ err.span_note(sup_span, "...must outlive the lifetime defined here");
}
(Some(sub_span), Some(sup_span), _, _) => {
- err.span_note(sub_span, format!("the lifetime defined here..."));
- err.span_note(
- sup_span,
- format!("...must outlive the lifetime defined here"),
- );
+ err.span_note(sub_span, "the lifetime defined here...");
+ err.span_note(sup_span, "...must outlive the lifetime defined here");
}
_ => {}
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 09f9aa3c8..49ad3ce50 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -1,20 +1,28 @@
//! Error Reporting for static impl Traits.
+use crate::errors::{
+ ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted,
+ ReqIntroducedLocations,
+};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
+use rustc_hir::{
+ self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, Node,
+ TyKind,
+};
use rustc_middle::ty::{
self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
};
use rustc_span::symbol::Ident;
use rustc_span::Span;
+use rustc_span::def_id::LocalDefId;
use std::ops::ControlFlow;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -49,46 +57,32 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
let param = self.find_param_with_region(*sup_r, *sub_r)?;
- let lifetime = if sup_r.has_name() {
- format!("lifetime `{}`", sup_r)
- } else {
- "an anonymous lifetime `'_`".to_string()
+ let simple_ident = param.param.pat.simple_ident();
+
+ let (has_impl_path, impl_path) = match ctxt.assoc_item.container {
+ AssocItemContainer::TraitContainer => {
+ let id = ctxt.assoc_item.container_id(tcx);
+ (true, tcx.def_path_str(id))
+ }
+ AssocItemContainer::ImplContainer => (false, String::new()),
};
- let mut err = struct_span_err!(
- tcx.sess,
- cause.span,
- E0772,
- "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
- requirement",
- param
- .param
- .pat
- .simple_ident()
- .map(|s| format!("`{}`", s))
- .unwrap_or_else(|| "`fn` parameter".to_string()),
- lifetime,
- ctxt.assoc_item.name,
- );
- err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
- err.span_label(
- cause.span,
- &format!(
- "...is used and required to live as long as `'static` here \
- because of an implicit lifetime bound on the {}",
- match ctxt.assoc_item.container {
- AssocItemContainer::TraitContainer => {
- let id = ctxt.assoc_item.container_id(tcx);
- format!("`impl` of `{}`", tcx.def_path_str(id))
- }
- AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
- },
- ),
- );
+
+ let mut err = self.tcx().sess.create_err(ButCallingIntroduces {
+ param_ty_span: param.param_ty_span,
+ cause_span: cause.span,
+ has_param_name: simple_ident.is_some(),
+ param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(),
+ has_lifetime: sup_r.has_name(),
+ lifetime: sup_r.to_string(),
+ assoc_item: ctxt.assoc_item.name,
+ has_impl_path,
+ impl_path,
+ });
if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
let reported = err.emit();
return Some(reported);
} else {
- err.cancel();
+ err.cancel()
}
}
return None;
@@ -104,25 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let sp = var_origin.span();
let return_sp = sub_origin.span();
let param = self.find_param_with_region(*sup_r, *sub_r)?;
- let (lifetime_name, lifetime) = if sup_r.has_name() {
- (sup_r.to_string(), format!("lifetime `{}`", sup_r))
- } else {
- ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
- };
- let param_name = param
- .param
- .pat
- .simple_ident()
- .map(|s| format!("`{}`", s))
- .unwrap_or_else(|| "`fn` parameter".to_string());
- let mut err = struct_span_err!(
- tcx.sess,
- sp,
- E0759,
- "{} has {} but it needs to satisfy a `'static` lifetime requirement",
- param_name,
- lifetime,
- );
+ let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
let (mention_influencer, influencer_point) =
if sup_origin.span().overlaps(param.param_ty_span) {
@@ -141,7 +117,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
} else {
(!sup_origin.span().overlaps(return_sp), param.param_ty_span)
};
- err.span_label(influencer_point, &format!("this data with {}...", lifetime));
debug!("try_report_static_impl_trait: param_info={:?}", param);
@@ -155,31 +130,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
spans.dedup_by_key(|span| (span.lo(), span.hi()));
// We try to make the output have fewer overlapping spans if possible.
- let require_msg = if spans.is_empty() {
- "...is used and required to live as long as `'static` here"
- } else {
- "...and is required to live as long as `'static` here"
- };
let require_span =
if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp };
- for span in &spans {
- err.span_label(*span, "...is used here...");
- }
-
- if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
- // If any of the "captured here" labels appears on the same line or after
- // `require_span`, we put it on a note to ensure the text flows by appearing
- // always at the end.
- err.span_note(require_span, require_msg);
+ let spans_empty = spans.is_empty();
+ let require_as_note = spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp);
+ let bound = if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
+ Some(*bound)
} else {
- // We don't need a note, it's already at the end, it can be shown as a `span_label`.
- err.span_label(require_span, require_msg);
- }
+ None
+ };
+
+ let mut subdiag = None;
- if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
- err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
- }
if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
if let ObligationCauseCode::ReturnValue(hir_id)
| ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
@@ -187,33 +150,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let parent_id = tcx.hir().get_parent_item(*hir_id);
if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
let mut span: MultiSpan = fn_decl.output.span().into();
+ let mut spans = Vec::new();
let mut add_label = true;
if let hir::FnRetTy::Return(ty) = fn_decl.output {
let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
v.visit_ty(ty);
if !v.0.is_empty() {
span = v.0.clone().into();
- for sp in v.0 {
- span.push_span_label(sp, "`'static` requirement introduced here");
- }
+ spans = v.0;
add_label = false;
}
}
- if add_label {
- span.push_span_label(
- fn_decl.output.span(),
- "requirement introduced by this return type",
- );
- }
- span.push_span_label(cause.span, "because of this returned expression");
- err.span_note(
+ let fn_decl_span = fn_decl.output.span();
+
+ subdiag = Some(ReqIntroducedLocations {
span,
- "`'static` lifetime requirement introduced by the return type",
- );
+ spans,
+ fn_decl_span,
+ cause_span: cause.span,
+ add_label,
+ });
}
}
}
+ let diag = ButNeedsToSatisfy {
+ sp,
+ influencer_point,
+ spans: spans.clone(),
+ // If any of the "captured here" labels appears on the same line or after
+ // `require_span`, we put it on a note to ensure the text flows by appearing
+ // always at the end.
+ require_span_as_note: require_as_note.then_some(require_span),
+ // We don't need a note, it's already at the end, it can be shown as a `span_label`.
+ require_span_as_label: (!require_as_note).then_some(require_span),
+ req_introduces_loc: subdiag,
+
+ has_lifetime: sup_r.has_name(),
+ lifetime: sup_r.to_string(),
+ spans_empty,
+ bound,
+ };
+
+ let mut err = self.tcx().sess.create_err(diag);
+
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
let mut override_error_code = None;
@@ -239,7 +219,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let mut v = TraitObjectVisitor(FxIndexSet::default());
v.visit_ty(param.param_ty);
if let Some((ident, self_ty)) =
- self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
+ NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0)
&& self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty)
{
override_error_code = Some(ident.name);
@@ -247,12 +227,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
// Provide a more targeted error code and description.
- err.code(rustc_errors::error_code!(E0772));
- err.set_primary_message(&format!(
- "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
- requirement",
- param_name, lifetime, ident,
- ));
+ let retarget_subdiag = MoreTargeted { ident };
+ retarget_subdiag.add_to_diagnostic(&mut err);
}
let arg = match param.param.pat.simple_ident() {
@@ -268,6 +244,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
Some(arg),
captures,
Some((param.param_ty_span, param.param_ty.to_string())),
+ Some(anon_reg_sup.def_id),
);
let reported = err.emit();
@@ -283,6 +260,7 @@ pub fn suggest_new_region_bound(
arg: Option<String>,
captures: String,
param: Option<(Span, String)>,
+ scope_def_id: Option<LocalDefId>,
) {
debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
@@ -309,19 +287,12 @@ pub fn suggest_new_region_bound(
let did = item_id.owner_id.to_def_id();
let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
- if let Some(span) = opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime {
- res: LifetimeName::Static,
- ident,
- ..
- }) => Some(ident.span),
- _ => None,
- })
- .next()
- {
+ if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime {
+ res: LifetimeName::Static, ident, ..
+ }) => Some(ident.span),
+ _ => None,
+ }) {
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
span,
@@ -330,7 +301,7 @@ pub fn suggest_new_region_bound(
Applicability::MaybeIncorrect,
);
}
- if let Some((param_span, param_ty)) = param.clone() {
+ if let Some((param_span, ref param_ty)) = param {
err.span_suggestion_verbose(
param_span,
add_static_bound,
@@ -338,27 +309,78 @@ pub fn suggest_new_region_bound(
Applicability::MaybeIncorrect,
);
}
- } else if opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime { ident, .. })
- if ident.name.to_string() == lifetime_name =>
- {
- Some(ident.span)
- }
- _ => None,
- })
- .next()
- .is_some()
- {
+ } else if opaque.bounds.iter().any(|arg| match arg {
+ GenericBound::Outlives(Lifetime { ident, .. })
+ if ident.name.to_string() == lifetime_name =>
+ {
+ true
+ }
+ _ => false,
+ }) {
} else {
- err.span_suggestion_verbose(
- fn_return.span.shrink_to_hi(),
- &format!("{declare} `{ty}` {captures}, {explicit}",),
- &plus_lt,
- Applicability::MaybeIncorrect,
- );
+ // get a lifetime name of existing named lifetimes if any
+ let existing_lt_name = if let Some(id) = scope_def_id
+ && let Some(generics) = tcx.hir().get_generics(id)
+ && let named_lifetimes = generics
+ .params
+ .iter()
+ .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }))
+ .map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}})
+ .filter(|n| ! matches!(n, None))
+ .collect::<Vec<_>>()
+ && named_lifetimes.len() > 0 {
+ named_lifetimes[0].clone()
+ } else {
+ None
+ };
+ let name = if let Some(name) = &existing_lt_name {
+ format!("{}", name)
+ } else {
+ format!("'a")
+ };
+ // if there are more than one elided lifetimes in inputs, the explicit `'_` lifetime cannot be used.
+ // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any
+ if let Some(id) = scope_def_id
+ && let Some(generics) = tcx.hir().get_generics(id)
+ && let mut spans_suggs = generics
+ .params
+ .iter()
+ .filter(|p| p.is_elided_lifetime())
+ .map(|p|
+ if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_)
+ (p.span.shrink_to_hi(),format!("{name} "))
+ } else { // Underscore (elided with '_)
+ (p.span, format!("{name}"))
+ }
+ )
+ .collect::<Vec<_>>()
+ && spans_suggs.len() > 1
+ {
+ let use_lt =
+ if existing_lt_name == None {
+ spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>")));
+ format!("you can introduce a named lifetime parameter `{name}`")
+ } else {
+ // make use the existing named lifetime
+ format!("you can use the named lifetime parameter `{name}`")
+ };
+ spans_suggs
+ .push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
+ err.multipart_suggestion_verbose(
+ &format!(
+ "{declare} `{ty}` {captures}, {use_lt}",
+ ),
+ spans_suggs,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!("{declare} `{ty}` {captures}, {explicit}",),
+ &plus_lt,
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
TyKind::TraitObject(_, lt, _) => {
@@ -403,66 +425,54 @@ pub fn suggest_new_region_bound(
}
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
- fn get_impl_ident_and_self_ty_from_trait(
- &self,
+ pub fn get_impl_ident_and_self_ty_from_trait(
+ tcx: TyCtxt<'tcx>,
def_id: DefId,
trait_objects: &FxIndexSet<DefId>,
) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
- let tcx = self.tcx();
- match tcx.hir().get_if_local(def_id) {
- Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+ match tcx.hir().get_if_local(def_id)? {
+ Node::ImplItem(impl_item) => {
+ let impl_did = tcx.hir().get_parent_item(impl_item.hir_id());
+ if let hir::OwnerNode::Item(Item {
+ kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+ ..
+ }) = tcx.hir().owner(impl_did)
{
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) => Some((impl_item.ident, self_ty)),
- _ => None,
+ Some((impl_item.ident, self_ty))
+ } else {
+ None
}
}
- Some(Node::TraitItem(trait_item)) => {
- let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did.def_id) {
- Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
- // The method being called is defined in the `trait`, but the `'static`
- // obligation comes from the `impl`. Find that `impl` so that we can point
- // at it in the suggestion.
- let trait_did = trait_did.to_def_id();
- match tcx
- .hir()
- .trait_impls(trait_did)
- .iter()
- .filter_map(|&impl_did| {
- match tcx.hir().get_if_local(impl_did.to_def_id()) {
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) if trait_objects.iter().all(|did| {
- // FIXME: we should check `self_ty` against the receiver
- // type in the `UnifyReceiver` context, but for now, use
- // this imperfect proxy. This will fail if there are
- // multiple `impl`s for the same trait like
- // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
- // In that case, only the first one will get suggestions.
- let mut traits = vec![];
- let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
- hir_v.visit_ty(self_ty);
- !traits.is_empty()
- }) =>
- {
- Some(self_ty)
- }
- _ => None,
- }
- })
- .next()
- {
- Some(self_ty) => Some((trait_item.ident, self_ty)),
- _ => None,
- }
+ Node::TraitItem(trait_item) => {
+ let trait_id = tcx.hir().get_parent_item(trait_item.hir_id());
+ debug_assert_eq!(tcx.def_kind(trait_id.def_id), hir::def::DefKind::Trait);
+ // The method being called is defined in the `trait`, but the `'static`
+ // obligation comes from the `impl`. Find that `impl` so that we can point
+ // at it in the suggestion.
+ let trait_did = trait_id.to_def_id();
+ tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
+ if let Node::Item(Item {
+ kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+ ..
+ }) = tcx.hir().find_by_def_id(impl_did)?
+ && trait_objects.iter().all(|did| {
+ // FIXME: we should check `self_ty` against the receiver
+ // type in the `UnifyReceiver` context, but for now, use
+ // this imperfect proxy. This will fail if there are
+ // multiple `impl`s for the same trait like
+ // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+ // In that case, only the first one will get suggestions.
+ let mut traits = vec![];
+ let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
+ hir_v.visit_ty(self_ty);
+ !traits.is_empty()
+ })
+ {
+ Some((trait_item.ident, *self_ty))
+ } else {
+ None
}
- _ => None,
- }
+ })
}
_ => None,
}
@@ -493,7 +503,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// Get the `Ident` of the method being called and the corresponding `impl` (to point at
// `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
- let Some((ident, self_ty)) = self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0) else {
+ let Some((ident, self_ty)) = NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0) else {
return false;
};
@@ -513,21 +523,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
hir_v.visit_ty(&self_ty);
- for span in &traits {
- let mut multi_span: MultiSpan = vec![*span].into();
- multi_span
- .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
- multi_span.push_span_label(
- ident.span,
- "calling this method introduces the `impl`'s 'static` requirement",
- );
- err.span_note(multi_span, "the used `impl` has a `'static` requirement");
- err.span_suggestion_verbose(
- span.shrink_to_hi(),
- "consider relaxing the implicit `'static` requirement",
- " + '_",
- Applicability::MaybeIncorrect,
- );
+ for &span in &traits {
+ let subdiag = DynTraitConstraintSuggestion { span, ident };
+ subdiag.add_to_diagnostic(err);
suggested = true;
}
}
@@ -545,7 +543,7 @@ impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
if let Some(def_id) = preds.principal_def_id() {
self.0.insert(def_id);
}
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
_ => t.super_visit_with(self),
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 5d536e982..40c0c806e 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -1,15 +1,17 @@
//! Error Reporting for `impl` items that do not match the obligations from their `trait`.
+use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::Subtype;
+use crate::infer::{Subtype, ValuePairs};
use crate::traits::ObligationCauseCode::CompareImplItemObligation;
-use rustc_errors::{ErrorGuaranteed, MultiSpan};
+use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::RegionHighlightMode;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_span::Span;
@@ -22,22 +24,27 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let error = self.error.as_ref()?;
debug!("try_report_impl_not_conforming_to_trait {:?}", error);
if let RegionResolutionError::SubSupConflict(
- _,
- var_origin,
- sub_origin,
- _sub,
- sup_origin,
- _sup,
- _,
- ) = error.clone()
+ _,
+ var_origin,
+ sub_origin,
+ _sub,
+ sup_origin,
+ _sup,
+ _,
+ ) = error.clone()
&& let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
- && let sub_expected_found @ Some((sub_expected, sub_found)) = sub_trace.values.ty()
- && let sup_expected_found @ Some(_) = sup_trace.values.ty()
&& let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
- && sup_expected_found == sub_expected_found
+ && sub_trace.values == sup_trace.values
+ && let ValuePairs::Sigs(ExpectedFound { expected, found }) = sub_trace.values
{
- let guar =
- self.emit_err(var_origin.span(), sub_expected, sub_found, *trait_item_def_id);
+ // FIXME(compiler-errors): Don't like that this needs `Ty`s, but
+ // all of the region highlighting machinery only deals with those.
+ let guar = self.emit_err(
+ var_origin.span(),
+ self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(expected)),
+ self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(found)),
+ *trait_item_def_id,
+ );
return Some(guar);
}
None
@@ -51,10 +58,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
trait_def_id: DefId,
) -> ErrorGuaranteed {
let trait_sp = self.tcx().def_span(trait_def_id);
- let mut err = self
- .tcx()
- .sess
- .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
// Mark all unnamed regions in the type with a number.
// This diagnostic is called in response to lifetime errors, so be informative.
@@ -91,9 +94,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let found =
self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
- err.span_label(sp, &format!("found `{}`", found));
- err.span_label(trait_sp, &format!("expected `{}`", expected));
-
// Get the span of all the used type parameters in the method.
let assoc_item = self.tcx().associated_item(trait_def_id);
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
@@ -110,26 +110,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
_ => {}
}
- let mut type_param_span: MultiSpan = visitor.types.to_vec().into();
- for &span in &visitor.types {
- type_param_span
- .push_span_label(span, "consider borrowing this type parameter in the trait");
- }
- err.note(&format!("expected `{}`\n found `{}`", expected, found));
-
- err.span_help(
- type_param_span,
- "the lifetime requirements from the `impl` do not correspond to the requirements in \
- the `trait`",
- );
- if visitor.types.is_empty() {
- err.help(
- "verify the lifetime relationships in the `trait` and `impl` between the `self` \
- argument, the other inputs and its output",
- );
- }
- err.emit()
+ let diag = TraitImplDiff {
+ sp,
+ trait_sp,
+ note: (),
+ param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() },
+ rel_help: visitor.types.is_empty().then_some(RelationshipHelp),
+ expected,
+ found,
+ };
+
+ self.tcx().sess.emit_err(diag)
}
}
@@ -147,7 +139,7 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
match arg.kind {
- hir::TyKind::Rptr(_, ref mut_ty) => {
+ hir::TyKind::Ref(_, ref mut_ty) => {
// We don't want to suggest looking into borrowing `&T` or `&Self`.
hir::intravisit::walk_ty(self, mut_ty.ty);
return;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index d2dffa4a0..b18cbd404 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -2,11 +2,14 @@ use crate::errors::RegionOriginNote;
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
use crate::infer::{self, SubregionOrigin};
use rustc_errors::{
- fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+ fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder,
+ ErrorGuaranteed,
};
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, Region};
+use rustc_middle::ty::{self, IsSuggestable, Region};
+use rustc_span::symbol::kw;
use super::ObligationCauseAsDiagArg;
@@ -22,29 +25,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
infer::Reborrow(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
}
- infer::ReborrowUpvar(span, ref upvar_id) => {
- let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_reborrow,
- name: &var_name.to_string(),
- continues: false,
- }
- .add_to_diagnostic(err);
- }
infer::RelateObjectBound(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
.add_to_diagnostic(err);
}
- infer::DataBorrowed(ty, span) => {
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_data_borrowed,
- name: &self.ty_to_string(ty),
- continues: false,
- }
- .add_to_diagnostic(err);
- }
infer::ReferenceOutlivesReferent(ty, span) => {
RegionOriginNote::WithName {
span,
@@ -159,33 +143,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
);
err
}
- infer::ReborrowUpvar(span, ref upvar_id) => {
- let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0313,
- "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
- var_name
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...the borrowed pointer is valid for ",
- sub,
- "...",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- &format!("...but `{}` is only valid for ", var_name),
- sup,
- "",
- None,
- );
- err
- }
infer::RelateObjectBound(span) => {
let mut err = struct_span_err!(
self.tcx.sess,
@@ -261,32 +218,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
);
err
}
- infer::DataBorrowed(ty, span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0490,
- "a value of type `{}` is borrowed for too long",
- self.ty_to_string(ty)
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "the type is valid for ",
- sub,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "but the borrow lasts for ",
- sup,
- "",
- None,
- );
- err
- }
infer::ReferenceOutlivesReferent(ty, span) => {
let mut err = struct_span_err!(
self.tcx.sess,
@@ -313,55 +244,38 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
);
err
}
- infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
- .report_extra_impl_obligation(
+ infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
+ let mut err = self.report_extra_impl_obligation(
span,
impl_item_def_id,
trait_item_def_id,
&format!("`{}: {}`", sup, sub),
- ),
+ );
+ // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
+ if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
+ && generics.where_clause_span.contains(span)
+ {
+ self.suggest_copy_trait_method_bounds(
+ trait_item_def_id,
+ impl_item_def_id,
+ &mut err,
+ );
+ }
+ err
+ }
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
let mut err = self.report_concrete_failure(*parent, sub, sup);
-
let trait_item_span = self.tcx.def_span(trait_item_def_id);
let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
err.span_label(
trait_item_span,
format!("definition of `{}` from trait", item_name),
);
-
- let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
- let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
-
- let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
- impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
- let clauses: Vec<_> = trait_predicates
- .predicates
- .into_iter()
- .filter(|&(pred, _)| !impl_predicates.contains(pred))
- .map(|(pred, _)| format!("{}", pred))
- .collect();
-
- if !clauses.is_empty() {
- let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
- let where_clause_span = generics.tail_span_for_predicate_suggestion();
-
- let suggestion = format!(
- "{} {}",
- generics.add_where_or_trailing_comma(),
- clauses.join(", "),
- );
- err.span_suggestion(
- where_clause_span,
- &format!(
- "try copying {} from the trait",
- if clauses.len() > 1 { "these clauses" } else { "this clause" }
- ),
- suggestion,
- rustc_errors::Applicability::MaybeIncorrect,
- );
- }
-
+ self.suggest_copy_trait_method_bounds(
+ trait_item_def_id,
+ impl_item_def_id,
+ &mut err,
+ );
err
}
infer::AscribeUserTypeProvePredicate(span) => {
@@ -388,6 +302,65 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
+ pub fn suggest_copy_trait_method_bounds(
+ &self,
+ trait_item_def_id: DefId,
+ impl_item_def_id: LocalDefId,
+ err: &mut Diagnostic,
+ ) {
+ // FIXME(compiler-errors): Right now this is only being used for region
+ // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
+ // but right now it's not really very smart when it comes to implicit `Sized`
+ // predicates and bounds on the trait itself.
+
+ let Some(impl_def_id) =
+ self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) else { return; };
+ let Some(trait_ref) = self
+ .tcx
+ .impl_trait_ref(impl_def_id)
+ else { return; };
+ let trait_substs = trait_ref
+ .subst_identity()
+ // Replace the explicit self type with `Self` for better suggestion rendering
+ .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
+ .substs;
+ let trait_item_substs =
+ ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id())
+ .rebase_onto(self.tcx, impl_def_id, trait_substs);
+
+ let Ok(trait_predicates) = self
+ .tcx
+ .explicit_predicates_of(trait_item_def_id)
+ .instantiate_own(self.tcx, trait_item_substs)
+ .map(|(pred, _)| {
+ if pred.is_suggestable(self.tcx, false) {
+ Ok(pred.to_string())
+ } else {
+ Err(())
+ }
+ })
+ .collect::<Result<Vec<_>, ()>>() else { return; };
+
+ let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; };
+
+ if trait_predicates.is_empty() {
+ err.span_suggestion_verbose(
+ generics.where_clause_span,
+ "remove the `where` clause",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ let space = if generics.where_clause_span.is_empty() { " " } else { "" };
+ err.span_suggestion_verbose(
+ generics.where_clause_span,
+ "copy the `where` clause predicates from the trait",
+ format!("{space}where {}", trait_predicates.join(", ")),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
pub(super) fn report_placeholder_failure(
&self,
placeholder_origin: SubregionOrigin<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_region.rs b/compiler/rustc_infer/src/infer/error_reporting/note_region.rs
deleted file mode 100644
index 41b115f33..000000000
--- a/compiler/rustc_infer/src/infer/error_reporting/note_region.rs
+++ /dev/null
@@ -1,427 +0,0 @@
-use crate::errors::RegionOriginNote;
-use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
-use crate::infer::{self, SubregionOrigin};
-use rustc_errors::{
- fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-};
-use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, Region};
-
-use super::ObligationCauseAsDiagArg;
-
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
- pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
- match *origin {
- infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
- span: trace.cause.span,
- requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
- expected_found: self.values_str(trace.values),
- }
- .add_to_diagnostic(err),
- infer::Reborrow(span) => {
- RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
- }
- infer::ReborrowUpvar(span, ref upvar_id) => {
- let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_reborrow,
- name: &var_name.to_string(),
- continues: false,
- }
- .add_to_diagnostic(err);
- }
- infer::RelateObjectBound(span) => {
- RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
- .add_to_diagnostic(err);
- }
- infer::DataBorrowed(ty, span) => {
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_data_borrowed,
- name: &self.ty_to_string(ty),
- continues: false,
- }
- .add_to_diagnostic(err);
- }
- infer::ReferenceOutlivesReferent(ty, span) => {
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_reference_outlives_referent,
- name: &self.ty_to_string(ty),
- continues: false,
- }
- .add_to_diagnostic(err);
- }
- infer::RelateParamBound(span, ty, opt_span) => {
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_relate_param_bound,
- name: &self.ty_to_string(ty),
- continues: opt_span.is_some(),
- }
- .add_to_diagnostic(err);
- if let Some(span) = opt_span {
- RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
- .add_to_diagnostic(err);
- }
- }
- infer::RelateRegionParamBound(span) => {
- RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
- .add_to_diagnostic(err);
- }
- infer::CompareImplItemObligation { span, .. } => {
- RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
- .add_to_diagnostic(err);
- }
- infer::CheckAssociatedTypeBounds { ref parent, .. } => {
- self.note_region_origin(err, &parent);
- }
- infer::AscribeUserTypeProvePredicate(span) => {
- RegionOriginNote::Plain {
- span,
- msg: fluent::infer_ascribe_user_type_prove_predicate,
- }
- .add_to_diagnostic(err);
- }
- }
- }
-
- pub(super) fn report_concrete_failure(
- &self,
- origin: SubregionOrigin<'tcx>,
- sub: Region<'tcx>,
- sup: Region<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- match origin {
- infer::Subtype(box trace) => {
- let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
- let mut err = self.report_and_explain_type_error(trace, terr);
- match (*sub, *sup) {
- (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
- (ty::RePlaceholder(_), _) => {
- note_and_explain_region(
- self.tcx,
- &mut err,
- "",
- sup,
- " doesn't meet the lifetime requirements",
- None,
- );
- }
- (_, ty::RePlaceholder(_)) => {
- note_and_explain_region(
- self.tcx,
- &mut err,
- "the required lifetime does not necessarily outlive ",
- sub,
- "",
- None,
- );
- }
- _ => {
- note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...does not necessarily outlive ",
- sub,
- "",
- None,
- );
- }
- }
- err
- }
- infer::Reborrow(span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0312,
- "lifetime of reference outlives lifetime of borrowed content..."
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...the reference is valid for ",
- sub,
- "...",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...but the borrowed content is only valid for ",
- sup,
- "",
- None,
- );
- err
- }
- infer::ReborrowUpvar(span, ref upvar_id) => {
- let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0313,
- "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
- var_name
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...the borrowed pointer is valid for ",
- sub,
- "...",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- &format!("...but `{}` is only valid for ", var_name),
- sup,
- "",
- None,
- );
- err
- }
- infer::RelateObjectBound(span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0476,
- "lifetime of the source pointer does not outlive lifetime bound of the \
- object type"
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "object type is valid for ",
- sub,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "source pointer is only valid for ",
- sup,
- "",
- None,
- );
- err
- }
- infer::RelateParamBound(span, ty, opt_span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0477,
- "the type `{}` does not fulfill the required lifetime",
- self.ty_to_string(ty)
- );
- match *sub {
- ty::ReStatic => note_and_explain_region(
- self.tcx,
- &mut err,
- "type must satisfy ",
- sub,
- if opt_span.is_some() { " as required by this binding" } else { "" },
- opt_span,
- ),
- _ => note_and_explain_region(
- self.tcx,
- &mut err,
- "type must outlive ",
- sub,
- if opt_span.is_some() { " as required by this binding" } else { "" },
- opt_span,
- ),
- }
- err
- }
- infer::RelateRegionParamBound(span) => {
- let mut err =
- struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
- note_and_explain_region(
- self.tcx,
- &mut err,
- "lifetime parameter instantiated with ",
- sup,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "but lifetime parameter must outlive ",
- sub,
- "",
- None,
- );
- err
- }
- infer::DataBorrowed(ty, span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0490,
- "a value of type `{}` is borrowed for too long",
- self.ty_to_string(ty)
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "the type is valid for ",
- sub,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "but the borrow lasts for ",
- sup,
- "",
- None,
- );
- err
- }
- infer::ReferenceOutlivesReferent(ty, span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0491,
- "in type `{}`, reference has a longer lifetime than the data it references",
- self.ty_to_string(ty)
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "the pointer is valid for ",
- sub,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "but the referenced data is only valid for ",
- sup,
- "",
- None,
- );
- err
- }
- infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
- .report_extra_impl_obligation(
- span,
- impl_item_def_id,
- trait_item_def_id,
- &format!("`{}: {}`", sup, sub),
- ),
- infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
- let mut err = self.report_concrete_failure(*parent, sub, sup);
-
- let trait_item_span = self.tcx.def_span(trait_item_def_id);
- let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
- err.span_label(
- trait_item_span,
- format!("definition of `{}` from trait", item_name),
- );
-
- let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
- let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
-
- let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
- impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
- let clauses: Vec<_> = trait_predicates
- .predicates
- .into_iter()
- .filter(|&(pred, _)| !impl_predicates.contains(pred))
- .map(|(pred, _)| format!("{}", pred))
- .collect();
-
- if !clauses.is_empty() {
- let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
- let where_clause_span = generics.tail_span_for_predicate_suggestion();
-
- let suggestion = format!(
- "{} {}",
- generics.add_where_or_trailing_comma(),
- clauses.join(", "),
- );
- err.span_suggestion(
- where_clause_span,
- &format!(
- "try copying {} from the trait",
- if clauses.len() > 1 { "these clauses" } else { "this clause" }
- ),
- suggestion,
- rustc_errors::Applicability::MaybeIncorrect,
- );
- }
-
- err
- }
- infer::AscribeUserTypeProvePredicate(span) => {
- let mut err =
- struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
- note_and_explain_region(
- self.tcx,
- &mut err,
- "lifetime instantiated with ",
- sup,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "but lifetime must outlive ",
- sub,
- "",
- None,
- );
- err
- }
- }
- }
-
- pub(super) fn report_placeholder_failure(
- &self,
- placeholder_origin: SubregionOrigin<'tcx>,
- sub: Region<'tcx>,
- sup: Region<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- // I can't think how to do better than this right now. -nikomatsakis
- debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
- match placeholder_origin {
- infer::Subtype(box ref trace)
- if matches!(
- &trace.cause.code().peel_derives(),
- ObligationCauseCode::BindingObligation(..)
- | ObligationCauseCode::ExprBindingObligation(..)
- ) =>
- {
- // Hack to get around the borrow checker because trace.cause has an `Rc`.
- if let ObligationCauseCode::BindingObligation(_, span)
- | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
- &trace.cause.code().peel_derives()
- {
- let span = *span;
- let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
- err.span_note(span, "the lifetime requirement is introduced here");
- err
- } else {
- unreachable!()
- }
- }
- infer::Subtype(box trace) => {
- let terr = TypeError::RegionsPlaceholderMismatch;
- return self.report_and_explain_type_error(trace, terr);
- }
- _ => return self.report_concrete_failure(placeholder_origin, sub, sup),
- }
- }
-}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 73b5a2cc4..5b02956a1 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -411,7 +411,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
span: Span,
) {
let hir = self.tcx.hir();
- let fn_hir_id = hir.get_parent_node(cause.body_id);
+ let fn_hir_id = hir.parent_id(cause.body_id);
if let Some(node) = self.tcx.hir().find(fn_hir_id) &&
let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(_sig, _, body_id), ..
@@ -486,12 +486,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
_ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => {
StatementAsExpression::CorrectType
}
- (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _))
- if last_def_id == exp_def_id =>
- {
- StatementAsExpression::CorrectType
- }
- (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
+ (
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, .. }),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, .. }),
+ ) if last_def_id == exp_def_id => StatementAsExpression::CorrectType,
+ (
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, substs: last_bounds, .. }),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, substs: exp_bounds, .. }),
+ ) => {
debug!(
"both opaque, likely future {:?} {:?} {:?} {:?}",
last_def_id, last_bounds, exp_def_id, exp_bounds
@@ -583,45 +585,42 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let hir::StmtKind::Local(local) = &stmt.kind else { continue; };
local.pat.walk(&mut find_compatible_candidates);
}
- match hir.find(hir.get_parent_node(blk.hir_id)) {
- Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => {
- match hir.find(hir.get_parent_node(*hir_id)) {
- Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
- pat.walk(&mut find_compatible_candidates);
- }
- Some(
- hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
- | hir::Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Fn(_, body),
- ..
- })
- | hir::Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
- ..
- })
- | hir::Node::Expr(hir::Expr {
- kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
- ..
- }),
- ) => {
- for param in hir.body(*body).params {
- param.pat.walk(&mut find_compatible_candidates);
- }
- }
- Some(hir::Node::Expr(hir::Expr {
- kind:
- hir::ExprKind::If(
- hir::Expr { kind: hir::ExprKind::Let(let_), .. },
- then_block,
- _,
- ),
+ match hir.find_parent(blk.hir_id) {
+ Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => match hir.find_parent(*hir_id) {
+ Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
+ pat.walk(&mut find_compatible_candidates);
+ }
+ Some(
+ hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
+ | hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(_, body), ..
+ })
+ | hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
..
- })) if then_block.hir_id == *hir_id => {
- let_.pat.walk(&mut find_compatible_candidates);
+ })
+ | hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
+ ..
+ }),
+ ) => {
+ for param in hir.body(*body).params {
+ param.pat.walk(&mut find_compatible_candidates);
}
- _ => {}
}
- }
+ Some(hir::Node::Expr(hir::Expr {
+ kind:
+ hir::ExprKind::If(
+ hir::Expr { kind: hir::ExprKind::Let(let_), .. },
+ then_block,
+ _,
+ ),
+ ..
+ })) if then_block.hir_id == *hir_id => {
+ let_.pat.walk(&mut find_compatible_candidates);
+ }
+ _ => {}
+ },
_ => {}
}
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index f6946929b..8f53b1ccd 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -205,12 +205,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
| ty::Dynamic(..)
| ty::Never
| ty::Tuple(..)
- | ty::Projection(..)
+ | ty::Alias(..)
| ty::Foreign(..)
| ty::Param(..)
| ty::Closure(..)
- | ty::GeneratorWitness(..)
- | ty::Opaque(..) => t.super_fold_with(self),
+ | ty::GeneratorWitness(..) => t.super_fold_with(self),
ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t),
}
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 7f27b35a5..21b68ce99 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -103,6 +103,11 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
where
T: Relate<'tcx>,
{
+ // GLB of a binder and itself is just itself
+ if a == b {
+ return Ok(a);
+ }
+
debug!("binders(a={:?}, b={:?})", a, b);
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
// When higher-ranked types are involved, computing the GLB is
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index eba65361a..4dbb4b4d7 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -78,7 +78,7 @@ where
//
// Example: if the LHS is a type variable, and RHS is
// `Box<i32>`, then we current compare `v` to the RHS first,
- // which will instantiate `v` with `Box<i32>`. Then when `v`
+ // which will instantiate `v` with `Box<i32>`. Then when `v`
// is compared to the LHS, we instantiate LHS with `Box<i32>`.
// But if we did in reverse order, we would create a `v <:
// LHS` (or vice versa) constraint and then instantiate
@@ -105,11 +105,13 @@ where
Ok(v)
}
- (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
- infcx.super_combine_tys(this, a, b)
- }
- (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
- if this.define_opaque_types() && did.is_local() =>
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+ ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+ if this.define_opaque_types() && def_id.is_local() =>
{
this.add_obligations(
infcx
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index ba990acfe..ce8aec804 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -52,7 +52,7 @@ pub struct LexicalRegionResolutions<'tcx> {
#[derive(Copy, Clone, Debug)]
pub(crate) enum VarValue<'tcx> {
- /// Empty lifetime is for data that is never accessed. We tag the
+ /// Empty lifetime is for data that is never accessed. We tag the
/// empty lifetime with a universe -- the idea is that we don't
/// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable.
/// Therefore, the `'empty` in a universe `U` is less than all
@@ -251,7 +251,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
VarValue::Empty(a_universe) => {
let b_data = var_values.value_mut(b_vid);
- let changed = (|| match *b_data {
+ let changed = match *b_data {
VarValue::Empty(b_universe) => {
// Empty regions are ordered according to the universe
// they are associated with.
@@ -280,20 +280,20 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
};
if lub == cur_region {
- return false;
+ false
+ } else {
+ debug!(
+ "Expanding value of {:?} from {:?} to {:?}",
+ b_vid, cur_region, lub
+ );
+
+ *b_data = VarValue::Value(lub);
+ true
}
-
- debug!(
- "Expanding value of {:?} from {:?} to {:?}",
- b_vid, cur_region, lub
- );
-
- *b_data = VarValue::Value(lub);
- true
}
VarValue::ErrorValue => false,
- })();
+ };
if changed {
changes.push(b_vid);
@@ -488,7 +488,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// If this empty region is from a universe that can
// name the placeholder, then the placeholder is
// larger; otherwise, the only ancestor is `'static`.
- if a_ui.can_name(placeholder.universe) { true } else { false }
+ return a_ui.can_name(placeholder.universe);
}
}
}
@@ -510,7 +510,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
// If both `a` and `b` are free, consult the declared
- // relationships. Note that this can be more precise than the
+ // relationships. Note that this can be more precise than the
// `lub` relationship defined below, since sometimes the "lub"
// is actually the `postdom_upper_bound` (see
// `TransitiveRelation` for more details).
@@ -665,7 +665,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// conflicting regions to report to the user. As we walk, we
// trip the flags from false to true, and if we find that
// we've already reported an error involving any particular
- // node we just stop and don't report the current error. The
+ // node we just stop and don't report the current error. The
// idea is to report errors that derive from independent
// regions of the graph, but not those that derive from
// overlapping locations.
@@ -702,26 +702,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// Obtain the spans for all the places that can
// influence the constraints on this value for
// richer diagnostics in `static_impl_trait`.
- let influences: Vec<Span> = self
- .data
- .constraints
- .iter()
- .filter_map(|(constraint, origin)| match (constraint, origin) {
- (
- Constraint::VarSubVar(_, sup),
- SubregionOrigin::DataBorrowed(_, sp),
- ) if sup == &node_vid => Some(*sp),
- _ => None,
- })
- .collect();
-
- self.collect_error_for_expanding_node(
- graph,
- &mut dup_vec,
- node_vid,
- errors,
- influences,
- );
+
+ self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
}
}
}
@@ -775,7 +757,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>,
node_idx: RegionVid,
errors: &mut Vec<RegionResolutionError<'tcx>>,
- influences: Vec<Span>,
) {
// Errors in expanding nodes result from a lower-bound that is
// not contained by an upper-bound.
@@ -830,7 +811,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
lower_bound.region,
upper_bound.origin.clone(),
upper_bound.region,
- influences,
+ vec![],
));
return;
}
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index 97ed4729b..c07ac1d3a 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -103,6 +103,11 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
where
T: Relate<'tcx>,
{
+ // LUB of a binder and itself is just itself
+ if a == b {
+ return Ok(a);
+ }
+
debug!("binders(a={:?}, b={:?})", a, b);
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
// When higher-ranked types are involved, computing the LUB is
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 706cd4124..f0e42c1fc 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -361,6 +361,7 @@ pub enum ValuePairs<'tcx> {
Terms(ExpectedFound<ty::Term<'tcx>>),
TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
+ Sigs(ExpectedFound<ty::FnSig<'tcx>>),
}
impl<'tcx> ValuePairs<'tcx> {
@@ -409,12 +410,6 @@ pub enum SubregionOrigin<'tcx> {
/// Creating a pointer `b` to contents of another reference
Reborrow(Span),
- /// Creating a pointer `b` to contents of an upvar
- ReborrowUpvar(Span, ty::UpvarId),
-
- /// Data with type `Ty<'tcx>` was borrowed
- DataBorrowed(Ty<'tcx>, Span),
-
/// (&'a &'b T) where a >= b
ReferenceOutlivesReferent(Ty<'tcx>, Span),
@@ -690,6 +685,10 @@ impl<'tcx> InferCtxt<'tcx> {
typeck_results: None,
fallback_has_occurred: false,
normalize_fn_sig: Box::new(|fn_sig| fn_sig),
+ autoderef_steps: Box::new(|ty| {
+ debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck");
+ vec![(ty, vec![])]
+ }),
}
}
@@ -1106,7 +1105,7 @@ impl<'tcx> InferCtxt<'tcx> {
self.tcx.mk_region(ty::ReVar(region_var))
}
- /// Return the universe that the region `r` was created in. For
+ /// Return the universe that the region `r` was created in. For
/// most regions (e.g., `'static`, named regions from the user,
/// etc) this is the root universe U0. For inference variables or
/// placeholders, however, it will return the universe which they
@@ -1340,6 +1339,12 @@ impl<'tcx> InferCtxt<'tcx> {
var_infos
}
+ #[instrument(level = "debug", skip(self), ret)]
+ pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
+ debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error);
+ std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
+ }
+
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
self.resolve_vars_if_possible(t).to_string()
}
@@ -1356,7 +1361,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
/// Resolve any type variables found in `value` -- but only one
- /// level. So, if the variable `?X` is bound to some type
+ /// level. So, if the variable `?X` is bound to some type
/// `Foo<?Y>`, then this would return `Foo<?Y>` (but `?Y` may
/// itself be bound to a type).
///
@@ -1681,33 +1686,54 @@ impl<'tcx> InferCtxt<'tcx> {
}
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+ /// Processes registered region obliations and resolves regions, reporting
+ /// any errors if any were raised. Prefer using this function over manually
+ /// calling `resolve_regions_and_report_errors`.
+ pub fn check_region_obligations_and_report_errors(
+ &self,
+ generic_param_scope: LocalDefId,
+ outlives_env: &OutlivesEnvironment<'tcx>,
+ ) -> Result<(), ErrorGuaranteed> {
+ self.process_registered_region_obligations(
+ outlives_env.region_bound_pairs(),
+ outlives_env.param_env,
+ );
+
+ self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
+ }
+
/// Process the region constraints and report any errors that
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_vars_if_possible` as well as `fully_resolve`.
///
/// Make sure to call [`InferCtxt::process_registered_region_obligations`]
- /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
+ /// first, or preferably use [`TypeErrCtxt::check_region_obligations_and_report_errors`]
/// to do both of these operations together.
pub fn resolve_regions_and_report_errors(
&self,
generic_param_scope: LocalDefId,
outlives_env: &OutlivesEnvironment<'tcx>,
- ) -> Option<ErrorGuaranteed> {
+ ) -> Result<(), ErrorGuaranteed> {
let errors = self.resolve_regions(outlives_env);
if let None = self.tainted_by_errors() {
// As a heuristic, just skip reporting region errors
// altogether if other errors have been reported while
- // this infcx was in use. This is totally hokey but
+ // this infcx was in use. This is totally hokey but
// otherwise we have a hard time separating legit region
// errors from silly ones.
self.report_region_errors(generic_param_scope, &errors);
}
- (!errors.is_empty()).then(|| {
- self.tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted")
- })
+ if errors.is_empty() {
+ Ok(())
+ } else {
+ Err(self
+ .tcx
+ .sess
+ .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"))
+ }
}
// [Note-Type-error-reporting]
@@ -1924,7 +1950,7 @@ impl<'tcx> TypeTrace<'tcx> {
) -> TypeTrace<'tcx> {
TypeTrace {
cause: cause.clone(),
- values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+ values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)),
}
}
@@ -1949,8 +1975,6 @@ impl<'tcx> SubregionOrigin<'tcx> {
RelateParamBound(a, ..) => a,
RelateRegionParamBound(a) => a,
Reborrow(a) => a,
- ReborrowUpvar(a, _) => a,
- DataBorrowed(_, a) => a,
ReferenceOutlivesReferent(_, a) => a,
CompareImplItemObligation { span, .. } => span,
AscribeUserTypeProvePredicate(span) => span,
@@ -2018,31 +2042,54 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>,
) -> SubstsRef<'tcx> {
- tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| {
- match arg.unpack() {
- GenericArgKind::Type(_) if arg.has_non_region_param() || arg.has_non_region_infer() => {
- tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
+ struct ReplaceParamAndInferWithPlaceholder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ idx: usize,
+ }
+
+ impl<'tcx> TypeFolder<'tcx> for ReplaceParamAndInferWithPlaceholder<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ if let ty::Infer(_) = t.kind() {
+ self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::ROOT,
- name: ty::BoundVar::from_usize(idx),
+ name: ty::BoundVar::from_usize({
+ let idx = self.idx;
+ self.idx += 1;
+ idx
+ }),
}))
- .into()
+ } else {
+ t.super_fold_with(self)
}
- GenericArgKind::Const(ct) if ct.has_non_region_infer() || ct.has_non_region_param() => {
- let ty = ct.ty();
- // If the type references param or infer, replace that too...
+ }
+
+ fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ if let ty::ConstKind::Infer(_) = c.kind() {
+ let ty = c.ty();
+ // If the type references param or infer then ICE ICE ICE
if ty.has_non_region_param() || ty.has_non_region_infer() {
- bug!("const `{ct}`'s type should not reference params or types");
+ bug!("const `{c}`'s type should not reference params or types");
}
- tcx.mk_const(
+ self.tcx.mk_const(
ty::PlaceholderConst {
universe: ty::UniverseIndex::ROOT,
- name: ty::BoundVar::from_usize(idx),
+ name: ty::BoundVar::from_usize({
+ let idx = self.idx;
+ self.idx += 1;
+ idx
+ }),
},
ty,
)
- .into()
+ } else {
+ c.super_fold_with(self)
}
- _ => arg,
}
- }))
+ }
+
+ substs.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 })
}
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index f6bc4db0d..f235cb5ab 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -275,13 +275,13 @@ where
/// `ProjectionEq(projection = ?U)`, `ProjectionEq(other_projection = ?U)`.
fn relate_projection_ty(
&mut self,
- projection_ty: ty::ProjectionTy<'tcx>,
+ projection_ty: ty::AliasTy<'tcx>,
value_ty: Ty<'tcx>,
) -> Ty<'tcx> {
use rustc_span::DUMMY_SP;
match *value_ty.kind() {
- ty::Projection(other_projection_ty) => {
+ ty::Alias(ty::Projection, other_projection_ty) => {
let var = self.infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: DUMMY_SP,
@@ -335,7 +335,9 @@ where
return Ok(value_ty);
}
- ty::Projection(projection_ty) if D::normalization() == NormalizationStrategy::Lazy => {
+ ty::Alias(ty::Projection, projection_ty)
+ if D::normalization() == NormalizationStrategy::Lazy =>
+ {
return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_ty_var(vid)));
}
@@ -406,8 +408,8 @@ where
}
};
let (a, b) = match (a.kind(), b.kind()) {
- (&ty::Opaque(..), _) => (a, generalize(b, false)?),
- (_, &ty::Opaque(..)) => (generalize(a, true)?, b),
+ (&ty::Alias(ty::Opaque, ..), _) => (a, generalize(b, false)?),
+ (_, &ty::Alias(ty::Opaque, ..)) => (generalize(a, true)?, b),
_ => unreachable!(),
};
let cause = ObligationCause::dummy_with_span(self.delegate.span());
@@ -437,7 +439,7 @@ trait VidValuePair<'tcx>: Debug {
fn value_ty(&self) -> Ty<'tcx>;
/// Extract the scopes that apply to whichever side of the tuple
- /// the vid was found on. See the comment where this is called
+ /// the vid was found on. See the comment where this is called
/// for more details on why we want them.
fn vid_scopes<'r, D: TypeRelatingDelegate<'tcx>>(
&self,
@@ -608,26 +610,30 @@ where
(&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
- (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
- infcx.super_combine_tys(self, a, b).or_else(|err| {
- self.tcx().sess.delay_span_bug(
- self.delegate.span(),
- "failure to relate an opaque to itself should result in an error later on",
- );
- if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
- })
- }
- (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => {
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+ ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b).or_else(|err| {
+ self.tcx().sess.delay_span_bug(
+ self.delegate.span(),
+ "failure to relate an opaque to itself should result in an error later on",
+ );
+ if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
+ }),
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+ if def_id.is_local() =>
+ {
self.relate_opaques(a, b)
}
- (&ty::Projection(projection_ty), _)
+ (&ty::Alias(ty::Projection, projection_ty), _)
if D::normalization() == NormalizationStrategy::Lazy =>
{
Ok(self.relate_projection_ty(projection_ty, b))
}
- (_, &ty::Projection(projection_ty))
+ (_, &ty::Alias(ty::Projection, projection_ty))
if D::normalization() == NormalizationStrategy::Lazy =>
{
Ok(self.relate_projection_ty(projection_ty, a))
@@ -825,7 +831,7 @@ where
/// (these are not explicitly present in the ty representation right
/// now). This visitor handles that: it descends the type, tracking
/// binder depth, and finds late-bound regions targeting the
-/// `for<..`>. For each of those, it creates an entry in
+/// `for<..`>. For each of those, it creates an entry in
/// `bound_region_scope`.
struct ScopeInstantiator<'me, 'tcx> {
next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
@@ -843,7 +849,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
t.super_visit_with(self);
self.target_index.shift_out(1);
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -857,7 +863,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
_ => {}
}
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
}
diff --git a/compiler/rustc_infer/src/infer/note.rs b/compiler/rustc_infer/src/infer/note.rs
deleted file mode 100644
index 2ccbd164f..000000000
--- a/compiler/rustc_infer/src/infer/note.rs
+++ /dev/null
@@ -1,203 +0,0 @@
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
- fn note_error_origin(
- &self,
- err: &mut Diagnostic,
- cause: &ObligationCause<'tcx>,
- exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
- terr: TypeError<'tcx>,
- ) {
- match *cause.code() {
- ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
- let ty = self.resolve_vars_if_possible(root_ty);
- if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)))
- {
- // don't show type `_`
- if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
- && let ty::Adt(def, substs) = ty.kind()
- && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
- {
- err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
- } else {
- err.span_label(span, format!("this expression has type `{}`", ty));
- }
- }
- if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
- && ty.is_box() && ty.boxed_ty() == found
- && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
- {
- err.span_suggestion(
- span,
- "consider dereferencing the boxed value",
- format!("*{}", snippet),
- Applicability::MachineApplicable,
- );
- }
- }
- ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => {
- err.span_label(span, "expected due to this");
- }
- ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
- arm_block_id,
- arm_span,
- arm_ty,
- prior_arm_block_id,
- prior_arm_span,
- prior_arm_ty,
- source,
- ref prior_arms,
- scrut_hir_id,
- opt_suggest_box_span,
- scrut_span,
- ..
- }) => match source {
- hir::MatchSource::TryDesugar => {
- if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
- let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
- let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
- let arg_expr = args.first().expect("try desugaring call w/out arg");
- self.typeck_results.as_ref().and_then(|typeck_results| {
- typeck_results.expr_ty_opt(arg_expr)
- })
- } else {
- bug!("try desugaring w/out call expr as scrutinee");
- };
-
- match scrut_ty {
- Some(ty) if expected == ty => {
- let source_map = self.tcx.sess.source_map();
- err.span_suggestion(
- source_map.end_point(cause.span),
- "try removing this `?`",
- "",
- Applicability::MachineApplicable,
- );
- }
- _ => {}
- }
- }
- }
- _ => {
- // `prior_arm_ty` can be `!`, `expected` will have better info when present.
- let t = self.resolve_vars_if_possible(match exp_found {
- Some(ty::error::ExpectedFound { expected, .. }) => expected,
- _ => prior_arm_ty,
- });
- let source_map = self.tcx.sess.source_map();
- let mut any_multiline_arm = source_map.is_multiline(arm_span);
- if prior_arms.len() <= 4 {
- for sp in prior_arms {
- any_multiline_arm |= source_map.is_multiline(*sp);
- err.span_label(*sp, format!("this is found to be of type `{}`", t));
- }
- } else if let Some(sp) = prior_arms.last() {
- any_multiline_arm |= source_map.is_multiline(*sp);
- err.span_label(
- *sp,
- format!("this and all prior arms are found to be of type `{}`", t),
- );
- }
- let outer_error_span = if any_multiline_arm {
- // Cover just `match` and the scrutinee expression, not
- // the entire match body, to reduce diagram noise.
- cause.span.shrink_to_lo().to(scrut_span)
- } else {
- cause.span
- };
- let msg = "`match` arms have incompatible types";
- err.span_label(outer_error_span, msg);
- self.suggest_remove_semi_or_return_binding(
- err,
- prior_arm_block_id,
- prior_arm_ty,
- prior_arm_span,
- arm_block_id,
- arm_ty,
- arm_span,
- );
- if let Some(ret_sp) = opt_suggest_box_span {
- // Get return type span and point to it.
- self.suggest_boxing_for_return_impl_trait(
- err,
- ret_sp,
- prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
- );
- }
- }
- },
- ObligationCauseCode::IfExpression(box IfExpressionCause {
- then_id,
- else_id,
- then_ty,
- else_ty,
- outer_span,
- opt_suggest_box_span,
- }) => {
- let then_span = self.find_block_span_from_hir_id(then_id);
- let else_span = self.find_block_span_from_hir_id(else_id);
- err.span_label(then_span, "expected because of this");
- if let Some(sp) = outer_span {
- err.span_label(sp, "`if` and `else` have incompatible types");
- }
- self.suggest_remove_semi_or_return_binding(
- err,
- Some(then_id),
- then_ty,
- then_span,
- Some(else_id),
- else_ty,
- else_span,
- );
- if let Some(ret_sp) = opt_suggest_box_span {
- self.suggest_boxing_for_return_impl_trait(
- err,
- ret_sp,
- [then_span, else_span].into_iter(),
- );
- }
- }
- ObligationCauseCode::LetElse => {
- err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
- err.help("...or use `match` instead of `let...else`");
- }
- _ => {
- if let ObligationCauseCode::BindingObligation(_, span)
- | ObligationCauseCode::ExprBindingObligation(_, span, ..)
- = cause.code().peel_derives()
- && let TypeError::RegionsPlaceholderMismatch = terr
- {
- err.span_note( * span,
- "the lifetime requirement is introduced here");
- }
- }
- }
- }
-}
-
-impl<'tcx> InferCtxt<'tcx> {
- /// Given a [`hir::Block`], get the span of its last expression or
- /// statement, peeling off any inner blocks.
- pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
- let block = block.innermost_block();
- if let Some(expr) = &block.expr {
- expr.span
- } else if let Some(stmt) = block.stmts.last() {
- // possibly incorrect trailing `;` in the else arm
- stmt.span
- } else {
- // empty block; point at its entirety
- block.span
- }
- }
-
- /// Given a [`hir::HirId`] for a block, get the span of its last expression
- /// or statement, peeling off any inner blocks.
- pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
- match self.tcx.hir().get(hir_id) {
- hir::Node::Block(blk) => self.find_block_span(blk),
- // The parser was in a weird state if either of these happen, but
- // it's better not to panic.
- hir::Node::Expr(e) => e.span,
- _ => rustc_span::DUMMY_SP,
- }
- }
-}
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 524f7a39e..c54c66eab 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -61,12 +61,14 @@ impl<'tcx> InferCtxt<'tcx> {
.as_local()
.map_or(false, |def_id| self.opaque_type_origin(def_id, span).is_some())
};
- let value = value.fold_with(&mut ty::fold::BottomUpFolder {
+ let value = value.fold_with(&mut BottomUpFolder {
tcx: self.tcx,
lt_op: |lt| lt,
ct_op: |ct| ct,
ty_op: |ty| match *ty.kind() {
- ty::Opaque(def_id, _substs) if replace_opaque_type(def_id) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })
+ if replace_opaque_type(def_id) =>
+ {
let def_span = self.tcx.def_span(def_id);
let span = if span.contains(def_span) { def_span } else { span };
let code = traits::ObligationCauseCode::OpaqueReturnType(None);
@@ -104,13 +106,13 @@ impl<'tcx> InferCtxt<'tcx> {
}
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
- ty::Opaque(def_id, substs) if def_id.is_local() => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) if def_id.is_local() => {
let def_id = def_id.expect_local();
let origin = match self.defining_use_anchor {
DefiningAnchor::Bind(_) => {
// Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose
- // value we are inferring. At present, this is
+ // value we are inferring. At present, this is
// always true during the first phase of
// type-check, but not always true later on during
// NLL. Once we support named opaque types more fully,
@@ -147,18 +149,19 @@ impl<'tcx> InferCtxt<'tcx> {
DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span),
DefiningAnchor::Error => return None,
};
- if let ty::Opaque(did2, _) = *b.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
// We could accept this, but there are various ways to handle this situation, and we don't
// want to make a decision on it right now. Likely this case is so super rare anyway, that
// no one encounters it in practice.
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
// where it is of no concern, so we only check for TAITs.
- if let Some(OpaqueTyOrigin::TyAlias) =
- did2.as_local().and_then(|did2| self.opaque_type_origin(did2, cause.span))
+ if let Some(OpaqueTyOrigin::TyAlias) = b_def_id
+ .as_local()
+ .and_then(|b_def_id| self.opaque_type_origin(b_def_id, cause.span))
{
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
span: cause.span,
- hidden_type: self.tcx.def_span(did2),
+ hidden_type: self.tcx.def_span(b_def_id),
opaque_type: self.tcx.def_span(def_id),
});
}
@@ -377,7 +380,7 @@ impl<'tcx> InferCtxt<'tcx> {
};
let item_kind = &self.tcx.hir().expect_item(def_id).kind;
- let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
+ let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
span_bug!(
span,
"weird opaque type: {:#?}, {:#?}",
@@ -437,16 +440,16 @@ where
t: &ty::Binder<'tcx, T>,
) -> ControlFlow<Self::BreakTy> {
t.super_visit_with(self);
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
match *r {
// ignore bound regions, keep visiting
- ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
+ ty::ReLateBound(_, _) => ControlFlow::Continue(()),
_ => {
(self.op)(r);
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
}
}
@@ -454,7 +457,7 @@ where
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
// We're only interested in types involving regions
if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
- return ControlFlow::CONTINUE;
+ return ControlFlow::Continue(());
}
match ty.kind() {
@@ -475,8 +478,8 @@ where
substs.as_generator().resume_ty().visit_with(self);
}
- ty::Opaque(def_id, ref substs) => {
- // Skip lifetime paramters that are not captures.
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, ref substs, .. }) => {
+ // Skip lifetime parameters that are not captures.
let variances = self.tcx.variances_of(*def_id);
for (v, s) in std::iter::zip(variances, substs.iter()) {
@@ -486,11 +489,11 @@ where
}
}
- ty::Projection(proj)
- if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ ty::Alias(ty::Projection, proj)
+ if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder =>
{
- // Skip lifetime paramters that are not captures.
- let variances = self.tcx.variances_of(proj.item_def_id);
+ // Skip lifetime parameters that are not captures.
+ let variances = self.tcx.variances_of(proj.def_id);
for (v, s) in std::iter::zip(variances, proj.substs.iter()) {
if *v != ty::Variance::Bivariant {
@@ -504,7 +507,7 @@ where
}
}
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
}
@@ -563,9 +566,9 @@ impl<'tcx> InferCtxt<'tcx> {
// We can't normalize associated types from `rustc_infer`,
// but we can eagerly register inference variables for them.
// FIXME(RPITIT): Don't replace RPITITs with inference vars.
- ty::Projection(projection_ty)
+ ty::Alias(ty::Projection, projection_ty)
if !projection_ty.has_escaping_bound_vars()
- && tcx.def_kind(projection_ty.item_def_id)
+ && tcx.def_kind(projection_ty.def_id)
!= DefKind::ImplTraitPlaceholder =>
{
self.infer_projection(
@@ -578,17 +581,16 @@ impl<'tcx> InferCtxt<'tcx> {
}
// Replace all other mentions of the same opaque type with the hidden type,
// as the bounds must hold on the hidden type after all.
- ty::Opaque(def_id2, substs2)
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, substs: substs2, .. })
if def_id.to_def_id() == def_id2 && substs == substs2 =>
{
hidden_ty
}
// FIXME(RPITIT): This can go away when we move to associated types
- ty::Projection(proj)
- if def_id.to_def_id() == proj.item_def_id && substs == proj.substs =>
- {
- hidden_ty
- }
+ ty::Alias(
+ ty::Projection,
+ ty::AliasTy { def_id: def_id2, substs: substs2, .. },
+ ) if def_id.to_def_id() == def_id2 && substs == substs2 => hidden_ty,
_ => ty,
},
lt_op: |lt| lt,
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index c146902d5..ae4b85c87 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -29,11 +29,6 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
}
}
- #[instrument(level = "debug", ret)]
- pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> {
- std::mem::take(&mut self.opaque_types)
- }
-
#[inline]
pub(crate) fn with_log<'a>(
&'a mut self,
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index 14ee9f051..3d86279b0 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -3,9 +3,8 @@
// RFC for reference.
use rustc_data_structures::sso::SsoHashSet;
-use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
use smallvec::{smallvec, SmallVec};
#[derive(Debug)]
@@ -23,7 +22,7 @@ pub enum Component<'tcx> {
// is not in a position to judge which is the best technique, so
// we just product the projection as a component and leave it to
// the consumer to decide (but see `EscapingProjection` below).
- Projection(ty::ProjectionTy<'tcx>),
+ Alias(ty::AliasTy<'tcx>),
// In the case where a projection has escaping regions -- meaning
// regions bound within the type itself -- we always use
@@ -45,9 +44,7 @@ pub enum Component<'tcx> {
// projection, so that implied bounds code can avoid relying on
// them. This gives us room to improve the regionck reasoning in
// the future without breaking backwards compat.
- EscapingProjection(Vec<Component<'tcx>>),
-
- Opaque(DefId, SubstsRef<'tcx>),
+ EscapingAlias(Vec<Component<'tcx>>),
}
/// Push onto `out` all the things that must outlive `'a` for the condition
@@ -123,17 +120,6 @@ fn compute_components<'tcx>(
out.push(Component::Param(p));
}
- // Ignore lifetimes found in opaque types. Opaque types can
- // have lifetimes in their substs which their hidden type doesn't
- // actually use. If we inferred that an opaque type is outlived by
- // its parameter lifetimes, then we could prove that any lifetime
- // outlives any other lifetime, which is unsound.
- // See https://github.com/rust-lang/rust/issues/84305 for
- // more details.
- ty::Opaque(def_id, substs) => {
- out.push(Component::Opaque(def_id, substs));
- },
-
// For projections, we prefer to generate an obligation like
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
// regionck more ways to prove that it holds. However,
@@ -142,23 +128,23 @@ fn compute_components<'tcx>(
// trait-ref. Therefore, if we see any higher-ranked regions,
// we simply fallback to the most restrictive rule, which
// requires that `Pi: 'a` for all `i`.
- ty::Projection(ref data) => {
- if !data.has_escaping_bound_vars() {
+ ty::Alias(_, alias_ty) => {
+ if !alias_ty.has_escaping_bound_vars() {
// best case: no escaping regions, so push the
// projection and skip the subtree (thus generating no
// constraints for Pi). This defers the choice between
// the rules OutlivesProjectionEnv,
// OutlivesProjectionTraitDef, and
// OutlivesProjectionComponents to regionck.
- out.push(Component::Projection(*data));
+ out.push(Component::Alias(alias_ty));
} else {
// fallback case: hard code
- // OutlivesProjectionComponents. Continue walking
+ // OutlivesProjectionComponents. Continue walking
// through and constrain Pi.
let mut subcomponents = smallvec![];
let mut subvisited = SsoHashSet::new();
compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited);
- out.push(Component::EscapingProjection(subcomponents.into_iter().collect()));
+ out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
}
}
@@ -195,7 +181,7 @@ fn compute_components<'tcx>(
ty::Error(_) => {
// (*) Function pointers and trait objects are both binders.
// In the RFC, this means we would add the bound regions to
- // the "bound regions list". In our representation, no such
+ // the "bound regions list". In our representation, no such
// list is maintained explicitly, because bound regions
// themselves can be readily identified.
compute_components_recursive(tcx, ty.into(), out, visited);
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 33543135d..24e3c34dd 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -138,13 +138,9 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
}
- OutlivesBound::RegionSubProjection(r_a, projection_b) => {
+ OutlivesBound::RegionSubAlias(r_a, alias_b) => {
self.region_bound_pairs
- .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
- }
- OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
- self.region_bound_pairs
- .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+ .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
}
OutlivesBound::RegionSubRegion(r_a, r_b) => {
if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index abb46ce3b..0194549a8 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -60,7 +60,6 @@
//! imply that `'b: 'a`.
use crate::infer::outlives::components::{push_outlives_components, Component};
-use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::outlives::verify::VerifyBoundCx;
use crate::infer::{
@@ -68,9 +67,6 @@ use crate::infer::{
};
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::undo_log::UndoLogs;
-use rustc_errors::ErrorGuaranteed;
-use rustc_hir::def_id::DefId;
-use rustc_hir::def_id::LocalDefId;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
@@ -116,7 +112,7 @@ impl<'tcx> InferCtxt<'tcx> {
std::mem::take(&mut self.inner.borrow_mut().region_obligations)
}
- /// NOTE: Prefer using [`InferCtxt::check_region_obligations_and_report_errors`]
+ /// NOTE: Prefer using `TypeErrCtxt::check_region_obligations_and_report_errors`
/// instead of calling this directly.
///
/// Process the region obligations that must be proven (during
@@ -170,22 +166,6 @@ impl<'tcx> InferCtxt<'tcx> {
outlives.type_must_outlive(origin, sup_type, sub_region, category);
}
}
-
- /// Processes registered region obliations and resolves regions, reporting
- /// any errors if any were raised. Prefer using this function over manually
- /// calling `resolve_regions_and_report_errors`.
- pub fn check_region_obligations_and_report_errors(
- &self,
- generic_param_scope: LocalDefId,
- outlives_env: &OutlivesEnvironment<'tcx>,
- ) -> Option<ErrorGuaranteed> {
- self.process_registered_region_obligations(
- outlives_env.region_bound_pairs(),
- outlives_env.param_env,
- );
-
- self.err_ctxt().resolve_regions_and_report_errors(generic_param_scope, outlives_env)
- }
}
/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
@@ -285,13 +265,8 @@ where
Component::Param(param_ty) => {
self.param_ty_must_outlive(origin, region, *param_ty);
}
- Component::Opaque(def_id, substs) => {
- self.opaque_must_outlive(*def_id, substs, origin, region)
- }
- Component::Projection(projection_ty) => {
- self.projection_must_outlive(origin, region, *projection_ty);
- }
- Component::EscapingProjection(subcomponents) => {
+ Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty),
+ Component::EscapingAlias(subcomponents) => {
self.components_must_outlive(origin, &subcomponents, region, category);
}
Component::UnresolvedInferenceVariable(v) => {
@@ -307,78 +282,26 @@ where
}
}
+ #[instrument(level = "debug", skip(self))]
fn param_ty_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,
region: ty::Region<'tcx>,
param_ty: ty::ParamTy,
) {
- debug!(
- "param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})",
- region, param_ty, origin
- );
-
- let generic = GenericKind::Param(param_ty);
let verify_bound = self.verify_bound.param_bound(param_ty);
- self.delegate.push_verify(origin, generic, region, verify_bound);
+ self.delegate.push_verify(origin, GenericKind::Param(param_ty), region, verify_bound);
}
#[instrument(level = "debug", skip(self))]
- fn opaque_must_outlive(
+ fn alias_ty_must_outlive(
&mut self,
- def_id: DefId,
- substs: SubstsRef<'tcx>,
origin: infer::SubregionOrigin<'tcx>,
region: ty::Region<'tcx>,
- ) {
- self.generic_must_outlive(
- origin,
- region,
- GenericKind::Opaque(def_id, substs),
- def_id,
- substs,
- true,
- |ty| match *ty.kind() {
- ty::Opaque(def_id, substs) => (def_id, substs),
- _ => bug!("expected only projection types from env, not {:?}", ty),
- },
- );
- }
-
- #[instrument(level = "debug", skip(self))]
- fn projection_must_outlive(
- &mut self,
- origin: infer::SubregionOrigin<'tcx>,
- region: ty::Region<'tcx>,
- projection_ty: ty::ProjectionTy<'tcx>,
- ) {
- self.generic_must_outlive(
- origin,
- region,
- GenericKind::Projection(projection_ty),
- projection_ty.item_def_id,
- projection_ty.substs,
- false,
- |ty| match ty.kind() {
- ty::Projection(projection_ty) => (projection_ty.item_def_id, projection_ty.substs),
- _ => bug!("expected only projection types from env, not {:?}", ty),
- },
- );
- }
-
- #[instrument(level = "debug", skip(self, filter))]
- fn generic_must_outlive(
- &mut self,
- origin: infer::SubregionOrigin<'tcx>,
- region: ty::Region<'tcx>,
- generic: GenericKind<'tcx>,
- def_id: DefId,
- substs: SubstsRef<'tcx>,
- is_opaque: bool,
- filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>),
+ alias_ty: ty::AliasTy<'tcx>,
) {
// An optimization for a common case with opaque types.
- if substs.is_empty() {
+ if alias_ty.substs.is_empty() {
return;
}
@@ -388,7 +311,7 @@ where
// particular). :) First off, we have to choose between using the
// OutlivesProjectionEnv, OutlivesProjectionTraitDef, and
// OutlivesProjectionComponent rules, any one of which is
- // sufficient. If there are no inference variables involved, it's
+ // sufficient. If there are no inference variables involved, it's
// not hard to pick the right rule, but if there are, we're in a
// bit of a catch 22: if we picked which rule we were going to
// use, we could add constraints to the region inference graph
@@ -400,14 +323,14 @@ where
// These are guaranteed to apply, no matter the inference
// results.
let trait_bounds: Vec<_> =
- self.verify_bound.declared_region_bounds(def_id, substs).collect();
+ self.verify_bound.declared_bounds_from_definition(alias_ty).collect();
debug!(?trait_bounds);
// Compute the bounds we can derive from the environment. This
// is an "approximate" match -- in some cases, these bounds
// may not apply.
- let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic);
+ let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(alias_ty);
debug!(?approx_env_bounds);
// Remove outlives bounds that we get from the environment but
@@ -422,8 +345,8 @@ where
// If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
// will be invoked with `['b => ^1]` and so we will get `^1` returned.
let bound = bound_outlives.skip_binder();
- let (def_id, substs) = filter(bound.0);
- self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1)
+ let ty::Alias(_, alias_ty) = bound.0.kind() else { bug!("expected AliasTy") };
+ self.verify_bound.declared_bounds_from_definition(*alias_ty).all(|r| r != bound.1)
});
// If declared bounds list is empty, the only applicable rule is
@@ -440,12 +363,12 @@ where
// the problem is to add `T: 'r`, which isn't true. So, if there are no
// inference variables, we use a verify constraint instead of adding
// edges, which winds up enforcing the same condition.
- let needs_infer = substs.needs_infer();
- if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) {
+ if approx_env_bounds.is_empty()
+ && trait_bounds.is_empty()
+ && (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque)
+ {
debug!("no declared bounds");
-
- self.substs_must_outlive(substs, origin, region);
-
+ self.substs_must_outlive(alias_ty.substs, origin, region);
return;
}
@@ -486,14 +409,9 @@ where
// projection outlive; in some cases, this may add insufficient
// edges into the inference graph, leading to inference failures
// even though a satisfactory solution exists.
- let verify_bound = self.verify_bound.projection_opaque_bounds(
- generic,
- def_id,
- substs,
- &mut Default::default(),
- );
- debug!("projection_must_outlive: pushing {:?}", verify_bound);
- self.delegate.push_verify(origin, generic, region, verify_bound);
+ let verify_bound = self.verify_bound.alias_bound(alias_ty, &mut Default::default());
+ debug!("alias_must_outlive: pushing {:?}", verify_bound);
+ self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound);
}
fn substs_must_outlive(
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index f470b2eb8..94de9bc2d 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -1,11 +1,10 @@
use crate::infer::outlives::components::{compute_components_recursive, Component};
use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::region_constraints::VerifyIfEq;
-use crate::infer::{GenericKind, VerifyBound};
+use crate::infer::VerifyBound;
use rustc_data_structures::sso::SsoHashSet;
-use rustc_hir::def_id::DefId;
use rustc_middle::ty::GenericArg;
-use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
use smallvec::smallvec;
@@ -94,29 +93,26 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// this list.
pub fn approx_declared_bounds_from_env(
&self,
- generic: GenericKind<'tcx>,
+ alias_ty: ty::AliasTy<'tcx>,
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
- let projection_ty = generic.to_ty(self.tcx);
- let erased_projection_ty = self.tcx.erase_regions(projection_ty);
- self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
+ let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx));
+ self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
}
#[instrument(level = "debug", skip(self, visited))]
- pub fn projection_opaque_bounds(
+ pub fn alias_bound(
&self,
- generic: GenericKind<'tcx>,
- def_id: DefId,
- substs: SubstsRef<'tcx>,
+ alias_ty: ty::AliasTy<'tcx>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> {
- let generic_ty = generic.to_ty(self.tcx);
+ let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
// Search the env for where clauses like `P: 'a`.
- let projection_opaque_bounds = self
- .approx_declared_bounds_from_env(generic)
+ let env_bounds = self
+ .approx_declared_bounds_from_env(alias_ty)
.into_iter()
.map(|binder| {
- if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty {
+ if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == alias_ty_as_ty {
// Micro-optimize if this is an exact match (this
// occurs often when there are no region variables
// involved).
@@ -126,19 +122,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
VerifyBound::IfEq(verify_if_eq_b)
}
});
- // Extend with bounds that we can find from the trait.
- let trait_bounds =
- self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r));
+
+ // Extend with bounds that we can find from the definition.
+ let definition_bounds =
+ self.declared_bounds_from_definition(alias_ty).map(|r| VerifyBound::OutlivedBy(r));
// see the extensive comment in projection_must_outlive
let recursive_bound = {
let mut components = smallvec![];
- compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited);
+ compute_components_recursive(self.tcx, alias_ty_as_ty.into(), &mut components, visited);
self.bound_from_components(&components, visited)
};
- VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect())
- .or(recursive_bound)
+ VerifyBound::AnyBound(env_bounds.chain(definition_bounds).collect()).or(recursive_bound)
}
fn bound_from_components(
@@ -149,10 +145,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
let mut bounds = components
.iter()
.map(|component| self.bound_from_single_component(component, visited))
- .filter(|bound| {
- // Remove bounds that must hold, since they are not interesting.
- !bound.must_hold()
- });
+ // Remove bounds that must hold, since they are not interesting.
+ .filter(|bound| !bound.must_hold());
match (bounds.next(), bounds.next()) {
(Some(first), None) => first,
@@ -170,19 +164,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
match *component {
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
Component::Param(param_ty) => self.param_bound(param_ty),
- Component::Opaque(did, substs) => self.projection_opaque_bounds(
- GenericKind::Opaque(did, substs),
- did,
- substs,
- visited,
- ),
- Component::Projection(projection_ty) => self.projection_opaque_bounds(
- GenericKind::Projection(projection_ty),
- projection_ty.item_def_id,
- projection_ty.substs,
- visited,
- ),
- Component::EscapingProjection(ref components) => {
+ Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited),
+ Component::EscapingAlias(ref components) => {
self.bound_from_components(components, visited)
}
Component::UnresolvedInferenceVariable(v) => {
@@ -298,20 +281,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
///
/// This is for simplicity, and because we are not really smart
/// enough to cope with such bounds anywhere.
- pub fn declared_region_bounds(
+ pub fn declared_bounds_from_definition(
&self,
- def_id: DefId,
- substs: SubstsRef<'tcx>,
+ alias_ty: ty::AliasTy<'tcx>,
) -> impl Iterator<Item = ty::Region<'tcx>> {
let tcx = self.tcx;
- let bounds = tcx.item_bounds(def_id);
- trace!("{:#?}", bounds);
+ let bounds = tcx.item_bounds(alias_ty.def_id);
+ trace!("{:#?}", bounds.0);
bounds
- .into_iter()
+ .subst_iter(tcx, alias_ty.substs)
.filter_map(|p| p.to_opt_type_outlives())
.filter_map(|p| p.no_bound_vars())
- .map(|b| b.1)
- .map(move |r| EarlyBinder(r).subst(tcx, substs))
+ .map(|OutlivesPredicate(_, r)| r)
}
/// Searches through a predicate list for a predicate `T: 'a`.
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index eb6deee29..4667d99ff 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -16,12 +16,12 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn infer_projection(
&self,
param_env: ty::ParamEnv<'tcx>,
- projection_ty: ty::ProjectionTy<'tcx>,
+ projection_ty: ty::AliasTy<'tcx>,
cause: ObligationCause<'tcx>,
recursion_depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>,
) -> Ty<'tcx> {
- let def_id = projection_ty.item_def_id;
+ let def_id = projection_ty.def_id;
let ty_var = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::NormalizeProjectionType,
span: self.tcx.def_span(def_id),
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index 22b4bbb17..c46edc33f 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -357,15 +357,13 @@ impl<'tcx> SccUniverse<'tcx> {
}
rustc_index::newtype_index! {
- struct LeakCheckNode {
- DEBUG_FORMAT = "LeakCheckNode({})"
- }
+ #[debug_format = "LeakCheckNode({})"]
+ struct LeakCheckNode {}
}
rustc_index::newtype_index! {
- struct LeakCheckScc {
- DEBUG_FORMAT = "LeakCheckScc({})"
- }
+ #[debug_format = "LeakCheckScc({})"]
+ struct LeakCheckScc {}
}
/// Represents the graph of constraints. For each `R1: R2` constraint we create
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 985c5d360..0428481b7 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -12,10 +12,8 @@ use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify as ut;
-use rustc_hir::def_id::DefId;
use rustc_index::vec::IndexVec;
use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
-use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::ReStatic;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReLateBound, ReVar};
@@ -169,8 +167,7 @@ pub struct Verify<'tcx> {
#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
pub enum GenericKind<'tcx> {
Param(ty::ParamTy),
- Projection(ty::ProjectionTy<'tcx>),
- Opaque(DefId, SubstsRef<'tcx>),
+ Alias(ty::AliasTy<'tcx>),
}
/// Describes the things that some `GenericKind` value `G` is known to
@@ -749,10 +746,7 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
GenericKind::Param(ref p) => write!(f, "{:?}", p),
- GenericKind::Projection(ref p) => write!(f, "{:?}", p),
- GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
- write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
- }),
+ GenericKind::Alias(ref p) => write!(f, "{:?}", p),
}
}
}
@@ -761,10 +755,7 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
GenericKind::Param(ref p) => write!(f, "{}", p),
- GenericKind::Projection(ref p) => write!(f, "{}", p),
- GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
- write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
- }),
+ GenericKind::Alias(ref p) => write!(f, "{}", p),
}
}
}
@@ -773,8 +764,7 @@ impl<'tcx> GenericKind<'tcx> {
pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match *self {
GenericKind::Param(ref p) => p.to_ty(tcx),
- GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs),
- GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs),
+ GenericKind::Alias(ref p) => p.to_ty(tcx),
}
}
}
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 8671f8d45..65b90aa3d 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -147,7 +147,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
} else if !t.has_non_region_infer() {
// All const/type variables in inference types must already be resolved,
// no need to visit the contents.
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
} else {
// Otherwise, keep visiting.
t.super_visit_with(self)
@@ -178,7 +178,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
} else if !ct.has_non_region_infer() {
// All const/type variables in inference types must already be resolved,
// no need to visit the contents.
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
} else {
// Otherwise, keep visiting.
ct.super_visit_with(self)
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 2c6987cc3..bd38b52ba 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -130,12 +130,16 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
Ok(self.tcx().ty_error_with_guaranteed(e))
}
- (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+ ) if a_def_id == b_def_id => {
self.fields.infcx.super_combine_tys(self, a, b)?;
Ok(a)
}
- (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
- if self.fields.define_opaque_types && did.is_local() =>
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+ if self.fields.define_opaque_types && def_id.is_local() =>
{
self.fields.obligations.extend(
infcx
@@ -213,6 +217,11 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
where
T: Relate<'tcx>,
{
+ // A binder is always a subtype of itself if it's structually equal to itself
+ if a == b {
+ return Ok(a);
+ }
+
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
Ok(a)
}
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 7ff086452..263c6a47d 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -433,7 +433,7 @@ impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> {
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, ut::NoError> {
match (value1, value2) {
// We never equate two type variables, both of which
- // have known types. Instead, we recursively equate
+ // have known types. Instead, we recursively equate
// those types.
(&TypeVariableValue::Known { .. }, &TypeVariableValue::Known { .. }) => {
bug!("equating two type variables, both of which have known types")
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 611961ab1..955c54e85 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -87,18 +87,12 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
/// The combined undo log for all the various unification tables. For each change to the storage
/// for any kind of inference variable, we record an UndoLog entry in the vector here.
-#[derive(Clone)]
+#[derive(Clone, Default)]
pub(crate) struct InferCtxtUndoLogs<'tcx> {
logs: Vec<UndoLog<'tcx>>,
num_open_snapshots: usize,
}
-impl Default for InferCtxtUndoLogs<'_> {
- fn default() -> Self {
- Self { logs: Default::default(), num_open_snapshots: Default::default() }
- }
-}
-
/// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any
/// action that is convertible into an UndoLog (per the From impls above).
impl<'tcx, T> UndoLogs<T> for InferCtxtUndoLogs<'tcx>