summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer/src')
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs10
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs4
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs4
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs4
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs747
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs52
-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/placeholder_error.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs63
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs294
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs67
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs6
-rw-r--r--compiler/rustc_infer/src/infer/fudge.rs19
-rw-r--r--compiler/rustc_infer/src/infer/generalize.rs22
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs114
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs12
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs8
-rw-r--r--compiler/rustc_infer/src/infer/outlives/for_liveness.rs129
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs1
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs28
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs28
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs4
-rw-r--r--compiler/rustc_infer/src/infer/undo_log.rs10
-rw-r--r--compiler/rustc_infer/src/lib.rs3
-rw-r--r--compiler/rustc_infer/src/traits/error_reporting/mod.rs68
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs1
-rw-r--r--compiler/rustc_infer/src/traits/util.rs63
31 files changed, 1028 insertions, 757 deletions
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index ad4525c92..3ff1a5c0c 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -194,13 +194,13 @@ impl<'a> SourceKindMultiSuggestion<'a> {
data: &'a FnRetTy<'a>,
should_wrap_expr: Option<Span>,
) -> Self {
- let (arrow, post) = match data {
- FnRetTy::DefaultReturn(_) => ("-> ", " "),
- _ => ("", ""),
+ let arrow = match data {
+ FnRetTy::DefaultReturn(_) => " -> ",
+ _ => "",
};
let (start_span, start_span_code, end_span) = match should_wrap_expr {
- Some(end_span) => (data.span(), format!("{arrow}{ty_info}{post}{{ "), Some(end_span)),
- None => (data.span(), format!("{arrow}{ty_info}{post}"), None),
+ Some(end_span) => (data.span(), format!("{arrow}{ty_info} {{"), Some(end_span)),
+ None => (data.span(), format!("{arrow}{ty_info}"), None),
};
Self::ClosureReturn { start_span, start_span_code, end_span }
}
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index 9276bb0a7..57bc14ebc 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -60,9 +60,7 @@ impl<'a> DescriptionCtx<'a> {
let span = Some(tcx.def_span(scope));
(span, "defined_here", String::new())
}
- _ => {
- (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string())
- }
+ _ => (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string()),
}
}
}
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 4124c9ead..0e2f9ba70 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -457,8 +457,8 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Bool
| ty::Char
| ty::Int(..)
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 41787ee29..3c4c4644f 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -27,7 +27,7 @@ use rustc_index::IndexVec;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::GenericArg;
use rustc_middle::ty::{self, List, Ty, TyCtxt};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
pub use rustc_middle::infer::canonical::*;
pub use substitute::CanonicalExt;
@@ -152,7 +152,7 @@ impl<'tcx> InferCtxt<'tcx> {
)
.into(),
CanonicalVarKind::Effect => {
- let vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
+ let vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid;
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool)
.into()
}
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index ee13eb027..2a9e20b9f 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -320,7 +320,7 @@ impl<'tcx> InferCtxt<'tcx> {
#[instrument(level = "debug", skip(self))]
fn unify_const_variable(
&self,
- target_vid: ty::ConstVid<'tcx>,
+ target_vid: ty::ConstVid,
ct: ty::Const<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
@@ -381,7 +381,7 @@ impl<'tcx> InferCtxt<'tcx> {
fn unify_effect_variable(
&self,
vid_is_expected: bool,
- vid: ty::EffectVid<'tcx>,
+ vid: ty::EffectVid,
val: EffectVarValue<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
self.inner
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 665297da2..5d929394e 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -56,7 +56,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
// performing trait matching (which then performs equality
// unification).
- relate::relate_args(self, a_arg, b_arg)
+ relate::relate_args_invariantly(self, a_arg, b_arg)
}
fn relate_with_variance<T: Relate<'tcx>>(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 72cfc1337..26d071a01 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -59,20 +59,19 @@ use crate::traits::{
};
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_errors::{error_code, Applicability, DiagnosticBuilder, DiagnosticStyledString};
use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
-use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::Node;
use rustc_middle::dep_graph::DepContext;
-use rustc_middle::ty::print::with_forced_trimmed_paths;
+use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError};
use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
use rustc_middle::ty::{
- self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
- TypeVisitable, TypeVisitableExt,
+ self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
+ TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
};
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
@@ -228,8 +227,10 @@ fn msg_span_from_named_region<'tcx>(
let scope = region.free_region_binding_scope(tcx).expect_local();
match fr.bound_region {
ty::BoundRegionKind::BrNamed(_, name) => {
- let span = if let Some(param) =
- tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+ let span = if let Some(param) = tcx
+ .hir()
+ .get_generics(scope)
+ .and_then(|generics| generics.get_named(name))
{
param.span
} else {
@@ -244,7 +245,7 @@ fn msg_span_from_named_region<'tcx>(
}
ty::BrAnon => (
"the anonymous lifetime as defined here".to_string(),
- Some(tcx.def_span(scope))
+ Some(tcx.def_span(scope)),
),
_ => (
format!("the lifetime `{region}` as defined here"),
@@ -579,76 +580,68 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
struct AbsolutePathPrinter<'tcx> {
tcx: TyCtxt<'tcx>,
+ segments: Vec<String>,
}
- struct NonTrivialPath;
-
impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
- type Error = NonTrivialPath;
-
- type Path = Vec<String>;
- type Region = !;
- type Type = !;
- type DynExistential = !;
- type Const = !;
-
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
self.tcx
}
- fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
- Err(NonTrivialPath)
+ fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
+ Err(fmt::Error)
}
- fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
- Err(NonTrivialPath)
+ fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
+ Err(fmt::Error)
}
fn print_dyn_existential(
- self,
+ &mut self,
_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
- ) -> Result<Self::DynExistential, Self::Error> {
- Err(NonTrivialPath)
+ ) -> Result<(), PrintError> {
+ Err(fmt::Error)
}
- fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
- Err(NonTrivialPath)
+ fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
+ Err(fmt::Error)
}
- fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- Ok(vec![self.tcx.crate_name(cnum).to_string()])
+ fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
+ self.segments = vec![self.tcx.crate_name(cnum).to_string()];
+ Ok(())
}
fn path_qualified(
- self,
+ &mut self,
_self_ty: Ty<'tcx>,
_trait_ref: Option<ty::TraitRef<'tcx>>,
- ) -> Result<Self::Path, Self::Error> {
- Err(NonTrivialPath)
+ ) -> Result<(), PrintError> {
+ Err(fmt::Error)
}
fn path_append_impl(
- self,
- _print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ &mut self,
+ _print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
_disambiguated_data: &DisambiguatedDefPathData,
_self_ty: Ty<'tcx>,
_trait_ref: Option<ty::TraitRef<'tcx>>,
- ) -> Result<Self::Path, Self::Error> {
- Err(NonTrivialPath)
+ ) -> Result<(), PrintError> {
+ Err(fmt::Error)
}
fn path_append(
- self,
- print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ &mut self,
+ print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
disambiguated_data: &DisambiguatedDefPathData,
- ) -> Result<Self::Path, Self::Error> {
- let mut path = print_prefix(self)?;
- path.push(disambiguated_data.to_string());
- Ok(path)
+ ) -> Result<(), PrintError> {
+ print_prefix(self)?;
+ self.segments.push(disambiguated_data.to_string());
+ Ok(())
}
fn path_generic_args(
- self,
- print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ &mut self,
+ print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
_args: &[GenericArg<'tcx>],
- ) -> Result<Self::Path, Self::Error> {
+ ) -> Result<(), PrintError> {
print_prefix(self)
}
}
@@ -658,12 +651,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// are from a local module we could have false positives, e.g.
// let _ = [{struct Foo; Foo}, {struct Foo; Foo}];
if did1.krate != did2.krate {
- let abs_path =
- |def_id| AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]);
+ let abs_path = |def_id| {
+ let mut printer = AbsolutePathPrinter { tcx: self.tcx, segments: vec![] };
+ printer.print_def_path(def_id, &[]).map(|_| printer.segments)
+ };
// We compare strings because DefPath can be different
// for imported and non-imported crates
- let same_path = || -> Result<_, NonTrivialPath> {
+ let same_path = || -> Result<_, PrintError> {
Ok(self.tcx.def_path_str(did1) == self.tcx.def_path_str(did2)
|| abs_path(did1)? == abs_path(did2)?)
};
@@ -716,13 +711,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& let ty::Adt(def, args) = 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 `{}`", args.type_at(0)));
+ err.span_label(
+ span,
+ format!("this is an iterator with items of type `{}`", args.type_at(0)),
+ );
} else {
- err.span_label(span, format!("this expression has type `{ty}`"));
- }
+ 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
+ && ty.is_box()
+ && ty.boxed_ty() == found
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
{
err.span_suggestion(
@@ -744,9 +743,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
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)
- })
+ 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");
};
@@ -764,7 +763,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
_ => {}
}
}
- },
+ }
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
arm_block_id,
arm_span,
@@ -776,6 +775,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
ref prior_arms,
opt_suggest_box_span,
scrut_span,
+ scrut_hir_id,
..
}) => match source {
hir::MatchSource::TryDesugar(scrut_hir_id) => {
@@ -783,9 +783,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
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)
- })
+ 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");
};
@@ -843,6 +843,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
) {
err.subdiagnostic(subdiag);
}
+ if let Some(hir::Node::Expr(m)) = self.tcx.hir().find_parent(scrut_hir_id)
+ && let Some(hir::Node::Stmt(stmt)) = self.tcx.hir().find_parent(m.hir_id)
+ && let hir::StmtKind::Expr(_) = stmt.kind
+ {
+ err.span_suggestion_verbose(
+ stmt.span.shrink_to_hi(),
+ "consider using a semicolon here, but this will discard any values \
+ in the match arms",
+ ";",
+ Applicability::MaybeIncorrect,
+ );
+ }
if let Some(ret_sp) = opt_suggest_box_span {
// Get return type span and point to it.
self.suggest_boxing_for_return_impl_trait(
@@ -879,8 +891,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
// don't suggest wrapping either blocks in `if .. {} else {}`
let is_empty_arm = |id| {
- let hir::Node::Block(blk) = self.tcx.hir().get(id)
- else {
+ let hir::Node::Block(blk) = self.tcx.hir().get(id) else {
return false;
};
if blk.expr.is_some() || !blk.stmts.is_empty() {
@@ -909,12 +920,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
_ => {
if let ObligationCauseCode::BindingObligation(_, span)
- | ObligationCauseCode::ExprBindingObligation(_, span, ..)
- = cause.code().peel_derives()
+ | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
+ cause.code().peel_derives()
&& let TypeError::RegionsPlaceholderMismatch = terr
{
- err.span_note( * span,
- "the lifetime requirement is introduced here");
+ err.span_note(*span, "the lifetime requirement is introduced here");
}
}
}
@@ -1060,7 +1070,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let get_lifetimes = |sig| {
use rustc_hir::def::Namespace;
- let (_, sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS)
+ let (sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS)
.name_all_regions(sig)
.unwrap();
let lts: Vec<String> = reg.into_values().map(|kind| kind.to_string()).collect();
@@ -1574,14 +1584,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
target: &str,
types: &FxIndexMap<TyCategory, FxIndexSet<Span>>,
) {
- for (key, values) in types.iter() {
+ for (kind, values) in types.iter() {
let count = values.len();
- let kind = key.descr();
for &sp in values {
err.span_label(
sp,
format!(
- "{}{} {}{}",
+ "{}{} {:#}{}",
if count == 1 { "the " } else { "one of the " },
target,
kind,
@@ -1743,19 +1752,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| {
- if let ty::Adt(expected, _) = expected.kind() && let Some(primitive) = found.primitive_symbol() {
+ if let ty::Adt(expected, _) = expected.kind()
+ && let Some(primitive) = found.primitive_symbol()
+ {
let path = self.tcx.def_path(expected.did()).data;
let name = path.last().unwrap().data.get_opt_name();
if name == Some(primitive) {
return Some(Similar::PrimitiveFound { expected: *expected, found });
}
- } else if let Some(primitive) = expected.primitive_symbol() && let ty::Adt(found, _) = found.kind() {
+ } else if let Some(primitive) = expected.primitive_symbol()
+ && let ty::Adt(found, _) = found.kind()
+ {
let path = self.tcx.def_path(found.did()).data;
let name = path.last().unwrap().data.get_opt_name();
if name == Some(primitive) {
return Some(Similar::PrimitiveExpected { expected, found: *found });
}
- } else if let ty::Adt(expected, _) = expected.kind() && let ty::Adt(found, _) = found.kind() {
+ } else if let ty::Adt(expected, _) = expected.kind()
+ && let ty::Adt(found, _) = found.kind()
+ {
if !expected.did().is_local() && expected.did().krate == found.did().krate {
// Most likely types from different versions of the same crate
// are in play, in which case this message isn't so helpful.
@@ -1765,8 +1780,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let f_path = self.tcx.def_path(found.did()).data;
let e_path = self.tcx.def_path(expected.did()).data;
- if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last()) && e_last == f_last {
- return Some(Similar::Adts{expected: *expected, found: *found});
+ if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last())
+ && e_last == f_last
+ {
+ return Some(Similar::Adts { expected: *expected, found: *found });
}
}
None
@@ -1797,7 +1814,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
let diagnose_adts =
- |expected_adt : ty::AdtDef<'tcx>,
+ |expected_adt: ty::AdtDef<'tcx>,
found_adt: ty::AdtDef<'tcx>,
diagnostic: &mut Diagnostic| {
let found_name = values.found.sort_string(self.tcx);
@@ -1817,8 +1834,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
.tcx
.parent_module_from_def_id(defid.expect_local())
.to_def_id();
- let module_name = self.tcx.def_path(module).to_string_no_crate_verbose();
- format!("{name} is defined in module `crate{module_name}` of the current crate")
+ let module_name =
+ self.tcx.def_path(module).to_string_no_crate_verbose();
+ format!(
+ "{name} is defined in module `crate{module_name}` of the current crate"
+ )
} else if defid.is_local() {
format!("{name} is defined in the current crate")
} else {
@@ -1830,13 +1850,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
match s {
- Similar::Adts{expected, found} => {
- diagnose_adts(expected, found, diag)
- }
- Similar::PrimitiveFound{expected, found: prim} => {
+ Similar::Adts { expected, found } => diagnose_adts(expected, found, diag),
+ Similar::PrimitiveFound { expected, found: prim } => {
diagnose_primitive(prim, values.expected, expected.did(), diag)
}
- Similar::PrimitiveExpected{expected: prim, found} => {
+ Similar::PrimitiveExpected { expected: prim, found } => {
diagnose_primitive(prim, values.found, found.did(), diag)
}
}
@@ -1878,7 +1896,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
s
};
- if !(values.expected.is_simple_text(self.tcx) && values.found.is_simple_text(self.tcx))
+ if !(values.expected.is_simple_text(self.tcx)
+ && values.found.is_simple_text(self.tcx))
|| (exp_found.is_some_and(|ef| {
// This happens when the type error is a subset of the expectation,
// like when you have two references but one is `usize` and the other
@@ -1968,13 +1987,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& let exp_found = TypeError::Sorts(exp_found)
&& exp_found != terr
{
- self.note_and_explain_type_err(
- diag,
- exp_found,
- cause,
- span,
- cause.body_id.to_def_id(),
- );
+ self.note_and_explain_type_err(diag, exp_found, cause, span, cause.body_id.to_def_id());
}
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
@@ -1984,7 +1997,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
{
let span = self.tcx.def_span(def_id);
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
- self.suggest_for_all_lifetime_closure(span, self.tcx.hir().get_by_def_id(def_id), &exp_found, diag);
+ self.suggest_for_all_lifetime_closure(
+ span,
+ self.tcx.hir().get_by_def_id(def_id),
+ &exp_found,
+ diag,
+ );
}
// It reads better to have the error origin as the final
@@ -2010,7 +2028,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// parentheses around it, perhaps the user meant to write `(expr,)` to
// build a tuple (issue #86100)
(ty::Tuple(fields), _) => {
- suggestions.extend(self.suggest_wrap_to_build_a_tuple( span, found, fields))
+ suggestions.extend(self.suggest_wrap_to_build_a_tuple(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
@@ -2060,8 +2078,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
// For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
// we try to suggest to add the missing `let` for `if let Some(..) = expr`
- (ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
- suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
+ (ty::Bool, ty::Tuple(list)) => {
+ if list.len() == 0 {
+ suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
+ }
}
(ty::Array(_, _), ty::Array(_, _)) => {
suggestions.extend(self.suggest_specify_actual_length(terr, trace, span))
@@ -2071,8 +2091,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
let code = trace.cause.code();
if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. })
- | BlockTailExpression(.., source)
- ) = code
+ | BlockTailExpression(.., source)) = code
&& let hir::MatchSource::TryDesugar(_) = source
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
{
@@ -2109,17 +2128,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// Find a local statement where the initializer has
// the same span as the error and the type is specified.
if let hir::Stmt {
- kind: hir::StmtKind::Local(hir::Local {
- init: Some(hir::Expr {
- span: init_span,
+ kind:
+ hir::StmtKind::Local(hir::Local {
+ init: Some(hir::Expr { span: init_span, .. }),
+ ty: Some(array_ty),
..
}),
- ty: Some(array_ty),
- ..
- }),
..
} = s
- && init_span == &self.span {
+ && init_span == &self.span
+ {
self.result = Some(*array_ty);
}
}
@@ -2317,113 +2335,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- // Attempt to obtain the span of the parameter so we can
- // 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);
- 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
- // `T:` when appropriate
- if let Some(span) = bounds {
- (span, true)
- } else {
- let sp = self.tcx.def_span(def_id);
- (sp.shrink_to_hi(), false)
- }
- })
- } else {
- None
- }
- }
- _ => None,
- };
-
- let new_lt = {
- let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char));
- let lts_names =
- iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
- .flat_map(|g| &g.params)
- .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
- .map(|p| p.name.as_str())
- .collect::<Vec<_>>();
- possible
- .find(|candidate| !lts_names.contains(&&candidate[..]))
- .unwrap_or("'lt".to_string())
- };
-
- 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()
- .is_some_and(|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(' ')
- {
- new_lt.to_string()
- } else {
- format!("{new_lt} ")
- }
- )
- ));
- } else {
- add_lt_suggs.push(Some((p.span.shrink_to_hi(), format!("<{new_lt}>"))));
- }
- }
- }
+ if let Some(SubregionOrigin::CompareImplItemObligation {
+ span,
+ impl_item_def_id,
+ trait_item_def_id,
+ }) = origin
+ {
+ return self.report_extra_impl_obligation(
+ span,
+ impl_item_def_id,
+ trait_item_def_id,
+ &format!("`{bound_kind}: {sub}`"),
+ );
}
let labeled_user_string = match bound_kind {
@@ -2437,223 +2360,211 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
},
};
- if let Some(SubregionOrigin::CompareImplItemObligation {
+ let mut err = self.tcx.sess.struct_span_err_with_code(
span,
- impl_item_def_id,
- trait_item_def_id,
- }) = origin
- {
- return self.report_extra_impl_obligation(
- span,
- impl_item_def_id,
- trait_item_def_id,
- &format!("`{bound_kind}: {sub}`"),
- );
+ format!("{labeled_user_string} may not live long enough"),
+ match sub.kind() {
+ ty::ReEarlyBound(_) | ty::ReFree(_) if sub.has_name() => error_code!(E0309),
+ ty::ReStatic => error_code!(E0310),
+ _ => error_code!(E0311),
+ },
+ );
+
+ '_explain: {
+ let (description, span) = match sub.kind() {
+ ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
+ msg_span_from_named_region(self.tcx, sub, Some(span))
+ }
+ _ => (format!("lifetime `{sub}`"), Some(span)),
+ };
+ let prefix = format!("{labeled_user_string} must be valid for ");
+ label_msg_span(&mut err, &prefix, description, span, "...");
+ if let Some(origin) = origin {
+ self.note_region_origin(&mut err, &origin);
+ }
}
- fn binding_suggestion<'tcx, S: fmt::Display>(
- err: &mut Diagnostic,
- type_param_span: Option<(Span, bool)>,
- bound_kind: GenericKind<'tcx>,
- sub: S,
- add_lt_suggs: Vec<Option<(Span, String)>>,
- ) {
+ 'suggestion: {
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)];
- for add_lt_sugg in add_lt_suggs.into_iter().flatten() {
- suggestions.push(add_lt_sugg);
+
+ if (bound_kind, sub).has_infer_regions()
+ || (bound_kind, sub).has_placeholders()
+ || !bound_kind.is_suggestable(self.tcx, false)
+ {
+ let lt_name = sub.get_name_or_anon().to_string();
+ err.help(format!("{msg} `{bound_kind}: {lt_name}`..."));
+ break 'suggestion;
+ }
+
+ let mut generic_param_scope = generic_param_scope;
+ while self.tcx.def_kind(generic_param_scope) == DefKind::OpaqueTy {
+ generic_param_scope = self.tcx.local_parent(generic_param_scope);
+ }
+
+ // type_param_sugg_span is (span, has_bounds)
+ let (type_scope, type_param_sugg_span) = match bound_kind {
+ GenericKind::Param(ref param) => {
+ let generics = self.tcx.generics_of(generic_param_scope);
+ let def_id = generics.type_param(param, self.tcx).def_id.expect_local();
+ let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.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_generics = self.tcx.hir().get_generics(scope).unwrap();
+ let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
+ Some(span) => Some((span, true)),
+ // If `param` corresponds to `Self`, no usable suggestion span.
+ None if generics.has_self && param.index == 0 => None,
+ None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false)),
+ };
+ (scope, sugg_span)
}
- err.multipart_suggestion_verbose(
- format!("{msg}..."),
- suggestions,
- Applicability::MaybeIncorrect, // Issue #41966
- );
+ _ => (generic_param_scope, None),
+ };
+ let suggestion_scope = {
+ let lifetime_scope = match sub.kind() {
+ ty::ReStatic => hir::def_id::CRATE_DEF_ID,
+ _ => match self.tcx.is_suitable_region(sub) {
+ Some(info) => info.def_id,
+ None => generic_param_scope,
+ },
+ };
+ match self.tcx.is_descendant_of(type_scope.into(), lifetime_scope.into()) {
+ true => type_scope,
+ false => lifetime_scope,
+ }
+ };
+
+ let mut suggs = vec![];
+ let lt_name = self.suggest_name_region(sub, &mut suggs);
+
+ if let Some((sp, has_lifetimes)) = type_param_sugg_span
+ && suggestion_scope == type_scope
+ {
+ let suggestion =
+ if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
+ suggs.push((sp, suggestion))
+ } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) {
+ let pred = format!("{bound_kind}: {lt_name}");
+ let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
+ suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion))
} else {
let consider = format!("{msg} `{bound_kind}: {sub}`...");
err.help(consider);
}
+
+ if !suggs.is_empty() {
+ err.multipart_suggestion_verbose(
+ format!("{msg}"),
+ suggs,
+ Applicability::MaybeIncorrect, // Issue #41966
+ );
+ }
}
- let new_binding_suggestion =
- |err: &mut Diagnostic, type_param_span: Option<(Span, bool)>| {
- let msg = "consider introducing an explicit lifetime bound";
- if let Some((sp, has_lifetimes)) = type_param_span {
- let suggestion =
- if has_lifetimes { format!(" + {new_lt}") } else { format!(": {new_lt}") };
- let mut sugg =
- vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {new_lt}"))];
- for lt in add_lt_suggs.clone().into_iter().flatten() {
- sugg.push(lt);
- sugg.rotate_right(1);
- }
- // `MaybeIncorrect` due to issue #41966.
- err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
- }
- };
+ err
+ }
- #[derive(Debug)]
- enum SubOrigin<'hir> {
- GAT(&'hir hir::Generics<'hir>),
- Impl,
- Trait,
- Fn,
- Unknown,
- }
- let sub_origin = 'origin: {
- match *sub {
- ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) => {
- let node = self.tcx.hir().get_if_local(def_id).unwrap();
- match node {
- Node::GenericParam(param) => {
- for h in self.tcx.hir().parent_iter(param.hir_id) {
- break 'origin match h.1 {
- Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Type(..),
- generics,
- ..
- })
- | Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Type(..),
- generics,
- ..
- }) => SubOrigin::GAT(generics),
- Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Fn(..),
- ..
- })
- | Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(..),
- ..
- })
- | Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(..), ..
- }) => SubOrigin::Fn,
- Node::Item(hir::Item {
- kind: hir::ItemKind::Trait(..),
- ..
- }) => SubOrigin::Trait,
- Node::Item(hir::Item {
- kind: hir::ItemKind::Impl(..), ..
- }) => SubOrigin::Impl,
- _ => continue,
- };
- }
+ pub fn suggest_name_region(
+ &self,
+ lifetime: Region<'tcx>,
+ add_lt_suggs: &mut Vec<(Span, String)>,
+ ) -> String {
+ struct LifetimeReplaceVisitor<'tcx, 'a> {
+ tcx: TyCtxt<'tcx>,
+ needle: hir::LifetimeName,
+ new_lt: &'a str,
+ add_lt_suggs: &'a mut Vec<(Span, String)>,
+ }
+
+ impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'tcx, '_> {
+ fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
+ if lt.res == self.needle {
+ let (pos, span) = lt.suggestion_position();
+ let new_lt = &self.new_lt;
+ let sugg = match pos {
+ hir::LifetimeSuggestionPosition::Normal => format!("{new_lt}"),
+ hir::LifetimeSuggestionPosition::Ampersand => format!("{new_lt} "),
+ hir::LifetimeSuggestionPosition::ElidedPath => format!("<{new_lt}>"),
+ hir::LifetimeSuggestionPosition::ElidedPathArgument => {
+ format!("{new_lt}, ")
}
- _ => {}
- }
+ hir::LifetimeSuggestionPosition::ObjectDefault => format!("+ {new_lt}"),
+ };
+ self.add_lt_suggs.push((span, sugg));
}
- _ => {}
}
- SubOrigin::Unknown
- };
- debug!(?sub_origin);
-
- let mut err = match (*sub, sub_origin) {
- // In the case of GATs, we have to be careful. If we a type parameter `T` on an impl,
- // but a lifetime `'a` on an associated type, then we might need to suggest adding
- // `where T: 'a`. Importantly, this is on the GAT span, not on the `T` declaration.
- (ty::ReEarlyBound(ty::EarlyBoundRegion { name: _, .. }), SubOrigin::GAT(generics)) => {
- // Does the required lifetime have a nice name we can print?
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0309,
- "{} may not live long enough",
- labeled_user_string
- );
- let pred = format!("{bound_kind}: {sub}");
- let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,);
- err.span_suggestion(
- generics.tail_span_for_predicate_suggestion(),
- "consider adding a where clause",
- suggestion,
- Applicability::MaybeIncorrect,
- );
- err
+
+ fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) {
+ let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind else {
+ return hir::intravisit::walk_ty(self, ty);
+ };
+ let opaque_ty = self.tcx.hir().item(item_id).expect_opaque_ty();
+ if let Some(&(_, b)) =
+ opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle)
+ {
+ let prev_needle =
+ std::mem::replace(&mut self.needle, hir::LifetimeName::Param(b));
+ for bound in opaque_ty.bounds {
+ self.visit_param_bound(bound);
+ }
+ self.needle = prev_needle;
+ }
}
- (
- ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
- | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }),
- _,
- ) if name != kw::UnderscoreLifetime => {
- // Does the required lifetime have a nice name we can print?
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0309,
- "{} may not live long enough",
- labeled_user_string
- );
- // Explicitly use the name instead of `sub`'s `Display` impl. The `Display` impl
- // 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, vec![]);
- err
- }
-
- (ty::ReStatic, _) => {
- // Does the required lifetime have a nice name we can print?
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0310,
- "{} may not live long enough",
- labeled_user_string
- );
- binding_suggestion(&mut err, type_param_span, bound_kind, "'static", vec![]);
- err
+ }
+
+ let (lifetime_def_id, lifetime_scope) = match self.tcx.is_suitable_region(lifetime) {
+ Some(info) if !lifetime.has_name() => {
+ (info.boundregion.get_id().unwrap().expect_local(), info.def_id)
}
+ _ => return lifetime.get_name_or_anon().to_string(),
+ };
- _ => {
- // If not, be less specific.
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0311,
- "{} may not live long enough",
- labeled_user_string
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- &format!("{labeled_user_string} must be valid for "),
- sub,
- "...",
- None,
- );
- if let Some(infer::RelateParamBound(_, t, _)) = origin {
- let t = self.resolve_vars_if_possible(t);
- match t.kind() {
- // We've got:
- // 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(..) | ty::Alias(ty::Opaque, ..) => {
- new_binding_suggestion(&mut err, type_param_span);
- }
- _ => {
- binding_suggestion(
- &mut err,
- type_param_span,
- bound_kind,
- new_lt,
- add_lt_suggs,
- );
- }
+ let new_lt = {
+ let generics = self.tcx.generics_of(lifetime_scope);
+ let mut used_names =
+ iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
+ .flat_map(|g| &g.params)
+ .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
+ .map(|p| p.name)
+ .collect::<Vec<_>>();
+ if let Some(hir_id) = self.tcx.opt_local_def_id_to_hir_id(lifetime_scope) {
+ // consider late-bound lifetimes ...
+ used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(|p| {
+ match p {
+ ty::BoundVariableKind::Region(lt) => lt.get_name(),
+ _ => None,
}
- }
- err
+ }))
}
+ (b'a'..=b'z')
+ .map(|c| format!("'{}", c as char))
+ .find(|candidate| !used_names.iter().any(|e| e.as_str() == candidate))
+ .unwrap_or("'lt".to_string())
};
- if let Some(origin) = origin {
- self.note_region_origin(&mut err, &origin);
- }
- err
+ let mut visitor = LifetimeReplaceVisitor {
+ tcx: self.tcx,
+ needle: hir::LifetimeName::Param(lifetime_def_id),
+ add_lt_suggs,
+ new_lt: &new_lt,
+ };
+ match self.tcx.hir().expect_owner(lifetime_scope) {
+ hir::OwnerNode::Item(i) => visitor.visit_item(i),
+ hir::OwnerNode::ForeignItem(i) => visitor.visit_foreign_item(i),
+ hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i),
+ hir::OwnerNode::TraitItem(i) => visitor.visit_trait_item(i),
+ hir::OwnerNode::Crate(_) => bug!("OwnerNode::Crate doesn't not have generics"),
+ }
+
+ let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap();
+ let sugg = ast_generics
+ .span_for_lifetime_suggestion()
+ .map(|span| (span, format!("{new_lt}, ")))
+ .unwrap_or_else(|| (ast_generics.span, format!("<{new_lt}>")));
+ add_lt_suggs.push(sugg);
+
+ new_lt
}
fn report_sub_sup_conflict(
@@ -2925,7 +2836,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
// say, also take a look at the error code, maybe we can
// tailor to that.
_ => match terr {
- TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => Error0644,
+ TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() => Error0644,
TypeError::IntrinsicCast => Error0308,
_ => Error0308,
},
@@ -2972,7 +2883,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
// say, also take a look at the error code, maybe we can
// tailor to that.
_ => match terr {
- TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => {
+ TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() => {
ObligationCauseFailureCode::ClosureSelfref { span }
}
TypeError::IntrinsicCast => {
@@ -3040,21 +2951,23 @@ pub enum TyCategory {
Closure,
Opaque,
OpaqueFuture,
- Generator(hir::GeneratorKind),
+ Coroutine(hir::CoroutineKind),
Foreign,
}
-impl TyCategory {
- fn descr(&self) -> &'static str {
+impl fmt::Display for TyCategory {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- Self::Closure => "closure",
- Self::Opaque => "opaque type",
- Self::OpaqueFuture => "future",
- Self::Generator(gk) => gk.descr(),
- Self::Foreign => "foreign type",
+ Self::Closure => "closure".fmt(f),
+ Self::Opaque => "opaque type".fmt(f),
+ Self::OpaqueFuture => "future".fmt(f),
+ Self::Coroutine(gk) => gk.fmt(f),
+ Self::Foreign => "foreign type".fmt(f),
}
}
+}
+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)),
@@ -3063,8 +2976,8 @@ impl TyCategory {
if tcx.ty_is_opaque_future(ty) { Self::OpaqueFuture } else { Self::Opaque };
Some((kind, def_id))
}
- ty::Generator(def_id, ..) => {
- Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
+ ty::Coroutine(def_id, ..) => {
+ Some((Self::Coroutine(tcx.coroutine_kind(def_id).unwrap()), def_id))
}
ty::Foreign(def_id) => Some((Self::Foreign, def_id)),
_ => None,
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 a9029a8ce..4beb51da7 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
@@ -27,7 +27,7 @@ use std::iter;
pub enum TypeAnnotationNeeded {
/// ```compile_fail,E0282
- /// let x = "hello".chars().rev().collect();
+ /// let x;
/// ```
E0282,
/// An implementation cannot be chosen unambiguously because of lack of information.
@@ -163,13 +163,13 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
let ty_vars = infcx_inner.type_variables();
let var_origin = ty_vars.var_origin(ty_vid);
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind
- && name != kw::SelfUpper && !var_origin.span.from_expansion()
+ && name != kw::SelfUpper
+ && !var_origin.span.from_expansion()
{
let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id));
let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap();
let generic_param_def = generics.param_at(idx as usize, infcx.tcx);
- if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind
- {
+ if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind {
None
} else {
Some(name)
@@ -200,12 +200,15 @@ fn ty_to_string<'tcx>(
ty: Ty<'tcx>,
called_method_def_id: Option<DefId>,
) -> String {
- let printer = fmt_printer(infcx, Namespace::TypeNS);
+ let mut printer = fmt_printer(infcx, Namespace::TypeNS);
let ty = infcx.resolve_vars_if_possible(ty);
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(&mut printer).unwrap();
+ printer.into_buffer()
+ }
(_, Some(def_id))
if ty.is_ty_or_numeric_infer()
&& infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) =>
@@ -218,7 +221,10 @@ fn ty_to_string<'tcx>(
//
// We do have to hide the `extern "rust-call"` ABI in that case though,
// which is too much of a bother for now.
- _ => ty.print(printer).unwrap().into_buffer(),
+ _ => {
+ ty.print(&mut printer).unwrap();
+ printer.into_buffer()
+ }
}
}
@@ -285,8 +291,9 @@ impl<'tcx> InferCtxt<'tcx> {
if let Some(highlight) = highlight {
printer.region_highlight_mode = highlight;
}
+ ty.print(&mut printer).unwrap();
InferenceDiagnosticsData {
- name: ty.print(printer).unwrap().into_buffer(),
+ name: printer.into_buffer(),
span: None,
kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
parent: None,
@@ -312,8 +319,9 @@ impl<'tcx> InferCtxt<'tcx> {
if let Some(highlight) = highlight {
printer.region_highlight_mode = highlight;
}
+ ct.print(&mut printer).unwrap();
InferenceDiagnosticsData {
- name: ct.print(printer).unwrap().into_buffer(),
+ name: printer.into_buffer(),
span: Some(origin.span),
kind: UnderspecifiedArgKind::Const { is_parameter: false },
parent: None,
@@ -329,8 +337,9 @@ impl<'tcx> InferCtxt<'tcx> {
if let Some(highlight) = highlight {
printer.region_highlight_mode = highlight;
}
+ ct.print(&mut printer).unwrap();
InferenceDiagnosticsData {
- name: ct.print(printer).unwrap().into_buffer(),
+ name: printer.into_buffer(),
span: None,
kind: UnderspecifiedArgKind::Const { is_parameter: false },
parent: None,
@@ -487,7 +496,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
{
"Vec<_>".to_string()
} else {
- fmt_printer(self, Namespace::TypeNS)
+ let mut printer = fmt_printer(self, Namespace::TypeNS);
+ printer
.comma_sep(generic_args.iter().copied().map(|arg| {
if arg.is_suggestable(self.tcx, true) {
return arg;
@@ -512,8 +522,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
.into(),
}
}))
- .unwrap()
- .into_buffer()
+ .unwrap();
+ printer.into_buffer()
};
if !have_turbofish {
@@ -525,8 +535,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => {
- let printer = fmt_printer(self, Namespace::ValueNS);
- let def_path = printer.print_def_path(def_id, args).unwrap().into_buffer();
+ let mut printer = fmt_printer(self, Namespace::ValueNS);
+ printer.print_def_path(def_id, args).unwrap();
+ let def_path = printer.into_buffer();
// We only care about whether we have to add `&` or `&mut ` for now.
// This is the case if the last adjustment is a borrow and the
@@ -792,8 +803,9 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, '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
+ 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
@@ -863,11 +875,11 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
GenericArgKind::Type(ty) => {
if matches!(
ty.kind(),
- ty::Alias(ty::Opaque, ..) | ty::Closure(..) | ty::Generator(..)
+ ty::Alias(ty::Opaque, ..) | ty::Closure(..) | ty::Coroutine(..)
) {
// Opaque types can't be named by the user right now.
//
- // Both the generic arguments of closures and generators can
+ // Both the generic arguments of closures and coroutines can
// also not be named. We may want to only look into the closure
// signature in case it has no captures, as that can be represented
// using `fn(T) -> R`.
@@ -1242,7 +1254,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
successor,
args,
def_id,
- }
+ },
})
}
}
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 59fb74eb5..2a70c4673 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
@@ -3,7 +3,7 @@ use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::lexical_region_resolve::RegionResolutionError::*;
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
mod different_lifetimes;
pub mod find_anon_type;
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 4aec28b05..c38e5b8cd 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
@@ -28,7 +28,7 @@ pub struct Highlighted<'tcx, 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>>,
+ T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>>,
{
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
rustc_errors::DiagnosticArgValue::Str(self.to_string().into())
@@ -43,14 +43,14 @@ impl<'tcx, T> Highlighted<'tcx, T> {
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>>,
+ T: for<'a> Print<'tcx, 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)
+ self.value.print(&mut printer)?;
+ f.write_str(&printer.into_buffer())
}
}
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 3cfda0cc5..e2be6cf42 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
@@ -214,7 +214,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
ObligationCauseCode::MatchImpl(parent, ..) => parent.code(),
_ => cause.code(),
}
- && let (&ObligationCauseCode::ItemObligation(item_def_id) | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), None) = (code, override_error_code)
+ && let (
+ &ObligationCauseCode::ItemObligation(item_def_id)
+ | &ObligationCauseCode::ExprItemObligation(item_def_id, ..),
+ None,
+ ) = (code, override_error_code)
{
// Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
// lifetime as above, but called using a fully-qualified path to the method:
@@ -322,13 +326,27 @@ pub fn suggest_new_region_bound(
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 {
+ .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
@@ -342,30 +360,28 @@ pub fn suggest_new_region_bound(
.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, name.to_string())
- }
- )
+ .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, name.to_string())
+ }
+ })
.collect::<Vec<_>>()
&& spans_suggs.len() > 1
{
- let use_lt =
- if existing_lt_name == None {
+ 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} ")));
+ spans_suggs.push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
err.multipart_suggestion_verbose(
- format!(
- "{declare} `{ty}` {captures}, {use_lt}",
- ),
+ format!("{declare} `{ty}` {captures}, {use_lt}",),
spans_suggs,
Applicability::MaybeIncorrect,
);
@@ -443,8 +459,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
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, .. }),
- ..
+ 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
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index 5c3beee28..a8ae43d52 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -54,13 +54,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
(ty::Param(expected), ty::Param(found)) => {
let generics = tcx.generics_of(body_owner_def_id);
- let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id);
- if !sp.contains(e_span) {
- diag.span_label(e_span, "expected type parameter");
+ if let Some(param) = generics.opt_type_param(expected, tcx) {
+ let e_span = tcx.def_span(param.def_id);
+ if !sp.contains(e_span) {
+ diag.span_label(e_span, "expected type parameter");
+ }
}
- let f_span = tcx.def_span(generics.type_param(found, tcx).def_id);
- if !sp.contains(f_span) {
- diag.span_label(f_span, "found type parameter");
+ if let Some(param) = generics.opt_type_param(found, tcx) {
+ let f_span = tcx.def_span(param.def_id);
+ if !sp.contains(f_span) {
+ diag.span_label(f_span, "found type parameter");
+ }
}
diag.note(
"a type parameter was expected, but a different one was found; \
@@ -72,32 +76,41 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
#traits-as-parameters",
);
}
- (ty::Alias(ty::Projection | ty::Inherent, _), ty::Alias(ty::Projection | ty::Inherent, _)) => {
+ (
+ ty::Alias(ty::Projection | ty::Inherent, _),
+ ty::Alias(ty::Projection | ty::Inherent, _),
+ ) => {
diag.note("an associated type was expected, but a different one was found");
}
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
- (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
+ (ty::Param(p), ty::Alias(ty::Projection, proj))
+ | (ty::Alias(ty::Projection, proj), ty::Param(p))
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
{
- let p_def_id = tcx
- .generics_of(body_owner_def_id)
- .type_param(p, tcx)
- .def_id;
- let p_span = tcx.def_span(p_def_id);
- if !sp.contains(p_span) {
- diag.span_label(p_span, "this type parameter");
- }
- let hir = tcx.hir();
- let mut note = true;
- let parent = p_def_id
- .as_local()
- .and_then(|id| {
- let local_id = hir.local_def_id_to_hir_id(id);
- let generics = tcx.hir().find_parent(local_id)?.generics()?;
- Some((id, generics))
+ let parent = tcx.generics_of(body_owner_def_id)
+ .opt_type_param(p, tcx)
+ .and_then(|param| {
+ let p_def_id = param.def_id;
+ let p_span = tcx.def_span(p_def_id);
+ let expected = match (values.expected.kind(), values.found.kind()) {
+ (ty::Param(_), _) => "expected ",
+ (_, ty::Param(_)) => "found ",
+ _ => "",
+ };
+ if !sp.contains(p_span) {
+ diag.span_label(
+ p_span,
+ format!("{expected}this type parameter"),
+ );
+ }
+ p_def_id.as_local().and_then(|id| {
+ let local_id = tcx.hir().local_def_id_to_hir_id(id);
+ let generics = tcx.hir().find_parent(local_id)?.generics()?;
+ Some((id, generics))
+ })
});
- if let Some((local_id, generics)) = parent
- {
+ let mut note = true;
+ if let Some((local_id, generics)) = parent {
// Synthesize the associated type restriction `Add<Output = Expected>`.
// FIXME: extract this logic for use in other diagnostics.
let (trait_ref, assoc_args) = proj.trait_ref_and_own_args(tcx);
@@ -112,15 +125,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut matching_span = None;
let mut matched_end_of_args = false;
for bound in generics.bounds_for_param(local_id) {
- let potential_spans = bound
- .bounds
- .iter()
- .find_map(|bound| {
- let bound_trait_path = bound.trait_ref()?.path;
- let def_id = bound_trait_path.res.opt_def_id()?;
- let generic_args = bound_trait_path.segments.iter().last().map(|path| path.args());
- (def_id == trait_ref.def_id).then_some((bound_trait_path.span, generic_args))
- });
+ let potential_spans = bound.bounds.iter().find_map(|bound| {
+ let bound_trait_path = bound.trait_ref()?.path;
+ let def_id = bound_trait_path.res.opt_def_id()?;
+ let generic_args = bound_trait_path
+ .segments
+ .iter()
+ .last()
+ .map(|path| path.args());
+ (def_id == trait_ref.def_id)
+ .then_some((bound_trait_path.span, generic_args))
+ });
if let Some((end_of_trait, end_of_args)) = potential_spans {
let args_span = end_of_args.and_then(|args| args.span());
@@ -167,9 +182,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
(ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
| (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
let generics = tcx.generics_of(body_owner_def_id);
- let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
- if !sp.contains(p_span) {
- diag.span_label(p_span, "this type parameter");
+ if let Some(param) = generics.opt_type_param(p, tcx) {
+ let p_span = tcx.def_span(param.def_id);
+ let expected = match (values.expected.kind(), values.found.kind()) {
+ (ty::Param(_), _) => "expected ",
+ (_, ty::Param(_)) => "found ",
+ _ => "",
+ };
+ if !sp.contains(p_span) {
+ diag.span_label(p_span, format!("{expected}this type parameter"));
+ }
}
diag.help("type parameters must be constrained to match other types");
if tcx.sess.teach(&diag.get_code().unwrap()) {
@@ -205,11 +227,13 @@ impl<T> Trait<T> for X {
#traits-as-parameters",
);
}
- (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => {
+ (ty::Param(p), ty::Closure(..) | ty::Coroutine(..)) => {
let generics = tcx.generics_of(body_owner_def_id);
- let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
- if !sp.contains(p_span) {
- diag.span_label(p_span, "this type parameter");
+ if let Some(param) = generics.opt_type_param(p, tcx) {
+ let p_span = tcx.def_span(param.def_id);
+ if !sp.contains(p_span) {
+ diag.span_label(p_span, "expected this type parameter");
+ }
}
diag.help(format!(
"every closure has a distinct type and so could not always match the \
@@ -218,12 +242,21 @@ impl<T> Trait<T> for X {
}
(ty::Param(p), _) | (_, ty::Param(p)) => {
let generics = tcx.generics_of(body_owner_def_id);
- let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
- if !sp.contains(p_span) {
- diag.span_label(p_span, "this type parameter");
+ if let Some(param) = generics.opt_type_param(p, tcx) {
+ let p_span = tcx.def_span(param.def_id);
+ let expected = match (values.expected.kind(), values.found.kind()) {
+ (ty::Param(_), _) => "expected ",
+ (_, ty::Param(_)) => "found ",
+ _ => "",
+ };
+ if !sp.contains(p_span) {
+ diag.span_label(p_span, format!("{expected}this type parameter"));
+ }
}
}
- (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
+ (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _)
+ if !tcx.is_impl_trait_in_trait(proj_ty.def_id) =>
+ {
self.expected_projection(
diag,
proj_ty,
@@ -232,11 +265,15 @@ impl<T> Trait<T> for X {
cause.code(),
);
}
- (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
- let msg = || format!(
- "consider constraining the associated type `{}` to `{}`",
- values.found, values.expected,
- );
+ (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty))
+ if !tcx.is_impl_trait_in_trait(proj_ty.def_id) =>
+ {
+ let msg = || {
+ format!(
+ "consider constraining the associated type `{}` to `{}`",
+ values.found, values.expected,
+ )
+ };
if !(self.suggest_constraining_opaque_associated_type(
diag,
msg,
@@ -256,19 +293,40 @@ impl<T> Trait<T> for X {
);
}
}
- (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::Fn | DefKind::Static(_) | DefKind::Const | DefKind::AssocFn | DefKind::AssocConst) => {
+ (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias))
+ if alias.def_id.is_local()
+ && matches!(
+ tcx.def_kind(body_owner_def_id),
+ DefKind::Fn
+ | DefKind::Static(_)
+ | DefKind::Const
+ | DefKind::AssocFn
+ | DefKind::AssocConst
+ ) =>
+ {
if tcx.is_type_alias_impl_trait(alias.def_id) {
- if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) {
- let sp = tcx.def_ident_span(body_owner_def_id).unwrap_or_else(|| tcx.def_span(body_owner_def_id));
- diag.span_note(sp, "\
+ if !tcx
+ .opaque_types_defined_by(body_owner_def_id.expect_local())
+ .contains(&alias.def_id.expect_local())
+ {
+ let sp = tcx
+ .def_ident_span(body_owner_def_id)
+ .unwrap_or_else(|| tcx.def_span(body_owner_def_id));
+ diag.span_note(
+ sp,
+ "\
this item must have the opaque type in its signature \
- in order to be able to register hidden types");
+ in order to be able to register hidden types",
+ );
}
}
}
- (ty::FnPtr(sig), ty::FnDef(def_id, _)) | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
+ (ty::FnPtr(sig), ty::FnDef(def_id, _))
+ | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() {
- diag.note("unsafe functions cannot be coerced into safe function pointers");
+ diag.note(
+ "unsafe functions cannot be coerced into safe function pointers",
+ );
}
}
_ => {}
@@ -283,7 +341,7 @@ impl<T> Trait<T> for X {
}
CyclicTy(ty) => {
// Watch out for various cases of cyclic types and try to explain.
- if ty.is_closure() || ty.is_generator() {
+ if ty.is_closure() || ty.is_coroutine() {
diag.note(
"closures cannot capture themselves or take themselves as argument;\n\
this error may be the result of a recent compiler bug-fix,\n\
@@ -314,39 +372,53 @@ impl<T> Trait<T> for X {
let tcx = self.tcx;
let assoc = tcx.associated_item(proj_ty.def_id);
let (trait_ref, assoc_args) = proj_ty.trait_ref_and_own_args(tcx);
- if let Some(item) = tcx.hir().get_if_local(body_owner_def_id) {
- if let Some(hir_generics) = item.generics() {
- // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
- // This will also work for `impl Trait`.
- let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() {
- let generics = tcx.generics_of(body_owner_def_id);
- generics.type_param(param_ty, tcx).def_id
- } else {
- return false;
- };
- let Some(def_id) = def_id.as_local() else {
- return false;
- };
-
- // First look in the `where` clause, as this might be
- // `fn foo<T>(x: T) where T: Trait`.
- for pred in hir_generics.bounds_for_param(def_id) {
- if self.constrain_generic_bound_associated_type_structured_suggestion(
- diag,
- &trait_ref,
- pred.bounds,
- assoc,
- assoc_args,
- ty,
- &msg,
- false,
- ) {
- return true;
- }
- }
+ let Some(item) = tcx.hir().get_if_local(body_owner_def_id) else {
+ return false;
+ };
+ let Some(hir_generics) = item.generics() else {
+ return false;
+ };
+ // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
+ // This will also work for `impl Trait`.
+ let ty::Param(param_ty) = proj_ty.self_ty().kind() else {
+ return false;
+ };
+ let generics = tcx.generics_of(body_owner_def_id);
+ let Some(param) = generics.opt_type_param(param_ty, tcx) else {
+ return false;
+ };
+ let Some(def_id) = param.def_id.as_local() else {
+ return false;
+ };
+
+ // First look in the `where` clause, as this might be
+ // `fn foo<T>(x: T) where T: Trait`.
+ for pred in hir_generics.bounds_for_param(def_id) {
+ if self.constrain_generic_bound_associated_type_structured_suggestion(
+ diag,
+ &trait_ref,
+ pred.bounds,
+ assoc,
+ assoc_args,
+ ty,
+ &msg,
+ false,
+ ) {
+ return true;
}
}
- false
+ if (param_ty.index as usize) >= generics.parent_count {
+ // The param comes from the current item, do not look at the parent. (#117209)
+ return false;
+ }
+ // If associated item, look to constrain the params of the trait/impl.
+ let hir_id = match item {
+ hir::Node::ImplItem(item) => item.hir_id(),
+ hir::Node::TraitItem(item) => item.hir_id(),
+ _ => return false,
+ };
+ let parent = tcx.hir().get_parent_item(hir_id).def_id;
+ self.suggest_constraint(diag, msg, parent.into(), proj_ty, ty)
}
/// An associated type was expected and a different type was found.
@@ -399,21 +471,26 @@ impl<T> Trait<T> for X {
let impl_comparison =
matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
let assoc = tcx.associated_item(proj_ty.def_id);
- if !callable_scope || impl_comparison {
+ if impl_comparison {
// We do not want to suggest calling functions when the reason of the
- // type error is a comparison of an `impl` with its `trait` or when the
- // scope is outside of a `Body`.
+ // type error is a comparison of an `impl` with its `trait`.
} else {
- // If we find a suitable associated function that returns the expected type, we don't
- // want the more general suggestion later in this method about "consider constraining
- // the associated type or calling a method that returns the associated type".
- let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
- diag,
- assoc.container_id(tcx),
- current_method_ident,
- proj_ty.def_id,
- values.expected,
- );
+ let point_at_assoc_fn = if callable_scope
+ && self.point_at_methods_that_satisfy_associated_type(
+ diag,
+ assoc.container_id(tcx),
+ current_method_ident,
+ proj_ty.def_id,
+ values.expected,
+ ) {
+ // If we find a suitable associated function that returns the expected type, we
+ // don't want the more general suggestion later in this method about "consider
+ // constraining the associated type or calling a method that returns the associated
+ // type".
+ true
+ } else {
+ false
+ };
// Possibly suggest constraining the associated type to conform to the
// found type.
if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found)
@@ -616,7 +693,8 @@ fn foo(&self) -> Self::T { String::new() }
for item in &items[..] {
if let hir::AssocItemKind::Type = item.kind {
let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
- if let hir::Defaultness::Default { has_value: true } = tcx.defaultness(item.id.owner_id)
+ if let hir::Defaultness::Default { has_value: true } =
+ tcx.defaultness(item.id.owner_id)
&& self.infcx.can_eq(param_env, assoc_ty, found)
{
diag.span_label(
@@ -706,9 +784,9 @@ fn foo(&self) -> Self::T { String::new() }
}
pub fn format_generic_args(&self, args: &[ty::GenericArg<'tcx>]) -> String {
- FmtPrinter::new(self.tcx, hir::def::Namespace::TypeNS)
- .path_generic_args(Ok, args)
- .expect("could not write to `String`.")
- .into_buffer()
+ FmtPrinter::print_string(self.tcx, hir::def::Namespace::TypeNS, |cx| {
+ cx.path_generic_args(|_| Ok(()), args)
+ })
+ .expect("could not write to `String`.")
}
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index f1d53cb59..fe18d0029 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -491,12 +491,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
if let hir::StmtKind::Local(hir::Local {
- span, pat: hir::Pat{..}, ty: None, init: Some(_), ..
- }) = &ex.kind
- && self.found_if
- && span.eq(&self.err_span) {
- self.result = true;
- }
+ span,
+ pat: hir::Pat { .. },
+ ty: None,
+ init: Some(_),
+ ..
+ }) = &ex.kind
+ && self.found_if
+ && span.eq(&self.err_span)
+ {
+ self.result = true;
+ }
walk_stmt(self, ex);
}
@@ -546,45 +551,59 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let expected = expected.unpack();
let found = found.unpack();
// 3. Extract the tuple type from Fn trait and suggest the change.
- if let GenericArgKind::Type(expected) = expected &&
- let GenericArgKind::Type(found) = found &&
- let ty::Tuple(expected) = expected.kind() &&
- let ty::Tuple(found)= found.kind() &&
- expected.len() == found.len() {
+ if let GenericArgKind::Type(expected) = expected
+ && let GenericArgKind::Type(found) = found
+ && let ty::Tuple(expected) = expected.kind()
+ && let ty::Tuple(found) = found.kind()
+ && expected.len() == found.len()
+ {
let mut suggestion = "|".to_string();
let mut is_first = true;
let mut has_suggestion = false;
- for (((expected, found), param_hir), arg_hir) in expected.iter()
- .zip(found.iter())
- .zip(params.iter())
- .zip(fn_decl.inputs.iter()) {
+ for (((expected, found), param_hir), arg_hir) in
+ expected.iter().zip(found.iter()).zip(params.iter()).zip(fn_decl.inputs.iter())
+ {
if is_first {
is_first = false;
} else {
suggestion += ", ";
}
- if let ty::Ref(expected_region, _, _) = expected.kind() &&
- let ty::Ref(found_region, _, _) = found.kind() &&
- expected_region.is_late_bound() &&
- !found_region.is_late_bound() &&
- let hir::TyKind::Infer = arg_hir.kind {
+ if let ty::Ref(expected_region, _, _) = expected.kind()
+ && let ty::Ref(found_region, _, _) = found.kind()
+ && expected_region.is_late_bound()
+ && !found_region.is_late_bound()
+ && let hir::TyKind::Infer = arg_hir.kind
+ {
// If the expected region is late bound, the found region is not, and users are asking compiler
// to infer the type, we can suggest adding `: &_`.
if param_hir.pat.span == param_hir.ty_span {
// for `|x|`, `|_|`, `|x: impl Foo|`
- let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
+ let Ok(pat) =
+ self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span)
+ else {
+ return;
+ };
suggestion += &format!("{pat}: &_");
} else {
// for `|x: ty|`, `|_: ty|`
- let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
- let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) else { return; };
+ let Ok(pat) =
+ self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span)
+ else {
+ return;
+ };
+ let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span)
+ else {
+ return;
+ };
suggestion += &format!("{pat}: &{ty}");
}
has_suggestion = true;
} else {
- let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { return; };
+ let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else {
+ return;
+ };
// Otherwise, keep it as-is.
suggestion += &arg;
}
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 0596ce373..35204478c 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -42,7 +42,7 @@ pub struct TypeFreshener<'a, 'tcx> {
ty_freshen_count: u32,
const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
- const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
+ const_freshen_map: FxHashMap<ty::InferConst, ty::Const<'tcx>>,
}
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
@@ -79,12 +79,12 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
fn freshen_const<F>(
&mut self,
opt_ct: Option<ty::Const<'tcx>>,
- key: ty::InferConst<'tcx>,
+ key: ty::InferConst,
freshener: F,
ty: Ty<'tcx>,
) -> ty::Const<'tcx>
where
- F: FnOnce(u32) -> ty::InferConst<'tcx>,
+ F: FnOnce(u32) -> ty::InferConst,
{
if let Some(ct) = opt_ct {
return ct.fold_with(self);
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index 86c2c2be4..7e878ac06 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -1,3 +1,4 @@
+use rustc_middle::infer::unify_key::ConstVidKey;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
@@ -23,14 +24,14 @@ where
}
fn const_vars_since_snapshot<'tcx>(
- table: &mut UnificationTable<'_, 'tcx, ConstVid<'tcx>>,
+ table: &mut UnificationTable<'_, 'tcx, ConstVidKey<'tcx>>,
snapshot_var_len: usize,
-) -> (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>) {
+) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) {
let range = vars_since_snapshot(table, snapshot_var_len);
(
- range.start..range.end,
- (range.start.index..range.end.index)
- .map(|index| table.probe_value(ConstVid::from_index(index)).origin)
+ range.start.vid..range.end.vid,
+ (range.start.index()..range.end.index())
+ .map(|index| table.probe_value(ConstVid::from_u32(index)).origin)
.collect(),
)
}
@@ -172,7 +173,7 @@ pub struct InferenceFudger<'a, 'tcx> {
int_vars: Range<IntVid>,
float_vars: Range<FloatVid>,
region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>),
- const_vars: (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>),
+ const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
}
impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
@@ -220,7 +221,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- if let ty::ReVar(vid) = *r && self.region_vars.0.contains(&vid) {
+ if let ty::ReVar(vid) = *r
+ && self.region_vars.0.contains(&vid)
+ {
let idx = vid.index() - self.region_vars.0.start.index();
let origin = self.region_vars.1[idx];
return self.infcx.next_region_var(origin);
@@ -233,7 +236,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
if self.const_vars.0.contains(&vid) {
// This variable was created during the fudging.
// Recreate it with a fresh variable here.
- let idx = (vid.index - self.const_vars.0.start.index) as usize;
+ let idx = (vid.index() - self.const_vars.0.start.index()) as usize;
let origin = self.const_vars.1[idx];
self.infcx.next_const_var(ct.ty(), origin)
} else {
diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs
index dd7f8d354..17fe3aa7b 100644
--- a/compiler/rustc_infer/src/infer/generalize.rs
+++ b/compiler/rustc_infer/src/infer/generalize.rs
@@ -17,7 +17,7 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
infcx: &InferCtxt<'tcx>,
delegate: &mut D,
term: T,
- for_vid: impl Into<ty::TermVid<'tcx>>,
+ for_vid: impl Into<ty::TermVid>,
ambient_variance: ty::Variance,
) -> RelateResult<'tcx, Generalization<T>> {
let (for_universe, root_vid) = match for_vid.into() {
@@ -27,7 +27,7 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
),
ty::TermVid::Const(ct_vid) => (
infcx.probe_const_var(ct_vid).unwrap_err(),
- ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid)),
+ ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid).vid),
),
};
@@ -127,7 +127,7 @@ struct Generalizer<'me, 'tcx, D> {
/// The vid of the type variable that is in the process of being
/// instantiated. If we find this within the value we are folding,
/// that means we would have created a cyclic value.
- root_vid: ty::TermVid<'tcx>,
+ root_vid: ty::TermVid,
/// The universe of the type variable that is in the process of being
/// instantiated. If we find anything that this universe cannot name,
@@ -183,7 +183,7 @@ where
// Avoid fetching the variance if we are in an invariant
// context; no need, and it can induce dependency cycles
// (e.g., #41849).
- relate::relate_args(self, a_subst, b_subst)
+ relate::relate_args_invariantly(self, a_subst, b_subst)
} else {
let tcx = self.tcx();
let opt_variances = tcx.variances_of(item_def_id);
@@ -376,7 +376,7 @@ where
// `vid` are related and we'd be inferring an infinitely
// deep const.
if ty::TermVid::Const(
- self.infcx.inner.borrow_mut().const_unification_table().find(vid),
+ self.infcx.inner.borrow_mut().const_unification_table().find(vid).vid,
) == self.root_vid
{
return Err(self.cyclic_term_error());
@@ -394,10 +394,14 @@ where
if self.for_universe.can_name(universe) {
Ok(c)
} else {
- let new_var_id = variable_table.new_key(ConstVarValue {
- origin: var_value.origin,
- val: ConstVariableValue::Unknown { universe: self.for_universe },
- });
+ let new_var_id = variable_table
+ .new_key(ConstVarValue {
+ origin: var_value.origin,
+ val: ConstVariableValue::Unknown {
+ universe: self.for_universe,
+ },
+ })
+ .vid;
Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty()))
}
}
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 cb6513639..bee0a978a 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -346,7 +346,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// tighter bound than `'static`.
//
// (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
- if let ty::RePlaceholder(p) = *lub && b_universe.cannot_name(p.universe) {
+ if let ty::RePlaceholder(p) = *lub
+ && b_universe.cannot_name(p.universe)
+ {
lub = self.tcx().lifetimes.re_static;
}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index aeb3177af..4ee897ffe 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -6,7 +6,9 @@ pub use self::RegionVariableOrigin::*;
pub use self::SubregionOrigin::*;
pub use self::ValuePairs::*;
pub use combine::ObligationEmittingRelation;
+use rustc_data_structures::captures::Captures;
use rustc_data_structures::undo_log::UndoLogs;
+use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey};
use self::opaque_types::OpaqueTypeStorage;
pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
@@ -36,11 +38,10 @@ use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtx
use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid};
use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef};
use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use std::cell::{Cell, RefCell};
use std::fmt;
-use std::marker::PhantomData;
use self::combine::CombineFields;
use self::error_reporting::TypeErrCtxt;
@@ -85,7 +86,7 @@ pub struct InferOk<'tcx, T> {
pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
-pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result"
+pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>,
@@ -108,7 +109,7 @@ pub struct InferCtxtInner<'tcx> {
type_variable_storage: type_variable::TypeVariableStorage<'tcx>,
/// Map from const parameter variable to the kind of const it represents.
- const_unification_storage: ut::UnificationTableStorage<ty::ConstVid<'tcx>>,
+ const_unification_storage: ut::UnificationTableStorage<ConstVidKey<'tcx>>,
/// Map from integral variable to the kind of integer it represents.
int_unification_storage: ut::UnificationTableStorage<ty::IntVid>,
@@ -117,7 +118,7 @@ pub struct InferCtxtInner<'tcx> {
float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
/// Map from effect variable to the effect param it represents.
- effect_unification_storage: ut::UnificationTableStorage<ty::EffectVid<'tcx>>,
+ effect_unification_storage: ut::UnificationTableStorage<EffectVidKey<'tcx>>,
/// Tracks the set of region variables and the constraints between them.
///
@@ -224,11 +225,11 @@ impl<'tcx> InferCtxtInner<'tcx> {
}
#[inline]
- fn const_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::ConstVid<'tcx>> {
+ fn const_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ConstVidKey<'tcx>> {
self.const_unification_storage.with_log(&mut self.undo_log)
}
- fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::EffectVid<'tcx>> {
+ fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, EffectVidKey<'tcx>> {
self.effect_unification_storage.with_log(&mut self.undo_log)
}
@@ -341,7 +342,9 @@ pub struct InferCtxt<'tcx> {
next_trait_solver: bool,
}
-impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
+impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
+ type Interner = TyCtxt<'tcx>;
+
fn universe_of_ty(&self, ty: ty::InferTy) -> Option<ty::UniverseIndex> {
use InferTy::*;
match ty {
@@ -357,7 +360,7 @@ impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
}
}
- fn universe_of_ct(&self, ct: ty::InferConst<'tcx>) -> Option<ty::UniverseIndex> {
+ fn universe_of_ct(&self, ct: ty::InferConst) -> Option<ty::UniverseIndex> {
use ty::InferConst::*;
match ct {
// Same issue as with `universe_of_ty`
@@ -546,11 +549,11 @@ pub enum NllRegionVariableOrigin {
// FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`.
#[derive(Copy, Clone, Debug)]
-pub enum FixupError<'tcx> {
+pub enum FixupError {
UnresolvedIntTy(IntVid),
UnresolvedFloatTy(FloatVid),
UnresolvedTy(TyVid),
- UnresolvedConst(ConstVid<'tcx>),
+ UnresolvedConst(ConstVid),
}
/// See the `region_obligations` field for more information.
@@ -561,7 +564,7 @@ pub struct RegionObligation<'tcx> {
pub origin: SubregionOrigin<'tcx>,
}
-impl<'tcx> fmt::Display for FixupError<'tcx> {
+impl fmt::Display for FixupError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::FixupError::*;
@@ -792,7 +795,7 @@ impl<'tcx> InferCtxt<'tcx> {
let mut table = inner.effect_unification_table();
(0..table.len())
- .map(|i| ty::EffectVid { index: i as u32, phantom: PhantomData })
+ .map(|i| ty::EffectVid::from_usize(i))
.filter(|&vid| table.probe_value(vid).is_none())
.map(|v| {
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool)
@@ -1070,15 +1073,20 @@ impl<'tcx> InferCtxt<'tcx> {
.inner
.borrow_mut()
.const_unification_table()
- .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } });
+ .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } })
+ .vid;
ty::Const::new_var(self.tcx, vid, ty)
}
- pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> {
- self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue {
- origin,
- val: ConstVariableValue::Unknown { universe: self.universe() },
- })
+ pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid {
+ self.inner
+ .borrow_mut()
+ .const_unification_table()
+ .new_key(ConstVarValue {
+ origin,
+ val: ConstVariableValue::Unknown { universe: self.universe() },
+ })
+ .vid
}
fn next_int_var_id(&self) -> IntVid {
@@ -1192,11 +1200,15 @@ impl<'tcx> InferCtxt<'tcx> {
),
span,
};
- let const_var_id =
- self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue {
+ let const_var_id = self
+ .inner
+ .borrow_mut()
+ .const_unification_table()
+ .new_key(ConstVarValue {
origin,
val: ConstVariableValue::Unknown { universe: self.universe() },
- });
+ })
+ .vid;
ty::Const::new_var(
self.tcx,
const_var_id,
@@ -1211,7 +1223,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
- let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
+ let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid;
let ty = self
.tcx
.type_of(param.def_id)
@@ -1331,12 +1343,12 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().type_variables().root_var(var)
}
- pub fn root_const_var(&self, var: ty::ConstVid<'tcx>) -> ty::ConstVid<'tcx> {
- self.inner.borrow_mut().const_unification_table().find(var)
+ pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
+ self.inner.borrow_mut().const_unification_table().find(var).vid
}
- pub fn root_effect_var(&self, var: ty::EffectVid<'tcx>) -> ty::EffectVid<'tcx> {
- self.inner.borrow_mut().effect_unification_table().find(var)
+ pub fn root_effect_var(&self, var: ty::EffectVid) -> ty::EffectVid {
+ self.inner.borrow_mut().effect_unification_table().find(var).vid
}
/// Resolves an int var to a rigid int type, if it was constrained to one,
@@ -1400,17 +1412,14 @@ impl<'tcx> InferCtxt<'tcx> {
value.visit_with(&mut resolve::UnresolvedTypeOrConstFinder::new(self)).break_value()
}
- pub fn probe_const_var(
- &self,
- vid: ty::ConstVid<'tcx>,
- ) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
+ pub fn probe_const_var(&self, vid: ty::ConstVid) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
match self.inner.borrow_mut().const_unification_table().probe_value(vid).val {
ConstVariableValue::Known { value } => Ok(value),
ConstVariableValue::Unknown { universe } => Err(universe),
}
}
- pub fn probe_effect_var(&self, vid: EffectVid<'tcx>) -> Option<EffectVarValue<'tcx>> {
+ pub fn probe_effect_var(&self, vid: EffectVid) -> Option<EffectVarValue<'tcx>> {
self.inner.borrow_mut().effect_unification_table().probe_value(vid)
}
@@ -1421,13 +1430,26 @@ impl<'tcx> InferCtxt<'tcx> {
///
/// This method is idempotent, but it not typically not invoked
/// except during the writeback phase.
- pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<'tcx, T> {
- let value = resolve::fully_resolve(self, value);
- assert!(
- value.as_ref().map_or(true, |value| !value.has_infer()),
- "`{value:?}` is not fully resolved"
- );
- value
+ pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<T> {
+ match resolve::fully_resolve(self, value) {
+ Ok(value) => {
+ if value.has_non_region_infer() {
+ bug!("`{value:?}` is not fully resolved");
+ }
+ if value.has_infer_regions() {
+ let guar = self
+ .tcx
+ .sess
+ .delay_span_bug(DUMMY_SP, format!("`{value:?}` is not fully resolved"));
+ Ok(self.tcx.fold_regions(value, |re, _| {
+ if re.is_var() { ty::Region::new_error(self.tcx, guar) } else { re }
+ }))
+ } else {
+ Ok(value)
+ }
+ }
+ Err(e) => Err(e),
+ }
}
// Instantiates the bound variables in a given binder with fresh inference
@@ -1632,11 +1654,11 @@ impl<'tcx> InferCtxt<'tcx> {
#[inline]
pub fn is_ty_infer_var_definitely_unchanged<'a>(
&'a self,
- ) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) {
+ ) -> (impl Fn(TyOrConstInferVar) -> bool + Captures<'tcx> + 'a) {
// This hoists the borrow/release out of the loop body.
let inner = self.inner.try_borrow();
- return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) {
+ return move |infer_var: TyOrConstInferVar| match (infer_var, &inner) {
(TyOrConstInferVar::Ty(ty_var), Ok(inner)) => {
use self::type_variable::TypeVariableValue;
@@ -1659,7 +1681,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// inference variables), and it handles both `Ty` and `ty::Const` without
/// having to resort to storing full `GenericArg`s in `stalled_on`.
#[inline(always)]
- pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool {
+ pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar) -> bool {
match infer_var {
TyOrConstInferVar::Ty(v) => {
use self::type_variable::TypeVariableValue;
@@ -1766,7 +1788,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
/// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently
/// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
#[derive(Copy, Clone, Debug)]
-pub enum TyOrConstInferVar<'tcx> {
+pub enum TyOrConstInferVar {
/// Equivalent to `ty::Infer(ty::TyVar(_))`.
Ty(TyVid),
/// Equivalent to `ty::Infer(ty::IntVar(_))`.
@@ -1775,12 +1797,12 @@ pub enum TyOrConstInferVar<'tcx> {
TyFloat(FloatVid),
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
- Const(ConstVid<'tcx>),
+ Const(ConstVid),
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`.
- Effect(EffectVid<'tcx>),
+ Effect(EffectVid),
}
-impl<'tcx> TyOrConstInferVar<'tcx> {
+impl<'tcx> TyOrConstInferVar {
/// Tries to extract an inference variable from a type or a constant, returns `None`
/// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and
/// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 1c3a5c360..7a5dec22f 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -362,6 +362,8 @@ impl<'tcx> InferCtxt<'tcx> {
.collect(),
);
+ // FIXME(#42940): This should use the `FreeRegionsVisitor`, but that's
+ // not currently sound until we have existential regions.
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
tcx: self.tcx,
op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions),
@@ -454,16 +456,16 @@ where
args.as_closure().sig_as_fn_ptr_ty().visit_with(self);
}
- ty::Generator(_, ref args, _) => {
+ ty::Coroutine(_, ref args, _) => {
// Skip lifetime parameters of the enclosing item(s)
// Also skip the witness type, because that has no free regions.
- for upvar in args.as_generator().upvar_tys() {
+ for upvar in args.as_coroutine().upvar_tys() {
upvar.visit_with(self);
}
- args.as_generator().return_ty().visit_with(self);
- args.as_generator().yield_ty().visit_with(self);
- args.as_generator().resume_ty().visit_with(self);
+ args.as_coroutine().return_ty().visit_with(self);
+ args.as_coroutine().yield_ty().visit_with(self);
+ args.as_coroutine().resume_ty().visit_with(self);
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, ref args, .. }) => {
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index 6a9d40daa..38819e8ad 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -102,17 +102,17 @@ fn compute_components<'tcx>(
compute_components(tcx, tupled_ty, out, visited);
}
- ty::Generator(_, ref args, _) => {
+ ty::Coroutine(_, ref args, _) => {
// Same as the closure case
- let tupled_ty = args.as_generator().tupled_upvars_ty();
+ let tupled_ty = args.as_coroutine().tupled_upvars_ty();
compute_components(tcx, tupled_ty, out, visited);
- // We ignore regions in the generator interior as we don't
+ // We ignore regions in the coroutine interior as we don't
// want these to affect region inference
}
// All regions are bound inside a witness
- ty::GeneratorWitness(..) => (),
+ ty::CoroutineWitness(..) => (),
// OutlivesTypeParameterEnv -- the actual checking that `X:'a`
// is implied by the environment is done in regionck.
diff --git a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs
new file mode 100644
index 000000000..398ac94ee
--- /dev/null
+++ b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs
@@ -0,0 +1,129 @@
+use rustc_middle::ty::{
+ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+};
+
+use std::ops::ControlFlow;
+
+use crate::infer::outlives::test_type_match;
+use crate::infer::region_constraints::VerifyIfEq;
+
+/// Visits free regions in the type that are relevant for liveness computation.
+/// These regions are passed to `OP`.
+///
+/// Specifically, we visit all of the regions of types recursively, except if
+/// the type is an alias, we look at the outlives bounds in the param-env
+/// and alias's item bounds. If there is a unique outlives bound, then visit
+/// that instead. If there is not a unique but there is a `'static` outlives
+/// bound, then don't visit anything. Otherwise, walk through the opaque's
+/// regions structurally.
+pub struct FreeRegionsVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
+ pub tcx: TyCtxt<'tcx>,
+ pub param_env: ty::ParamEnv<'tcx>,
+ pub op: OP,
+}
+
+impl<'tcx, OP> TypeVisitor<TyCtxt<'tcx>> for FreeRegionsVisitor<'tcx, OP>
+where
+ OP: FnMut(ty::Region<'tcx>),
+{
+ fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
+ &mut self,
+ t: &ty::Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ t.super_visit_with(self);
+ 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(()),
+ _ => {
+ (self.op)(r);
+ ControlFlow::Continue(())
+ }
+ }
+ }
+
+ 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(());
+ }
+
+ // FIXME: Don't consider alias bounds on types that have escaping bound
+ // vars. See #117455.
+ if ty.has_escaping_bound_vars() {
+ return ty.super_visit_with(self);
+ }
+
+ match ty.kind() {
+ // We can prove that an alias is live two ways:
+ // 1. All the components are live.
+ //
+ // 2. There is a known outlives bound or where-clause, and that
+ // region is live.
+ //
+ // We search through the item bounds and where clauses for
+ // either `'static` or a unique outlives region, and if one is
+ // found, we just need to prove that that region is still live.
+ // If one is not found, then we continue to walk through the alias.
+ ty::Alias(kind, ty::AliasTy { def_id, args, .. }) => {
+ let tcx = self.tcx;
+ let param_env = self.param_env;
+ let outlives_bounds: Vec<_> = tcx
+ .item_bounds(def_id)
+ .iter_instantiated(tcx, args)
+ .chain(param_env.caller_bounds())
+ .filter_map(|clause| {
+ let outlives = clause.as_type_outlives_clause()?;
+ if let Some(outlives) = outlives.no_bound_vars()
+ && outlives.0 == ty
+ {
+ Some(outlives.1)
+ } else {
+ test_type_match::extract_verify_if_eq(
+ tcx,
+ param_env,
+ &outlives.map_bound(|ty::OutlivesPredicate(ty, bound)| {
+ VerifyIfEq { ty, bound }
+ }),
+ ty,
+ )
+ }
+ })
+ .collect();
+ // If we find `'static`, then we know the alias doesn't capture *any* regions.
+ // Otherwise, all of the outlives regions should be equal -- if they're not,
+ // we don't really know how to proceed, so we continue recursing through the
+ // alias.
+ if outlives_bounds.contains(&tcx.lifetimes.re_static) {
+ // no
+ } else if let Some(r) = outlives_bounds.first()
+ && outlives_bounds[1..].iter().all(|other_r| other_r == r)
+ {
+ assert!(r.type_flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS));
+ r.visit_with(self)?;
+ } else {
+ // Skip lifetime parameters that are not captures.
+ let variances = match kind {
+ ty::Opaque => Some(self.tcx.variances_of(*def_id)),
+ _ => None,
+ };
+
+ for (idx, s) in args.iter().enumerate() {
+ if variances.map(|variances| variances[idx]) != Some(ty::Variance::Bivariant) {
+ s.visit_with(self)?;
+ }
+ }
+ }
+ }
+
+ _ => {
+ ty.super_visit_with(self)?;
+ }
+ }
+
+ ControlFlow::Continue(())
+ }
+}
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index cb92fc6dd..0987915f4 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -9,6 +9,7 @@ use rustc_middle::ty;
pub mod components;
pub mod env;
+pub mod for_liveness;
pub mod obligations;
pub mod test_type_match;
pub mod verify;
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
index fefa89595..6f973ee37 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -44,7 +44,7 @@ pub fn extract_verify_if_eq<'tcx>(
test_ty: Ty<'tcx>,
) -> Option<ty::Region<'tcx>> {
assert!(!verify_if_eq_b.has_escaping_bound_vars());
- let mut m = Match::new(tcx, param_env);
+ let mut m = MatchAgainstHigherRankedOutlives::new(tcx, param_env);
let verify_if_eq = verify_if_eq_b.skip_binder();
m.relate(verify_if_eq.ty, test_ty).ok()?;
@@ -87,24 +87,32 @@ pub(super) fn can_match_erased_ty<'tcx>(
// pointless micro-optimization
true
} else {
- Match::new(tcx, param_env).relate(outlives_ty, erased_ty).is_ok()
+ MatchAgainstHigherRankedOutlives::new(tcx, param_env).relate(outlives_ty, erased_ty).is_ok()
}
}
-struct Match<'tcx> {
+struct MatchAgainstHigherRankedOutlives<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
pattern_depth: ty::DebruijnIndex,
map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
}
-impl<'tcx> Match<'tcx> {
- fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Match<'tcx> {
- Match { tcx, param_env, pattern_depth: ty::INNERMOST, map: FxHashMap::default() }
+impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> {
+ fn new(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> MatchAgainstHigherRankedOutlives<'tcx> {
+ MatchAgainstHigherRankedOutlives {
+ tcx,
+ param_env,
+ pattern_depth: ty::INNERMOST,
+ map: FxHashMap::default(),
+ }
}
}
-impl<'tcx> Match<'tcx> {
+impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> {
/// Creates the "Error" variant that signals "no match".
fn no_match<T>(&self) -> RelateResult<'tcx, T> {
Err(TypeError::Mismatch)
@@ -134,7 +142,7 @@ impl<'tcx> Match<'tcx> {
}
}
-impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
+impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> {
fn tag(&self) -> &'static str {
"Match"
}
@@ -169,7 +177,9 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
value: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("self.pattern_depth = {:?}", self.pattern_depth);
- if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind() && depth == self.pattern_depth {
+ if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind()
+ && depth == self.pattern_depth
+ {
self.bind(br, value)
} else if pattern == value {
Ok(pattern)
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 4279d0ab7..7f0a4717d 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -108,20 +108,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
// Search the env for where clauses like `P: 'a`.
- 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 == alias_ty_as_ty {
- // Micro-optimize if this is an exact match (this
- // occurs often when there are no region variables
- // involved).
- VerifyBound::OutlivedBy(r)
- } else {
- let verify_if_eq_b = binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound });
- VerifyBound::IfEq(verify_if_eq_b)
- }
- });
+ 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 == alias_ty_as_ty
+ {
+ // Micro-optimize if this is an exact match (this
+ // occurs often when there are no region variables
+ // involved).
+ VerifyBound::OutlivedBy(r)
+ } else {
+ let verify_if_eq_b =
+ binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound });
+ VerifyBound::IfEq(verify_if_eq_b)
+ }
+ });
// Extend with bounds that we can find from the definition.
let definition_bounds =
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 708c51cab..3fa9a7333 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -457,7 +457,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
debug!("RegionConstraintCollector: add_verify({:?})", verify);
// skip no-op cases known to be satisfied
- if let VerifyBound::AllBounds(ref bs) = verify.bound && bs.is_empty() {
+ if let VerifyBound::AllBounds(ref bs) = verify.bound
+ && bs.is_empty()
+ {
return;
}
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 3c41e8b37..18a9cb6b4 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -192,7 +192,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for UnresolvedTypeOrConstFinder<'a, 'tc
/// Full type resolution replaces all type and region variables with
/// their concrete results. If any variable cannot be replaced (never unified, etc)
/// then an `Err` result is returned.
-pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<'tcx, T>
+pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<T>
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
@@ -206,7 +206,7 @@ struct FullTypeResolver<'a, 'tcx> {
}
impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
- type Error = FixupError<'tcx>;
+ type Error = FixupError;
fn interner(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 79144b3e6..565573051 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -3,7 +3,7 @@ use std::marker::PhantomData;
use rustc_data_structures::snapshot_vec as sv;
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
use rustc_data_structures::unify as ut;
-use rustc_middle::infer::unify_key::RegionVidKey;
+use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey, RegionVidKey};
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey};
use crate::{
@@ -21,10 +21,10 @@ pub struct Snapshot<'tcx> {
pub(crate) enum UndoLog<'tcx> {
OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
TypeVariables(type_variable::UndoLog<'tcx>),
- ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
+ ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
- EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
+ EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
ProjectionCache(traits::UndoLog<'tcx>),
@@ -56,9 +56,9 @@ impl_from! {
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
- EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
+ EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
- ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
+ ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
ProjectionCache(traits::UndoLog<'tcx>),
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index e92ba05aa..4a6d1bc68 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -13,6 +13,9 @@
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
#![feature(associated_type_bounds)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index e72a43630..329660119 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -5,7 +5,8 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::{self, TyCtxt};
use rustc_span::Span;
use std::fmt;
use std::iter;
@@ -62,7 +63,9 @@ pub fn report_object_safety_error<'tcx>(
let mut multi_span = vec![];
let mut messages = vec![];
for violation in violations {
- if let ObjectSafetyViolation::SizedSelf(sp) = &violation && !sp.is_empty() {
+ if let ObjectSafetyViolation::SizedSelf(sp) = &violation
+ && !sp.is_empty()
+ {
// Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations
// with a `Span`.
reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into()));
@@ -106,5 +109,66 @@ pub fn report_object_safety_error<'tcx>(
violation.solution(&mut err);
}
}
+
+ let impls_of = tcx.trait_impls_of(trait_def_id);
+ let impls = if impls_of.blanket_impls().is_empty() {
+ impls_of
+ .non_blanket_impls()
+ .values()
+ .flatten()
+ .filter(|def_id| {
+ !matches!(tcx.type_of(*def_id).instantiate_identity().kind(), ty::Dynamic(..))
+ })
+ .collect::<Vec<_>>()
+ } else {
+ vec![]
+ };
+ let externally_visible = if !impls.is_empty()
+ && let Some(def_id) = trait_def_id.as_local()
+ && tcx.effective_visibilities(()).is_exported(def_id)
+ {
+ true
+ } else {
+ false
+ };
+ match &impls[..] {
+ [] => {}
+ _ if impls.len() > 9 => {}
+ [only] if externally_visible => {
+ err.help(with_no_trimmed_paths!(format!(
+ "only type `{}` is seen to implement the trait in this crate, consider using it \
+ directly instead",
+ tcx.type_of(*only).instantiate_identity(),
+ )));
+ }
+ [only] => {
+ err.help(with_no_trimmed_paths!(format!(
+ "only type `{}` implements the trait, consider using it directly instead",
+ tcx.type_of(*only).instantiate_identity(),
+ )));
+ }
+ impls => {
+ let types = impls
+ .iter()
+ .map(|t| {
+ with_no_trimmed_paths!(format!(" {}", tcx.type_of(*t).instantiate_identity(),))
+ })
+ .collect::<Vec<_>>();
+ err.help(format!(
+ "the following types implement the trait, consider defining an enum where each \
+ variant holds one of these types, implementing `{}` for this new enum and using \
+ it instead:\n{}",
+ trait_str,
+ types.join("\n"),
+ ));
+ }
+ }
+ if externally_visible {
+ err.note(format!(
+ "`{trait_str}` can be implemented in other crates; if you want to support your users \
+ passing their own types here, you can't refer to a specific type",
+ ));
+ }
+
err
}
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index a5b2ccce8..a26e676c5 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -19,7 +19,6 @@ use rustc_span::Span;
pub use self::FulfillmentErrorCode::*;
pub use self::ImplSource::*;
-pub use self::ObligationCauseCode::*;
pub use self::SelectionError::*;
pub use self::engine::{TraitEngine, TraitEngineExt};
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 93dfbe63b..3c566e0dd 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -2,7 +2,7 @@ use smallvec::smallvec;
use crate::infer::outlives::components::{push_outlives_components, Component};
use crate::traits::{self, Obligation, PredicateObligation};
-use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::Ident;
use rustc_span::Span;
@@ -76,7 +76,13 @@ impl<'tcx> Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
pub struct Elaborator<'tcx, O> {
stack: Vec<O>,
visited: PredicateSet<'tcx>,
- only_self: bool,
+ mode: Filter,
+}
+
+enum Filter {
+ All,
+ OnlySelf,
+ OnlySelfThatDefines(Ident),
}
/// Describes how to elaborate an obligation into a sub-obligation.
@@ -224,7 +230,7 @@ pub fn elaborate<'tcx, O: Elaboratable<'tcx>>(
obligations: impl IntoIterator<Item = O>,
) -> Elaborator<'tcx, O> {
let mut elaborator =
- Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), only_self: false };
+ Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), mode: Filter::All };
elaborator.extend_deduped(obligations);
elaborator
}
@@ -242,7 +248,13 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
/// Filter to only the supertraits of trait predicates, i.e. only the predicates
/// that have `Self` as their self type, instead of all implied predicates.
pub fn filter_only_self(mut self) -> Self {
- self.only_self = true;
+ self.mode = Filter::OnlySelf;
+ self
+ }
+
+ /// Filter to only the supertraits of trait predicates that define the assoc_ty.
+ pub fn filter_only_self_that_defines(mut self, assoc_ty: Ident) -> Self {
+ self.mode = Filter::OnlySelfThatDefines(assoc_ty);
self
}
@@ -257,10 +269,12 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
return;
}
// Get predicates implied by the trait, or only super predicates if we only care about self predicates.
- let predicates = if self.only_self {
- tcx.super_predicates_of(data.def_id())
- } else {
- tcx.implied_predicates_of(data.def_id())
+ let predicates = match self.mode {
+ Filter::All => tcx.implied_predicates_of(data.def_id()),
+ Filter::OnlySelf => tcx.super_predicates_of(data.def_id()),
+ Filter::OnlySelfThatDefines(ident) => {
+ tcx.super_predicates_that_define_assoc_item((data.def_id(), ident))
+ }
};
let obligations =
@@ -409,14 +423,14 @@ impl<'tcx, O: Elaboratable<'tcx>> Iterator for Elaborator<'tcx, O> {
pub fn supertraits<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
-) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
+) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
elaborate(tcx, [trait_ref.to_predicate(tcx)]).filter_only_self().filter_to_traits()
}
pub fn transitive_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
-) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
+) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
.filter_only_self()
.filter_to_traits()
@@ -429,31 +443,12 @@ pub fn transitive_bounds<'tcx>(
/// `T::Item` and helps to avoid cycle errors (see e.g. #35237).
pub fn transitive_bounds_that_define_assoc_item<'tcx>(
tcx: TyCtxt<'tcx>,
- bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
+ trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
assoc_name: Ident,
-) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
- let mut stack: Vec<_> = bounds.collect();
- let mut visited = FxIndexSet::default();
-
- std::iter::from_fn(move || {
- while let Some(trait_ref) = stack.pop() {
- let anon_trait_ref = tcx.anonymize_bound_vars(trait_ref);
- if visited.insert(anon_trait_ref) {
- let super_predicates =
- tcx.super_predicates_that_define_assoc_item((trait_ref.def_id(), assoc_name));
- for (super_predicate, _) in super_predicates.predicates {
- let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
- if let Some(binder) = subst_predicate.as_trait_clause() {
- stack.push(binder.map_bound(|t| t.trait_ref));
- }
- }
-
- return Some(trait_ref);
- }
- }
-
- return None;
- })
+) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
+ elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
+ .filter_only_self_that_defines(assoc_name)
+ .filter_to_traits()
}
///////////////////////////////////////////////////////////////////////////