summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer')
-rw-r--r--compiler/rustc_infer/Cargo.toml1
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs505
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs177
-rw-r--r--compiler/rustc_infer/src/infer/at.rs13
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs19
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs94
-rw-r--r--compiler/rustc_infer/src/infer/canonical/substitute.rs7
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs99
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs19
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs643
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs421
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs147
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs10
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs60
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs18
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs9
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs37
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs20
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs151
-rw-r--r--compiler/rustc_infer/src/infer/free_regions.rs13
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs5
-rw-r--r--compiler/rustc_infer/src/infer/fudge.rs4
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs2
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs17
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs2
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs307
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs406
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs87
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs87
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/table.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs17
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs66
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs170
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs15
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs117
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs41
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs25
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs48
-rw-r--r--compiler/rustc_infer/src/infer/type_variable.rs1
-rw-r--r--compiler/rustc_infer/src/infer/undo_log.rs2
-rw-r--r--compiler/rustc_infer/src/lib.rs6
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs15
-rw-r--r--compiler/rustc_infer/src/traits/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs10
-rw-r--r--compiler/rustc_infer/src/traits/structural_impls.rs1
-rw-r--r--compiler/rustc_infer/src/traits/util.rs12
52 files changed, 2612 insertions, 1330 deletions
diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml
index 02ac83a5e..aced787d6 100644
--- a/compiler/rustc_infer/Cargo.toml
+++ b/compiler/rustc_infer/Cargo.toml
@@ -15,6 +15,7 @@ rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
+rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
new file mode 100644
index 000000000..2131d1906
--- /dev/null
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -0,0 +1,505 @@
+use hir::GenericParamKind;
+use rustc_errors::{
+ fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
+ MultiSpan, SubdiagnosticMessage,
+};
+use rustc_hir as hir;
+use rustc_hir::{FnRetTy, Ty};
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_middle::ty::{Region, TyCtxt};
+use rustc_span::symbol::kw;
+use rustc_span::{symbol::Ident, BytePos, Span};
+
+use crate::infer::error_reporting::{
+ need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
+ ObligationCauseAsDiagArg,
+};
+
+pub mod note_and_explain;
+
+#[derive(Diagnostic)]
+#[diag(infer_opaque_hidden_type)]
+pub struct OpaqueHiddenTypeDiag {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[note(opaque_type)]
+ pub opaque_type: Span,
+ #[note(hidden_type)]
+ pub hidden_type: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_type_annotations_needed, code = "E0282")]
+pub struct AnnotationRequired<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub source_kind: &'static str,
+ pub source_name: &'a str,
+ #[label]
+ pub failure_span: Option<Span>,
+ #[subdiagnostic]
+ pub bad_label: Option<InferenceBadError<'a>>,
+ #[subdiagnostic]
+ pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+ #[subdiagnostic]
+ pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+// Copy of `AnnotationRequired` for E0283
+#[derive(Diagnostic)]
+#[diag(infer_type_annotations_needed, code = "E0283")]
+pub struct AmbigousImpl<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub source_kind: &'static str,
+ pub source_name: &'a str,
+ #[label]
+ pub failure_span: Option<Span>,
+ #[subdiagnostic]
+ pub bad_label: Option<InferenceBadError<'a>>,
+ #[subdiagnostic]
+ pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+ #[subdiagnostic]
+ pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+// Copy of `AnnotationRequired` for E0284
+#[derive(Diagnostic)]
+#[diag(infer_type_annotations_needed, code = "E0284")]
+pub struct AmbigousReturn<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub source_kind: &'static str,
+ pub source_name: &'a str,
+ #[label]
+ pub failure_span: Option<Span>,
+ #[subdiagnostic]
+ pub bad_label: Option<InferenceBadError<'a>>,
+ #[subdiagnostic]
+ pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+ #[subdiagnostic]
+ pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_need_type_info_in_generator, code = "E0698")]
+pub struct NeedTypeInfoInGenerator<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub generator_kind: GeneratorKindAsDiagArg,
+ #[subdiagnostic]
+ pub bad_label: InferenceBadError<'a>,
+}
+
+// Used when a better one isn't available
+#[derive(Subdiagnostic)]
+#[label(infer_label_bad)]
+pub struct InferenceBadError<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub bad_kind: &'static str,
+ pub prefix_kind: UnderspecifiedArgKind,
+ pub has_parent: bool,
+ pub prefix: &'a str,
+ pub parent_prefix: &'a str,
+ pub parent_name: String,
+ pub name: String,
+}
+
+#[derive(Subdiagnostic)]
+pub enum SourceKindSubdiag<'a> {
+ #[suggestion_verbose(
+ infer_source_kind_subdiag_let,
+ code = ": {type_name}",
+ applicability = "has-placeholders"
+ )]
+ LetLike {
+ #[primary_span]
+ span: Span,
+ name: String,
+ type_name: String,
+ kind: &'static str,
+ x_kind: &'static str,
+ prefix_kind: UnderspecifiedArgKind,
+ prefix: &'a str,
+ arg_name: String,
+ },
+ #[label(infer_source_kind_subdiag_generic_label)]
+ GenericLabel {
+ #[primary_span]
+ span: Span,
+ is_type: bool,
+ param_name: String,
+ parent_exists: bool,
+ parent_prefix: String,
+ parent_name: String,
+ },
+ #[suggestion_verbose(
+ infer_source_kind_subdiag_generic_suggestion,
+ code = "::<{args}>",
+ applicability = "has-placeholders"
+ )]
+ GenericSuggestion {
+ #[primary_span]
+ span: Span,
+ arg_count: usize,
+ args: String,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub enum SourceKindMultiSuggestion<'a> {
+ #[multipart_suggestion_verbose(
+ infer_source_kind_fully_qualified,
+ applicability = "has-placeholders"
+ )]
+ FullyQualified {
+ #[suggestion_part(code = "{def_path}({adjustment}")]
+ span_lo: Span,
+ #[suggestion_part(code = "{successor_pos}")]
+ span_hi: Span,
+ def_path: String,
+ adjustment: &'a str,
+ successor_pos: &'a str,
+ },
+ #[multipart_suggestion_verbose(
+ infer_source_kind_closure_return,
+ applicability = "has-placeholders"
+ )]
+ ClosureReturn {
+ #[suggestion_part(code = "{start_span_code}")]
+ start_span: Span,
+ start_span_code: String,
+ #[suggestion_part(code = " }}")]
+ end_span: Option<Span>,
+ },
+}
+
+impl<'a> SourceKindMultiSuggestion<'a> {
+ pub fn new_fully_qualified(
+ span: Span,
+ def_path: String,
+ adjustment: &'a str,
+ successor: (&'a str, BytePos),
+ ) -> Self {
+ Self::FullyQualified {
+ span_lo: span.shrink_to_lo(),
+ span_hi: span.shrink_to_hi().with_hi(successor.1),
+ def_path,
+ adjustment,
+ successor_pos: successor.0,
+ }
+ }
+
+ pub fn new_closure_return(
+ ty_info: String,
+ data: &'a FnRetTy<'a>,
+ should_wrap_expr: Option<Span>,
+ ) -> Self {
+ let (arrow, post) = 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),
+ };
+ Self::ClosureReturn { start_span, start_span_code, end_span }
+ }
+}
+
+pub enum RegionOriginNote<'a> {
+ Plain {
+ span: Span,
+ msg: DiagnosticMessage,
+ },
+ WithName {
+ span: Span,
+ msg: DiagnosticMessage,
+ name: &'a str,
+ continues: bool,
+ },
+ WithRequirement {
+ span: Span,
+ requirement: ObligationCauseAsDiagArg<'a>,
+ expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
+ },
+}
+
+impl AddToDiagnostic for RegionOriginNote<'_> {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ let mut label_or_note = |span, msg: DiagnosticMessage| {
+ let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
+ let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
+ let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
+ if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
+ diag.span_label(span, msg);
+ } else if span_is_primary && expanded_sub_count == 0 {
+ diag.note(msg);
+ } else {
+ diag.span_note(span, msg);
+ }
+ };
+ match self {
+ RegionOriginNote::Plain { span, msg } => {
+ label_or_note(span, msg);
+ }
+ RegionOriginNote::WithName { span, msg, name, continues } => {
+ label_or_note(span, msg);
+ diag.set_arg("name", name);
+ diag.set_arg("continues", continues);
+ }
+ RegionOriginNote::WithRequirement {
+ span,
+ requirement,
+ expected_found: Some((expected, found)),
+ } => {
+ label_or_note(span, fluent::infer_subtype);
+ diag.set_arg("requirement", requirement);
+
+ diag.note_expected_found(&"", expected, &"", found);
+ }
+ RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
+ // FIXME: this really should be handled at some earlier stage. Our
+ // handling of region checking when type errors are present is
+ // *terrible*.
+ label_or_note(span, fluent::infer_subtype_2);
+ diag.set_arg("requirement", requirement);
+ }
+ };
+ }
+}
+
+pub enum LifetimeMismatchLabels {
+ InRet {
+ param_span: Span,
+ ret_span: Span,
+ span: Span,
+ label_var1: Option<Ident>,
+ },
+ Normal {
+ hir_equal: bool,
+ ty_sup: Span,
+ ty_sub: Span,
+ span: Span,
+ sup: Option<Ident>,
+ sub: Option<Ident>,
+ },
+}
+
+impl AddToDiagnostic for LifetimeMismatchLabels {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ match self {
+ LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
+ diag.span_label(param_span, fluent::infer_declared_different);
+ diag.span_label(ret_span, fluent::infer_nothing);
+ diag.span_label(span, fluent::infer_data_returned);
+ diag.set_arg("label_var1_exists", label_var1.is_some());
+ diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
+ }
+ LifetimeMismatchLabels::Normal {
+ hir_equal,
+ ty_sup,
+ ty_sub,
+ span,
+ sup: label_var1,
+ sub: label_var2,
+ } => {
+ if hir_equal {
+ diag.span_label(ty_sup, fluent::infer_declared_multiple);
+ diag.span_label(ty_sub, fluent::infer_nothing);
+ diag.span_label(span, fluent::infer_data_lifetime_flow);
+ } else {
+ diag.span_label(ty_sup, fluent::infer_types_declared_different);
+ diag.span_label(ty_sub, fluent::infer_nothing);
+ diag.span_label(span, fluent::infer_data_flows);
+ diag.set_arg("label_var1_exists", label_var1.is_some());
+ diag.set_arg(
+ "label_var1",
+ label_var1.map(|x| x.to_string()).unwrap_or_default(),
+ );
+ diag.set_arg("label_var2_exists", label_var2.is_some());
+ diag.set_arg(
+ "label_var2",
+ label_var2.map(|x| x.to_string()).unwrap_or_default(),
+ );
+ }
+ }
+ }
+ }
+}
+
+pub struct AddLifetimeParamsSuggestion<'a> {
+ pub tcx: TyCtxt<'a>,
+ pub sub: Region<'a>,
+ pub ty_sup: &'a Ty<'a>,
+ pub ty_sub: &'a Ty<'a>,
+ pub add_note: bool,
+}
+
+impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ let mut mk_suggestion = || {
+ let (
+ hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
+ hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+ ) = (self.ty_sub, self.ty_sup) else {
+ return false;
+ };
+
+ if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
+ return false;
+ };
+
+ let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
+ return false;
+ };
+
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
+
+ let node = self.tcx.hir().get(hir_id);
+ let is_impl = matches!(&node, hir::Node::ImplItem(_));
+ let generics = match node {
+ hir::Node::Item(&hir::Item {
+ kind: hir::ItemKind::Fn(_, ref generics, ..),
+ ..
+ })
+ | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
+ | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
+ _ => return false,
+ };
+
+ let suggestion_param_name = generics
+ .params
+ .iter()
+ .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+ .map(|p| p.name.ident().name)
+ .find(|i| *i != kw::UnderscoreLifetime);
+ let introduce_new = suggestion_param_name.is_none();
+ let suggestion_param_name =
+ suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
+
+ debug!(?lifetime_sup.span);
+ debug!(?lifetime_sub.span);
+ let make_suggestion = |span: rustc_span::Span| {
+ if span.is_empty() {
+ (span, format!("{}, ", suggestion_param_name))
+ } else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref()
+ {
+ (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
+ } else {
+ (span, suggestion_param_name.clone())
+ }
+ };
+ let mut suggestions =
+ vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
+
+ if introduce_new {
+ let new_param_suggestion = if let Some(first) =
+ generics.params.iter().find(|p| !p.name.ident().span.is_empty())
+ {
+ (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
+ } else {
+ (generics.span, format!("<{}>", suggestion_param_name))
+ };
+
+ suggestions.push(new_param_suggestion);
+ }
+
+ diag.multipart_suggestion(
+ fluent::infer_lifetime_param_suggestion,
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ diag.set_arg("is_impl", is_impl);
+ true
+ };
+ if mk_suggestion() && self.add_note {
+ diag.note(fluent::infer_lifetime_param_suggestion_elided);
+ }
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_lifetime_mismatch, code = "E0623")]
+pub struct LifetimeMismatch<'a> {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub labels: LifetimeMismatchLabels,
+ #[subdiagnostic]
+ pub suggestion: AddLifetimeParamsSuggestion<'a>,
+}
+
+pub struct IntroducesStaticBecauseUnmetLifetimeReq {
+ pub unmet_requirements: MultiSpan,
+ pub binding_span: Span,
+}
+
+impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
+ fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ self.unmet_requirements
+ .push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
+ diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req);
+ }
+}
+
+// FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
+#[derive(Subdiagnostic)]
+pub enum DoesNotOutliveStaticFromImpl {
+ #[note(infer_does_not_outlive_static_from_impl)]
+ Spanned {
+ #[primary_span]
+ span: Span,
+ },
+ #[note(infer_does_not_outlive_static_from_impl)]
+ Unspanned,
+}
+
+#[derive(Subdiagnostic)]
+pub enum ImplicitStaticLifetimeSubdiag {
+ #[note(infer_implicit_static_lifetime_note)]
+ Note {
+ #[primary_span]
+ span: Span,
+ },
+ #[suggestion_verbose(
+ infer_implicit_static_lifetime_suggestion,
+ code = " + '_",
+ applicability = "maybe-incorrect"
+ )]
+ Sugg {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_mismatched_static_lifetime)]
+pub struct MismatchedStaticLifetime<'a> {
+ #[primary_span]
+ pub cause_span: Span,
+ #[subdiagnostic]
+ pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq,
+ #[subdiagnostic]
+ pub expl: Option<note_and_explain::RegionExplanation<'a>>,
+ #[subdiagnostic]
+ pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
+ #[subdiagnostic(eager)]
+ pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
+}
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
new file mode 100644
index 000000000..6a29d8562
--- /dev/null
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -0,0 +1,177 @@
+use crate::infer::error_reporting::nice_region_error::find_anon_type;
+use rustc_errors::{
+ self, fluent, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessage,
+};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::{symbol::kw, Span};
+
+#[derive(Default)]
+struct DescriptionCtx<'a> {
+ span: Option<Span>,
+ kind: &'a str,
+ arg: String,
+ num_arg: u32,
+}
+
+impl<'a> DescriptionCtx<'a> {
+ fn new<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ region: ty::Region<'tcx>,
+ alt_span: Option<Span>,
+ ) -> Option<Self> {
+ let mut me = DescriptionCtx::default();
+ me.span = alt_span;
+ match *region {
+ ty::ReEarlyBound(_) | ty::ReFree(_) => {
+ return Self::from_early_bound_and_free_regions(tcx, region);
+ }
+ ty::ReStatic => {
+ me.kind = "restatic";
+ }
+
+ ty::RePlaceholder(_) => return None,
+
+ // FIXME(#13998) RePlaceholder should probably print like
+ // ReFree rather than dumping Debug output on the user.
+ //
+ // We shouldn't really be having unification failures with ReVar
+ // and ReLateBound though.
+ ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
+ me.kind = "revar";
+ me.arg = format!("{:?}", region);
+ }
+ };
+ Some(me)
+ }
+
+ fn from_early_bound_and_free_regions<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ region: ty::Region<'tcx>,
+ ) -> Option<Self> {
+ let mut me = DescriptionCtx::default();
+ let scope = region.free_region_binding_scope(tcx).expect_local();
+ match *region {
+ ty::ReEarlyBound(ref br) => {
+ let mut sp = tcx.def_span(scope);
+ if let Some(param) =
+ tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
+ {
+ sp = param.span;
+ }
+ if br.has_name() {
+ me.kind = "as_defined";
+ me.arg = br.name.to_string();
+ } else {
+ me.kind = "as_defined_anon";
+ };
+ me.span = Some(sp)
+ }
+ ty::ReFree(ref fr) => {
+ if !fr.bound_region.is_named()
+ && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
+ {
+ me.kind = "defined_here";
+ me.span = Some(ty.span);
+ } else {
+ match fr.bound_region {
+ ty::BoundRegionKind::BrNamed(_, name) => {
+ let mut sp = tcx.def_span(scope);
+ if let Some(param) =
+ tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+ {
+ sp = param.span;
+ }
+ if name == kw::UnderscoreLifetime {
+ me.kind = "as_defined_anon";
+ } else {
+ me.kind = "as_defined";
+ me.arg = name.to_string();
+ };
+ me.span = Some(sp);
+ }
+ ty::BrAnon(idx) => {
+ me.kind = "anon_num_here";
+ me.num_arg = idx+1;
+ me.span = Some(tcx.def_span(scope));
+ },
+ _ => {
+ me.kind = "defined_here_reg";
+ me.arg = region.to_string();
+ me.span = Some(tcx.def_span(scope));
+ },
+ }
+ }
+ }
+ _ => bug!(),
+ }
+ Some(me)
+ }
+
+ fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
+ diag.set_arg("desc_kind", self.kind);
+ diag.set_arg("desc_arg", self.arg);
+ diag.set_arg("desc_num_arg", self.num_arg);
+ }
+}
+
+pub enum PrefixKind {
+ Empty,
+}
+
+pub enum SuffixKind {
+ Continues,
+}
+
+impl IntoDiagnosticArg for PrefixKind {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ let kind = match self {
+ Self::Empty => "empty",
+ }
+ .into();
+ rustc_errors::DiagnosticArgValue::Str(kind)
+ }
+}
+
+impl IntoDiagnosticArg for SuffixKind {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ let kind = match self {
+ Self::Continues => "continues",
+ }
+ .into();
+ rustc_errors::DiagnosticArgValue::Str(kind)
+ }
+}
+
+pub struct RegionExplanation<'a> {
+ desc: DescriptionCtx<'a>,
+ prefix: PrefixKind,
+ suffix: SuffixKind,
+}
+
+impl RegionExplanation<'_> {
+ pub fn new<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ region: ty::Region<'tcx>,
+ alt_span: Option<Span>,
+ prefix: PrefixKind,
+ suffix: SuffixKind,
+ ) -> Option<Self> {
+ Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix })
+ }
+}
+
+impl AddToDiagnostic for RegionExplanation<'_> {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ if let Some(span) = self.desc.span {
+ diag.span_note(span, fluent::infer_region_explanation);
+ } else {
+ diag.note(fluent::infer_region_explanation);
+ }
+ self.desc.add_to(diag);
+ diag.set_arg("pref_kind", self.prefix);
+ diag.set_arg("suff_kind", self.suffix);
+ }
+}
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 130214a65..5ff3779fa 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -31,7 +31,7 @@ use rustc_middle::ty::relate::{Relate, TypeRelation};
use rustc_middle::ty::{Const, ImplSubject};
pub struct At<'a, 'tcx> {
- pub infcx: &'a InferCtxt<'a, 'tcx>,
+ pub infcx: &'a InferCtxt<'tcx>,
pub cause: &'a ObligationCause<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
/// Whether we should define opaque types
@@ -48,9 +48,9 @@ pub struct Trace<'a, 'tcx> {
trace: TypeTrace<'tcx>,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
#[inline]
- pub fn at(
+ pub fn at<'a>(
&'a self,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -66,7 +66,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
tcx: self.tcx,
defining_use_anchor: self.defining_use_anchor,
considering_regions: self.considering_regions,
- in_progress_typeck_results: self.in_progress_typeck_results,
inner: self.inner.clone(),
skip_leak_check: self.skip_leak_check.clone(),
lexical_region_resolutions: self.lexical_region_resolutions.clone(),
@@ -74,10 +73,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
evaluation_cache: self.evaluation_cache.clone(),
reported_trait_errors: self.reported_trait_errors.clone(),
reported_closure_mismatch: self.reported_closure_mismatch.clone(),
- tainted_by_errors_flag: self.tainted_by_errors_flag.clone(),
+ tainted_by_errors: self.tainted_by_errors.clone(),
err_count_on_creation: self.err_count_on_creation,
in_snapshot: self.in_snapshot.clone(),
universe: self.universe.clone(),
+ normalize_fn_sig_for_diagnostic: self
+ .normalize_fn_sig_for_diagnostic
+ .as_ref()
+ .map(|f| f.clone()),
}
}
}
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index ca7862c9d..a3ff70363 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -20,7 +20,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_index::vec::Idx;
use smallvec::SmallVec;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Canonicalizes a query value `V`. When we canonicalize a query,
/// we not only canonicalize unbound inference variables, but we
/// *also* replace all free regions whatsoever. So for example a
@@ -180,11 +180,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
match *r {
- ty::ReFree(_)
- | ty::ReErased
- | ty::ReStatic
- | ty::ReEmpty(ty::UniverseIndex::ROOT)
- | ty::ReEarlyBound(..) => r,
+ ty::ReFree(_) | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r,
ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) },
@@ -199,10 +195,6 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
)
}
- ty::ReEmpty(ui) => {
- bug!("canonicalizing 'empty in universe {:?}", ui) // FIXME
- }
-
_ => {
// Other than `'static` or `'empty`, the query
// response should be executing in a fully
@@ -324,7 +316,7 @@ impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
}
struct Canonicalizer<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>,
query_state: &'cx mut OriginalQueryValues<'tcx>,
@@ -372,7 +364,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
debug!(
"canonical: region var found with vid {:?}, \
opportunistically resolved to {:?}",
- vid, r
+ vid, resolved_vid
);
let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
self.canonicalize_mode.canonicalize_free_region(self, r)
@@ -381,7 +373,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
ty::ReStatic
| ty::ReEarlyBound(..)
| ty::ReFree(_)
- | ty::ReEmpty(_)
| ty::RePlaceholder(..)
| ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
}
@@ -530,7 +521,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
/// `canonicalize_query` and `canonicalize_response`.
fn canonicalize<V>(
value: V,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
canonicalize_region_mode: &dyn CanonicalizeMode,
query_state: &mut OriginalQueryValues<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index a9294a85e..06ca2534d 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -36,7 +36,7 @@ mod canonicalizer;
pub mod query_response;
mod substitute;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Creates a substitution S for the canonical value with fresh
/// inference variables and applies it to the canonical value.
/// Returns both the instantiated result *and* the substitution S.
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 8dc20544f..a299a3e57 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -16,12 +16,13 @@ use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelating
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
use crate::traits::query::{Fallible, NoSolution};
-use crate::traits::TraitEngine;
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
+use crate::traits::{PredicateObligations, TraitEngine};
use rustc_data_structures::captures::Captures;
use rustc_index::vec::Idx;
use rustc_index::vec::IndexVec;
use rustc_middle::arena::ArenaAllocatable;
+use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::relate::TypeRelation;
@@ -31,7 +32,7 @@ use rustc_span::Span;
use std::fmt::Debug;
use std::iter;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// This method is meant to be invoked as the final step of a canonical query
/// implementation. It is given:
///
@@ -63,8 +64,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
{
let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?;
+ debug!("query_response = {:#?}", query_response);
let canonical_result = self.canonicalize_response(query_response);
-
debug!("canonical_result = {:#?}", canonical_result);
Ok(self.tcx.arena.alloc(canonical_result))
@@ -125,13 +126,17 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
debug!("ambig_errors = {:#?}", ambig_errors);
let region_obligations = self.take_registered_region_obligations();
+ debug!(?region_obligations);
let region_constraints = self.with_region_constraints(|region_constraints| {
make_query_region_constraints(
tcx,
- region_obligations.iter().map(|r_o| (r_o.sup_type, r_o.sub_region)),
+ region_obligations
+ .iter()
+ .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())),
region_constraints,
)
});
+ debug!(?region_constraints);
let certainty =
if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
@@ -246,6 +251,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
// the original values `v_o` that was canonicalized into a
// variable...
+ let constraint_category = cause.to_constraint_category();
+
for (index, original_value) in original_values.var_values.iter().enumerate() {
// ...with the value `v_r` of that variable from the query.
let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| {
@@ -261,12 +268,14 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
(GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
if v_o != v_r {
- output_query_region_constraints
- .outlives
- .push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)));
- output_query_region_constraints
- .outlives
- .push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)));
+ output_query_region_constraints.outlives.push((
+ ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)),
+ constraint_category,
+ ));
+ output_query_region_constraints.outlives.push((
+ ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)),
+ constraint_category,
+ ));
}
}
@@ -312,7 +321,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
// Screen out `'a: 'a` cases -- we skip the binder here but
// only compare the inner values to one another, so they are still at
// consistent binding levels.
- let ty::OutlivesPredicate(k1, r2) = r_c.skip_binder();
+ let ty::OutlivesPredicate(k1, r2) = r_c.0.skip_binder();
if k1 != r2.into() { Some(r_c) } else { None }
}),
);
@@ -500,7 +509,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
for &(a, b) in &query_response.value.opaque_types {
let a = substitute_value(self.tcx, &result_subst, a);
let b = substitute_value(self.tcx, &result_subst, b);
- obligations.extend(self.handle_opaque_type(a, b, true, cause, param_env)?.obligations);
+ obligations.extend(self.at(cause, param_env).eq(a, b)?.obligations);
}
Ok(InferOk { value: result_subst, obligations })
@@ -557,7 +566,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Obligation<'tcx, ty::Predicate<'tcx>> {
- let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder();
+ let ty::OutlivesPredicate(k1, r2) = predicate.0.skip_binder();
let atom = match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
@@ -572,7 +581,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
}
};
- let predicate = predicate.rebind(atom).to_predicate(self.tcx);
+ let predicate = predicate.0.rebind(atom).to_predicate(self.tcx);
Obligation::new(cause, param_env, predicate)
}
@@ -623,7 +632,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// creates query region constraints.
pub fn make_query_region_constraints<'tcx>(
tcx: TyCtxt<'tcx>,
- outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>)>,
+ outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>,
region_constraints: &RegionConstraintData<'tcx>,
) -> QueryRegionConstraints<'tcx> {
let RegionConstraintData { constraints, verifys, givens, member_constraints } =
@@ -632,28 +641,35 @@ pub fn make_query_region_constraints<'tcx>(
assert!(verifys.is_empty());
assert!(givens.is_empty());
+ debug!(?constraints);
+
let outlives: Vec<_> = constraints
.iter()
- .map(|(k, _)| match *k {
- // Swap regions because we are going from sub (<=) to outlives
- // (>=).
- Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
- tcx.mk_region(ty::ReVar(v2)).into(),
- tcx.mk_region(ty::ReVar(v1)),
- ),
- Constraint::VarSubReg(v1, r2) => {
- ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
- }
- Constraint::RegSubVar(r1, v2) => {
- ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
- }
- Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
+ .map(|(k, origin)| {
+ // no bound vars in the code above
+ let constraint = ty::Binder::dummy(match *k {
+ // Swap regions because we are going from sub (<=) to outlives
+ // (>=).
+ Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
+ tcx.mk_region(ty::ReVar(v2)).into(),
+ tcx.mk_region(ty::ReVar(v1)),
+ ),
+ Constraint::VarSubReg(v1, r2) => {
+ ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
+ }
+ Constraint::RegSubVar(r1, v2) => {
+ ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
+ }
+ Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
+ });
+ (constraint, origin.to_constraint_category())
})
- .map(ty::Binder::dummy) // no bound vars in the code above
.chain(
outlives_obligations
- .map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r))
- .map(ty::Binder::dummy), // no bound vars in the code above
+ // no bound vars in the code above
+ .map(|(ty, r, constraint_category)| {
+ (ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), r)), constraint_category)
+ }),
)
.collect();
@@ -661,7 +677,7 @@ pub fn make_query_region_constraints<'tcx>(
}
struct QueryTypeRelatingDelegate<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
cause: &'a ObligationCause<'tcx>,
@@ -725,17 +741,11 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
true
}
- fn register_opaque_type(
+ fn register_opaque_type_obligations(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- a_is_expected: bool,
+ obligations: PredicateObligations<'tcx>,
) -> Result<(), TypeError<'tcx>> {
- self.obligations.extend(
- self.infcx
- .handle_opaque_type(a, b, a_is_expected, &self.cause, self.param_env)?
- .obligations,
- );
+ self.obligations.extend(obligations);
Ok(())
}
}
diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs
index 34b611342..389afe22e 100644
--- a/compiler/rustc_infer/src/infer/canonical/substitute.rs
+++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs
@@ -72,15 +72,16 @@ where
value
} else {
let delegate = FnMutDelegate {
- regions: |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() {
+ regions: &mut |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() {
GenericArgKind::Lifetime(l) => l,
r => bug!("{:?} is a region but value is {:?}", br, r),
},
- types: |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() {
+ types: &mut |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() {
GenericArgKind::Type(ty) => ty,
r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
},
- consts: |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack() {
+ consts: &mut |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack()
+ {
GenericArgKind::Const(ct) => ct,
c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
},
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 8bf1de34a..b5427f639 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -43,7 +43,7 @@ use rustc_span::{Span, DUMMY_SP};
#[derive(Clone)]
pub struct CombineFields<'infcx, 'tcx> {
- pub infcx: &'infcx InferCtxt<'infcx, 'tcx>,
+ pub infcx: &'infcx InferCtxt<'tcx>,
pub trace: TypeTrace<'tcx>,
pub cause: Option<ty::relate::Cause>,
pub param_env: ty::ParamEnv<'tcx>,
@@ -63,7 +63,7 @@ pub enum RelationDir {
EqTo,
}
-impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
pub fn super_combine_tys<R>(
&self,
relation: &mut R,
@@ -147,11 +147,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
ty::ConstKind::Infer(InferConst::Var(a_vid)),
ty::ConstKind::Infer(InferConst::Var(b_vid)),
) => {
- self.inner
- .borrow_mut()
- .const_unification_table()
- .unify_var_var(a_vid, b_vid)
- .map_err(|e| const_unification_error(a_is_expected, e))?;
+ self.inner.borrow_mut().const_unification_table().union(a_vid, b_vid);
return Ok(a);
}
@@ -246,21 +242,17 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
let value = ConstInferUnifier { infcx: self, span, param_env, for_universe, target_vid }
.relate(ct, ct)?;
- self.inner
- .borrow_mut()
- .const_unification_table()
- .unify_var_value(
- target_vid,
- ConstVarValue {
- origin: ConstVariableOrigin {
- kind: ConstVariableOriginKind::ConstInference,
- span: DUMMY_SP,
- },
- val: ConstVariableValue::Known { value },
+ self.inner.borrow_mut().const_unification_table().union_value(
+ target_vid,
+ ConstVarValue {
+ origin: ConstVariableOrigin {
+ kind: ConstVariableOriginKind::ConstInference,
+ span: DUMMY_SP,
},
- )
- .map(|()| value)
- .map_err(|e| const_unification_error(vid_is_expected, e))
+ val: ConstVariableValue::Known { value },
+ },
+ );
+ Ok(value)
}
fn unify_integral_variable(
@@ -391,7 +383,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
/// Preconditions:
///
/// - `for_vid` is a "root vid"
- #[instrument(skip(self), level = "trace")]
+ #[instrument(skip(self), level = "trace", ret)]
fn generalize(
&self,
ty: Ty<'tcx>,
@@ -435,15 +427,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
cache: SsoHashMap::new(),
};
- let ty = match generalize.relate(ty, ty) {
- Ok(ty) => ty,
- Err(e) => {
- debug!(?e, "failure");
- return Err(e);
- }
- };
+ let ty = generalize.relate(ty, ty)?;
let needs_wf = generalize.needs_wf;
- trace!(?ty, ?needs_wf, "success");
Ok(Generalization { ty, needs_wf })
}
@@ -467,7 +452,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
}
struct Generalizer<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
/// The span, used when creating new type variables and things.
cause: &'cx ObligationCause<'tcx>,
@@ -493,12 +478,13 @@ struct Generalizer<'cx, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
- cache: SsoHashMap<Ty<'tcx>, RelateResult<'tcx, Ty<'tcx>>>,
+ cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
}
/// Result from a generalization operation. This includes
/// not only the generalized type, but also a bool flag
/// indicating whether further WF checks are needed.
+#[derive(Debug)]
struct Generalization<'tcx> {
ty: Ty<'tcx>,
@@ -599,8 +585,8 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
- if let Some(result) = self.cache.get(&t) {
- return result.clone();
+ if let Some(&result) = self.cache.get(&t) {
+ return Ok(result);
}
debug!("generalize: t={:?}", t);
@@ -670,10 +656,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
Ok(t)
}
_ => relate::super_relate_tys(self, t, t),
- };
+ }?;
- self.cache.insert(t, result.clone());
- return result;
+ self.cache.insert(t, result);
+ Ok(result)
}
fn regions(
@@ -694,7 +680,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
ty::RePlaceholder(..)
| ty::ReVar(..)
- | ty::ReEmpty(_)
| ty::ReStatic
| ty::ReEarlyBound(..)
| ty::ReFree(..) => {
@@ -749,10 +734,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
}
}
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
- if self.tcx().lazy_normalization() =>
- {
- assert_eq!(promoted, None);
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
@@ -761,7 +743,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
)?;
Ok(self.tcx().mk_const(ty::ConstS {
ty: c.ty(),
- kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+ kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
}))
}
_ => relate::super_relate_consts(self, c, c),
@@ -776,13 +758,6 @@ pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> {
fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
}
-pub fn const_unification_error<'tcx>(
- a_is_expected: bool,
- (a, b): (ty::Const<'tcx>, ty::Const<'tcx>),
-) -> TypeError<'tcx> {
- TypeError::ConstMismatch(ExpectedFound::new(a_is_expected, a, b))
-}
-
fn int_unification_error<'tcx>(
a_is_expected: bool,
v: (ty::IntVarValue, ty::IntVarValue),
@@ -800,7 +775,7 @@ fn float_unification_error<'tcx>(
}
struct ConstInferUnifier<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
span: Span,
@@ -856,10 +831,9 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug_assert_eq!(t, _t);
- debug!("ConstInferUnifier: t={:?}", t);
match t.kind() {
&ty::Infer(ty::TyVar(vid)) => {
@@ -883,12 +857,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
.borrow_mut()
.type_variables()
.new_var(self.for_universe, origin);
- let u = self.tcx().mk_ty_var(new_var_id);
- debug!(
- "ConstInferUnifier: replacing original vid={:?} with new={:?}",
- vid, u
- );
- Ok(u)
+ Ok(self.tcx().mk_ty_var(new_var_id))
}
}
}
@@ -914,7 +883,6 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
ty::RePlaceholder(..)
| ty::ReVar(..)
- | ty::ReEmpty(_)
| ty::ReStatic
| ty::ReEarlyBound(..)
| ty::ReFree(..) => {
@@ -932,14 +900,13 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
}
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn consts(
&mut self,
c: ty::Const<'tcx>,
_c: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
debug_assert_eq!(c, _c);
- debug!("ConstInferUnifier: c={:?}", c);
match c.kind() {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
@@ -980,19 +947,17 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
}
}
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
- if self.tcx().lazy_normalization() =>
- {
- assert_eq!(promoted, None);
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
substs,
substs,
)?;
+
Ok(self.tcx().mk_const(ty::ConstS {
ty: c.ty(),
- kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+ kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
}))
}
_ => relate::super_relate_consts(self, c, c),
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 3b1798ca7..59728148a 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -110,6 +110,25 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
.obligations,
);
}
+ // Optimization of GeneratorWitness relation since we know that all
+ // free regions are replaced with bound regions during construction.
+ // This greatly speeds up equating of GeneratorWitness.
+ (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => {
+ let a_types = infcx.tcx.anonymize_bound_vars(a_types);
+ let b_types = infcx.tcx.anonymize_bound_vars(b_types);
+ if a_types.bound_vars() == b_types.bound_vars() {
+ let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders(
+ a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
+ );
+ for (a, b) in std::iter::zip(a_types, b_types) {
+ self.relate(a, b)?;
+ }
+ } else {
+ return Err(ty::error::TypeError::Sorts(ty::relate::expected_found(
+ self, a, b,
+ )));
+ }
+ }
_ => {
self.fields.infcx.super_combine_tys(self, a, b)?;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 20864c657..9ff703e52 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -51,6 +51,7 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa
use crate::infer;
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
+use crate::infer::ExpectedFound;
use crate::traits::error_reporting::report_object_safety_error;
use crate::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -58,30 +59,57 @@ use crate::traits::{
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
+use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::Node;
use rustc_middle::dep_graph::DepContext;
use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
use rustc_middle::ty::{
- self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable,
- TypeSuperVisitable, TypeVisitable,
+ self, error::TypeError, Binder, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+ TypeVisitable,
};
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
-use std::ops::ControlFlow;
+use std::ops::{ControlFlow, Deref};
use std::{cmp, fmt, iter};
mod note;
-mod need_type_info;
+pub(crate) mod need_type_info;
pub use need_type_info::TypeAnnotationNeeded;
pub mod nice_region_error;
+/// A helper for building type related errors. The `typeck_results`
+/// field is only populated during an in-progress typeck.
+/// Get an instance by calling `InferCtxt::err` or `FnCtxt::infer_err`.
+pub struct TypeErrCtxt<'a, 'tcx> {
+ pub infcx: &'a InferCtxt<'tcx>,
+ pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
+}
+
+impl TypeErrCtxt<'_, '_> {
+ /// This is just to avoid a potential footgun of accidentally
+ /// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
+ #[deprecated(note = "you already have a `TypeErrCtxt`")]
+ #[allow(unused)]
+ pub fn err_ctxt(&self) -> ! {
+ bug!("called `err_ctxt` on `TypeErrCtxt`. Try removing the call");
+ }
+}
+
+impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> {
+ type Target = InferCtxt<'tcx>;
+ fn deref(&self) -> &InferCtxt<'tcx> {
+ &self.infcx
+ }
+}
+
pub(super) fn note_and_explain_region<'tcx>(
tcx: TyCtxt<'tcx>,
err: &mut Diagnostic,
@@ -95,11 +123,6 @@ pub(super) fn note_and_explain_region<'tcx>(
msg_span_from_free_region(tcx, region, alt_span)
}
- ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), alt_span),
-
- // uh oh, hope no user ever sees THIS
- ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), alt_span),
-
ty::RePlaceholder(_) => return,
// FIXME(#13998) RePlaceholder should probably print like
@@ -138,8 +161,6 @@ fn msg_span_from_free_region<'tcx>(
(msg, Some(span))
}
ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
- ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), alt_span),
- ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), alt_span),
_ => bug!("{:?}", region),
}
}
@@ -249,17 +270,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
// Explain the region we are capturing.
match *hidden_region {
- ty::ReEmpty(ty::UniverseIndex::ROOT) => {
- // All lifetimes shorter than the function body are `empty` in
- // lexical region resolution. The default explanation of "an empty
- // lifetime" isn't really accurate here.
- let message = format!(
- "hidden type `{}` captures lifetime smaller than the function body",
- hidden_ty
- );
- err.span_note(span, &message);
- }
- ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) => {
+ ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
// Assuming regionck succeeded (*), we ought to always be
// capturing *some* region from the fn header, and hence it
// ought to be free. So under normal circumstances, we will go
@@ -318,7 +329,38 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
err
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
+ pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
+ if let ty::Opaque(def_id, substs) = ty.kind() {
+ let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
+ // Future::Output
+ let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
+
+ let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
+
+ for (predicate, _) in bounds.subst_iter_copied(self.tcx, substs) {
+ let output = predicate
+ .kind()
+ .map_bound(|kind| match kind {
+ ty::PredicateKind::Projection(projection_predicate)
+ if projection_predicate.projection_ty.item_def_id == item_def_id =>
+ {
+ projection_predicate.term.ty()
+ }
+ _ => None,
+ })
+ .transpose();
+ if output.is_some() {
+ // We don't account for multiple `Future::Output = Ty` constraints.
+ return output;
+ }
+ }
+ }
+ None
+ }
+}
+
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pub fn report_region_errors(
&self,
generic_param_scope: LocalDefId,
@@ -385,7 +427,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
RegionResolutionError::UpperBoundUniverseConflict(
_,
_,
- var_universe,
+ _,
sup_origin,
sup_r,
) => {
@@ -396,7 +438,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// placeholder. In practice, we expect more
// tailored errors that don't really use this
// value.
- let sub_r = self.tcx.mk_region(ty::ReEmpty(var_universe));
+ let sub_r = self.tcx.lifetimes.re_erased;
self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
}
@@ -457,7 +499,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
/// Adds a note if the types come from similarly named crates
- fn check_and_note_conflicting_crates(&self, err: &mut Diagnostic, terr: &TypeError<'tcx>) {
+ fn check_and_note_conflicting_crates(&self, err: &mut Diagnostic, terr: TypeError<'tcx>) {
use hir::def_id::CrateNum;
use rustc_hir::definitions::DisambiguatedDefPathData;
use ty::print::Printer;
@@ -561,7 +603,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
};
- match *terr {
+ match terr {
TypeError::Sorts(ref exp_found) => {
// if they are both "path types", there's a chance of ambiguity
// due to different versions of the same crate
@@ -583,7 +625,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err: &mut Diagnostic,
cause: &ObligationCause<'tcx>,
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
- terr: &TypeError<'tcx>,
+ terr: TypeError<'tcx>,
) {
match *cause.code() {
ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
@@ -592,13 +634,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
{
// don't show type `_`
if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
- && let ty::Adt(def, substs) = ty.kind()
- && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
+ && let ty::Adt(def, substs) = ty.kind()
+ && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
{
err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
} else {
- err.span_label(span, format!("this expression has type `{}`", ty));
- }
+ 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
@@ -634,8 +676,8 @@ impl<'a, 'tcx> InferCtxt<'a, '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.in_progress_typeck_results.and_then(|typeck_results| {
- typeck_results.borrow().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");
@@ -739,12 +781,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err.help("...or use `match` instead of `let...else`");
}
_ => {
- if let ObligationCauseCode::BindingObligation(_, binding_span) =
- cause.code().peel_derives()
+ if let ObligationCauseCode::BindingObligation(_, span)
+ | ObligationCauseCode::ExprBindingObligation(_, span, ..)
+ = cause.code().peel_derives()
+ && let TypeError::RegionsPlaceholderMismatch = terr
{
- if matches!(terr, TypeError::RegionsPlaceholderMismatch) {
- err.span_note(*binding_span, "the lifetime requirement is introduced here");
- }
+ err.span_note( * span,
+ "the lifetime requirement is introduced here");
}
}
}
@@ -960,12 +1003,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
+ fn normalize_fn_sig_for_diagnostic(&self, sig: ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> {
+ if let Some(normalize) = &self.normalize_fn_sig_for_diagnostic {
+ normalize(self, sig)
+ } else {
+ sig
+ }
+ }
+
/// Given two `fn` signatures highlight only sub-parts that are different.
fn cmp_fn_sig(
&self,
sig1: &ty::PolyFnSig<'tcx>,
sig2: &ty::PolyFnSig<'tcx>,
) -> (DiagnosticStyledString, DiagnosticStyledString) {
+ let sig1 = &self.normalize_fn_sig_for_diagnostic(*sig1);
+ let sig2 = &self.normalize_fn_sig_for_diagnostic(*sig2);
+
let get_lifetimes = |sig| {
use rustc_hir::def::Namespace;
let (_, sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS)
@@ -1422,9 +1476,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// the message in `secondary_span` as the primary label, and apply the message that would
/// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on
/// E0271, like `src/test/ui/issues/issue-39970.stderr`.
- #[tracing::instrument(
+ #[instrument(
level = "debug",
- skip(self, diag, secondary_span, swap_secondary_and_primary, force_label)
+ skip(self, diag, secondary_span, swap_secondary_and_primary, prefer_label)
)]
pub fn note_type_err(
&self,
@@ -1432,9 +1486,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
cause: &ObligationCause<'tcx>,
secondary_span: Option<(Span, String)>,
mut values: Option<ValuePairs<'tcx>>,
- terr: &TypeError<'tcx>,
+ terr: TypeError<'tcx>,
swap_secondary_and_primary: bool,
- force_label: bool,
+ prefer_label: bool,
) {
let span = cause.span();
@@ -1574,23 +1628,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Some(values) => {
let values = self.resolve_vars_if_possible(values);
let (is_simple_error, exp_found) = match values {
- ValuePairs::Terms(infer::ExpectedFound {
- expected: ty::Term::Ty(expected),
- found: ty::Term::Ty(found),
- }) => {
- let is_simple_err = expected.is_simple_text() && found.is_simple_text();
- OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
- .report(diag);
-
- (
- is_simple_err,
- Mismatch::Variable(infer::ExpectedFound { expected, found }),
- )
+ ValuePairs::Terms(infer::ExpectedFound { expected, found }) => {
+ match (expected.unpack(), found.unpack()) {
+ (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
+ let is_simple_err =
+ expected.is_simple_text() && found.is_simple_text();
+ OpaqueTypesVisitor::visit_expected_found(
+ self.tcx, expected, found, span,
+ )
+ .report(diag);
+
+ (
+ is_simple_err,
+ Mismatch::Variable(infer::ExpectedFound { expected, found }),
+ )
+ }
+ (ty::TermKind::Const(_), ty::TermKind::Const(_)) => {
+ (false, Mismatch::Fixed("constant"))
+ }
+ _ => (false, Mismatch::Fixed("type")),
+ }
}
ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
(false, Mismatch::Fixed("trait"))
}
- _ => (false, Mismatch::Fixed("type")),
+ ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
};
let vals = match self.values_str(values) {
Some((expected, found)) => Some((expected, found)),
@@ -1612,7 +1674,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
TypeError::ObjectUnsafeCoercion(_) => {}
_ => {
let mut label_or_note = |span: Span, msg: &str| {
- if force_label || &[span] == diag.span.primary_spans() {
+ if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() {
diag.span_label(span, msg);
} else {
diag.span_note(span, msg);
@@ -1649,8 +1711,114 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
),
Mismatch::Fixed(s) => (s.into(), s.into(), None),
};
- match (&terr, expected == found) {
- (TypeError::Sorts(values), extra) => {
+
+ enum Similar<'tcx> {
+ Adts { expected: ty::AdtDef<'tcx>, found: ty::AdtDef<'tcx> },
+ PrimitiveFound { expected: ty::AdtDef<'tcx>, found: Ty<'tcx> },
+ PrimitiveExpected { expected: Ty<'tcx>, found: ty::AdtDef<'tcx> },
+ }
+
+ let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| {
+ 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() {
+ 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() {
+ 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.
+ // A "perhaps two different versions..." error is already emitted for that.
+ return None;
+ }
+ 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});
+ }
+ }
+ None
+ };
+
+ match terr {
+ // If two types mismatch but have similar names, mention that specifically.
+ TypeError::Sorts(values) if let Some(s) = similarity(values) => {
+ let diagnose_primitive =
+ |prim: Ty<'tcx>,
+ shadow: Ty<'tcx>,
+ defid: DefId,
+ diagnostic: &mut Diagnostic| {
+ let name = shadow.sort_string(self.tcx);
+ diagnostic.note(format!(
+ "{prim} and {name} have similar names, but are actually distinct types"
+ ));
+ diagnostic
+ .note(format!("{prim} is a primitive defined by the language"));
+ let def_span = self.tcx.def_span(defid);
+ let msg = if defid.is_local() {
+ format!("{name} is defined in the current crate")
+ } else {
+ let crate_name = self.tcx.crate_name(defid.krate);
+ format!("{name} is defined in crate `{crate_name}")
+ };
+ diagnostic.span_note(def_span, msg);
+ };
+
+ let diagnose_adts =
+ |expected_adt : ty::AdtDef<'tcx>,
+ found_adt: ty::AdtDef<'tcx>,
+ diagnostic: &mut Diagnostic| {
+ let found_name = values.found.sort_string(self.tcx);
+ let expected_name = values.expected.sort_string(self.tcx);
+
+ let found_defid = found_adt.did();
+ let expected_defid = expected_adt.did();
+
+ diagnostic.note(format!("{found_name} and {expected_name} have similar names, but are actually distinct types"));
+ for (defid, name) in
+ [(found_defid, found_name), (expected_defid, expected_name)]
+ {
+ let def_span = self.tcx.def_span(defid);
+
+ let msg = if found_defid.is_local() && expected_defid.is_local() {
+ let module = self
+ .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")
+ } else if defid.is_local() {
+ format!("{name} is defined in the current crate")
+ } else {
+ let crate_name = self.tcx.crate_name(defid.krate);
+ format!("{name} is defined in crate `{crate_name}`")
+ };
+ diagnostic.span_note(def_span, msg);
+ }
+ };
+
+ match s {
+ 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} => {
+ diagnose_primitive(prim, values.found, found.did(), diag)
+ }
+ }
+ }
+ TypeError::Sorts(values) => {
+ let extra = expected == found;
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
(true, ty::Opaque(def_id, _)) => {
let sm = self.tcx.sess.source_map();
@@ -1662,6 +1830,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pos.col.to_usize() + 1,
)
}
+ (true, ty::Projection(proj))
+ if self.tcx.def_kind(proj.item_def_id)
+ == DefKind::ImplTraitPlaceholder =>
+ {
+ let sm = self.tcx.sess.source_map();
+ let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
+ format!(
+ " (trait associated opaque type at <{}:{}:{}>)",
+ sm.filename_for_diagnostics(&pos.file.name),
+ pos.line,
+ pos.col.to_usize() + 1,
+ )
+ }
(true, _) => format!(" ({})", ty.sort_string(self.tcx)),
(false, _) => "".to_string(),
};
@@ -1690,10 +1871,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
);
}
}
- (TypeError::ObjectUnsafeCoercion(_), _) => {
+ TypeError::ObjectUnsafeCoercion(_) => {
diag.note_unsuccessful_coercion(found, expected);
}
- (_, _) => {
+ _ => {
debug!(
"note_type_err: exp_found={:?}, expected={:?} found={:?}",
exp_found, expected, found
@@ -1713,7 +1894,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
ty::error::TypeError::Sorts(terr)
if exp_found.map_or(false, |ef| terr.found == ef.found) =>
{
- Some(*terr)
+ Some(terr)
}
_ => exp_found,
};
@@ -1738,7 +1919,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// In some (most?) cases cause.body_id points to actual body, but in some cases
// it's an actual definition. According to the comments (e.g. in
- // librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter
+ // rustc_hir_analysis/check/compare_method.rs:compare_predicate_entailment) the latter
// is relied upon by some other code. This might (or might not) need cleanup.
let body_owner_def_id =
self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
@@ -1750,6 +1931,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
&& let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind()
&& let Some(def_id) = def_id.as_local()
+ && terr.involves_regions()
{
let span = self.tcx.def_span(def_id);
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
@@ -1829,36 +2011,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
- pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
- if let ty::Opaque(def_id, substs) = ty.kind() {
- let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
- // Future::Output
- let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
-
- let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
-
- for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
- let predicate = predicate.subst(self.tcx, substs);
- let output = predicate
- .kind()
- .map_bound(|kind| match kind {
- ty::PredicateKind::Projection(projection_predicate)
- if projection_predicate.projection_ty.item_def_id == item_def_id =>
- {
- projection_predicate.term.ty()
- }
- _ => None,
- })
- .transpose();
- if output.is_some() {
- // We don't account for multiple `Future::Output = Ty` constraints.
- return output;
- }
- }
- }
- None
- }
-
/// A possible error is to forget to add `.await` when using futures:
///
/// ```compile_fail,E0308
@@ -2033,26 +2185,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
diag: &mut Diagnostic,
) {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+ && let Some(msg) = self.should_suggest_as_ref(exp_found.expected, exp_found.found)
+ {
+ diag.span_suggestion(
+ span,
+ msg,
+ // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
+ format!("{}.as_ref()", snippet.trim_start_matches('&')),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
+ pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) =
- (exp_found.expected.kind(), exp_found.found.kind())
+ (expected.kind(), found.kind())
{
if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
- let path_str = format!("{:?}", exp_def);
if exp_def == &found_def {
- let opt_msg = "you can convert from `&Option<T>` to `Option<&T>` using \
- `.as_ref()`";
- let result_msg = "you can convert from `&Result<T, E>` to \
- `Result<&T, &E>` using `.as_ref()`";
let have_as_ref = &[
- ("std::option::Option", opt_msg),
- ("core::option::Option", opt_msg),
- ("std::result::Result", result_msg),
- ("core::result::Result", result_msg),
+ (
+ sym::Option,
+ "you can convert from `&Option<T>` to `Option<&T>` using \
+ `.as_ref()`",
+ ),
+ (
+ sym::Result,
+ "you can convert from `&Result<T, E>` to \
+ `Result<&T, &E>` using `.as_ref()`",
+ ),
];
- if let Some(msg) = have_as_ref
- .iter()
- .find_map(|(path, msg)| (&path_str == path).then_some(msg))
- {
+ if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| {
+ self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg)
+ }) {
let mut show_suggestion = true;
for (exp_ty, found_ty) in
iter::zip(exp_substs.types(), found_substs.types())
@@ -2072,26 +2238,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => show_suggestion = false,
}
}
- if let (Ok(snippet), true) =
- (self.tcx.sess.source_map().span_to_snippet(span), show_suggestion)
- {
- diag.span_suggestion(
- span,
- *msg,
- format!("{}.as_ref()", snippet),
- Applicability::MachineApplicable,
- );
+ if show_suggestion {
+ return Some(*msg);
}
}
}
}
}
+ None
}
pub fn report_and_explain_type_error(
&self,
trace: TypeTrace<'tcx>,
- terr: &TypeError<'tcx>,
+ terr: TypeError<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
use crate::traits::ObligationCauseCode::MatchExpressionArm;
@@ -2111,6 +2271,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
}
FailureCode::Error0308(failure_str) => {
+ fn escape_literal(s: &str) -> String {
+ let mut escaped = String::with_capacity(s.len());
+ let mut chrs = s.chars().peekable();
+ while let Some(first) = chrs.next() {
+ match (first, chrs.peek()) {
+ ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => {
+ escaped.push('\\');
+ escaped.push(delim);
+ chrs.next();
+ }
+ ('"' | '\'', _) => {
+ escaped.push('\\');
+ escaped.push(first)
+ }
+ (c, _) => escaped.push(c),
+ };
+ }
+ escaped
+ }
let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
if let Some((expected, found)) = trace.values.ty() {
match (expected.kind(), found.kind()) {
@@ -2132,7 +2311,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err.span_suggestion(
span,
"if you meant to write a `char` literal, use single quotes",
- format!("'{}'", code),
+ format!("'{}'", escape_literal(code)),
Applicability::MachineApplicable,
);
}
@@ -2147,7 +2326,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err.span_suggestion(
span,
"if you meant to write a `str` literal, use double quotes",
- format!("\"{}\"", code),
+ format!("\"{}\"", escape_literal(code)),
Applicability::MachineApplicable,
);
}
@@ -2254,11 +2433,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
return None;
}
- Some(match (exp_found.expected, exp_found.found) {
- (ty::Term::Ty(expected), ty::Term::Ty(found)) => self.cmp(expected, found),
- (expected, found) => (
- DiagnosticStyledString::highlighted(expected.to_string()),
- DiagnosticStyledString::highlighted(found.to_string()),
+ Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) {
+ (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found),
+ _ => (
+ DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
+ DiagnosticStyledString::highlighted(exp_found.found.to_string()),
),
})
}
@@ -2298,7 +2477,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: Option<SubregionOrigin<'tcx>>,
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>,
- ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+ ) -> 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);
@@ -2314,7 +2493,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// We do this to avoid suggesting code that ends up as `T: 'a'b`,
// instead we suggest `T: 'a + 'b` in that case.
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let ast_generics = self.tcx.hir().get_generics(hir_id.owner);
+ let 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
@@ -2355,6 +2534,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
+ GenericKind::Opaque(def_id, substs) => {
+ format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs))
+ }
};
if let Some(SubregionOrigin::CompareImplItemObligation {
@@ -2376,19 +2558,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
type_param_span: Option<(Span, bool)>,
bound_kind: GenericKind<'tcx>,
sub: S,
+ add_lt_sugg: Option<(Span, String)>,
) {
let msg = "consider adding an explicit lifetime bound";
if let Some((sp, has_lifetimes)) = type_param_span {
let suggestion =
if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) };
- err.span_suggestion_verbose(
- sp,
- &format!("{}...", msg),
- suggestion,
+ let mut suggestions = vec![(sp, suggestion)];
+ if let Some(add_lt_sugg) = add_lt_sugg {
+ suggestions.push(add_lt_sugg);
+ }
+ err.multipart_suggestion_verbose(
+ format!("{msg}..."),
+ suggestions,
Applicability::MaybeIncorrect, // Issue #41966
);
} else {
- let consider = format!("{} `{}: {}`...", msg, bound_kind, sub,);
+ let consider = format!("{} `{}: {}`...", msg, bound_kind, sub);
err.help(&consider);
}
}
@@ -2404,7 +2590,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
};
let mut sugg =
vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))];
- if let Some(lt) = add_lt_sugg {
+ if let Some(lt) = add_lt_sugg.clone() {
sugg.push(lt);
sugg.rotate_right(1);
}
@@ -2430,7 +2616,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
for h in self.tcx.hir().parent_iter(param.hir_id) {
break 'origin match h.1 {
Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::TyAlias(..),
+ kind: hir::ImplItemKind::Type(..),
generics,
..
})
@@ -2510,7 +2696,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// for the bound is not suitable for suggestions when `-Zverbose` is set because it
// uses `Debug` output, so we handle it specially here so that suggestions are
// always correct.
- binding_suggestion(&mut err, type_param_span, bound_kind, name);
+ binding_suggestion(&mut err, type_param_span, bound_kind, name, None);
err
}
@@ -2523,7 +2709,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"{} may not live long enough",
labeled_user_string
);
- binding_suggestion(&mut err, type_param_span, bound_kind, "'static");
+ binding_suggestion(&mut err, type_param_span, bound_kind, "'static", None);
err
}
@@ -2557,7 +2743,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
new_binding_suggestion(&mut err, type_param_span);
}
_ => {
- binding_suggestion(&mut err, type_param_span, bound_kind, new_lt);
+ binding_suggestion(
+ &mut err,
+ type_param_span,
+ bound_kind,
+ new_lt,
+ add_lt_sugg,
+ );
}
}
}
@@ -2659,70 +2851,98 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Float types, respectively). When comparing two ADTs, these rules apply recursively.
pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
let (a, b) = self.resolve_vars_if_possible((a, b));
- match (a.kind(), b.kind()) {
- (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) => {
- if def_a != def_b {
- return false;
- }
+ SameTypeModuloInfer(self).relate(a, b).is_ok()
+ }
+}
- substs_a
- .types()
- .zip(substs_b.types())
- .all(|(a, b)| self.same_type_modulo_infer(a, b))
- }
- (&ty::FnDef(did_a, substs_a), &ty::FnDef(did_b, substs_b)) => {
- if did_a != did_b {
- return false;
- }
+struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>);
- substs_a
- .types()
- .zip(substs_b.types())
- .all(|(a, b)| self.same_type_modulo_infer(a, b))
- }
- (&ty::Int(_) | &ty::Uint(_), &ty::Infer(ty::InferTy::IntVar(_)))
+impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.0.tcx
+ }
+
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ // Unused, only for consts which we treat as always equal
+ ty::ParamEnv::empty()
+ }
+
+ fn tag(&self) -> &'static str {
+ "SameTypeModuloInfer"
+ }
+
+ fn a_is_expected(&self) -> bool {
+ true
+ }
+
+ fn relate_with_variance<T: relate::Relate<'tcx>>(
+ &mut self,
+ _variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
+ a: T,
+ b: T,
+ ) -> relate::RelateResult<'tcx, T> {
+ self.relate(a, b)
+ }
+
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ match (a.kind(), b.kind()) {
+ (ty::Int(_) | ty::Uint(_), ty::Infer(ty::InferTy::IntVar(_)))
| (
- &ty::Infer(ty::InferTy::IntVar(_)),
- &ty::Int(_) | &ty::Uint(_) | &ty::Infer(ty::InferTy::IntVar(_)),
+ ty::Infer(ty::InferTy::IntVar(_)),
+ ty::Int(_) | ty::Uint(_) | ty::Infer(ty::InferTy::IntVar(_)),
)
- | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
+ | (ty::Float(_), ty::Infer(ty::InferTy::FloatVar(_)))
| (
- &ty::Infer(ty::InferTy::FloatVar(_)),
- &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)),
+ ty::Infer(ty::InferTy::FloatVar(_)),
+ ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)),
)
- | (&ty::Infer(ty::InferTy::TyVar(_)), _)
- | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
- (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => {
- mut_a == mut_b && self.same_type_modulo_infer(ty_a, ty_b)
- }
- (&ty::RawPtr(a), &ty::RawPtr(b)) => {
- a.mutbl == b.mutbl && self.same_type_modulo_infer(a.ty, b.ty)
- }
- (&ty::Slice(a), &ty::Slice(b)) => self.same_type_modulo_infer(a, b),
- (&ty::Array(a_ty, a_ct), &ty::Array(b_ty, b_ct)) => {
- self.same_type_modulo_infer(a_ty, b_ty) && a_ct == b_ct
- }
- (&ty::Tuple(a), &ty::Tuple(b)) => {
- if a.len() != b.len() {
- return false;
- }
- std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b))
- }
- (&ty::FnPtr(a), &ty::FnPtr(b)) => {
- let a = a.skip_binder().inputs_and_output;
- let b = b.skip_binder().inputs_and_output;
- if a.len() != b.len() {
- return false;
- }
- std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b))
- }
- // FIXME(compiler-errors): This needs to be generalized more
- _ => a == b,
+ | (ty::Infer(ty::InferTy::TyVar(_)), _)
+ | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a),
+ (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch),
+ _ => relate::super_relate_tys(self, a, b),
}
}
+
+ fn regions(
+ &mut self,
+ a: ty::Region<'tcx>,
+ b: ty::Region<'tcx>,
+ ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+ if (a.is_var() && b.is_free_or_static())
+ || (b.is_var() && a.is_free_or_static())
+ || (a.is_var() && b.is_var())
+ || a == b
+ {
+ Ok(a)
+ } else {
+ Err(TypeError::Mismatch)
+ }
+ }
+
+ fn binders<T>(
+ &mut self,
+ a: ty::Binder<'tcx, T>,
+ b: ty::Binder<'tcx, T>,
+ ) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>>
+ where
+ T: relate::Relate<'tcx>,
+ {
+ Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
+ }
+
+ fn consts(
+ &mut self,
+ a: ty::Const<'tcx>,
+ _b: ty::Const<'tcx>,
+ ) -> relate::RelateResult<'tcx, ty::Const<'tcx>> {
+ // FIXME(compiler-errors): This could at least do some first-order
+ // relation
+ Ok(a)
+ }
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
fn report_inference_failure(
&self,
var_origin: RegionVariableOrigin,
@@ -2781,12 +3001,12 @@ pub enum FailureCode {
}
pub trait ObligationCauseExt<'tcx> {
- fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode;
+ fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode;
fn as_requirement_str(&self) -> &'static str;
}
impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
- fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode {
+ fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode {
use self::FailureCode::*;
use crate::traits::ObligationCauseCode::*;
match self.code() {
@@ -2823,7 +3043,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
TypeError::IntrinsicCast => {
Error0308("cannot coerce intrinsics to function pointers")
}
- TypeError::ObjectUnsafeCoercion(did) => Error0038(*did),
+ TypeError::ObjectUnsafeCoercion(did) => Error0038(did),
_ => Error0308("mismatched types"),
},
}
@@ -2853,6 +3073,30 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
}
}
+/// Newtype to allow implementing IntoDiagnosticArg
+pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>);
+
+impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ use crate::traits::ObligationCauseCode::*;
+ let kind = match self.0.code() {
+ CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat",
+ CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => "type_compat",
+ CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => "const_compat",
+ ExprAssignable => "expr_assignable",
+ IfExpression { .. } => "if_else_different",
+ IfExpressionWithNoElse => "no_else",
+ MainFunctionType => "fn_main_correct_type",
+ StartFunctionType => "fn_start_correct_type",
+ IntrinsicType => "intristic_correct_type",
+ MethodReceiver => "method_correct_type",
+ _ => "other",
+ }
+ .into();
+ rustc_errors::DiagnosticArgValue::Str(kind)
+ }
+}
+
/// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks
/// extra information about each type, but we only care about the category.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
@@ -2886,7 +3130,7 @@ impl TyCategory {
}
}
-impl<'tcx> InferCtxt<'_, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Given a [`hir::Block`], get the span of its last expression or
/// statement, peeling off any inner blocks.
pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
@@ -2913,7 +3157,9 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
_ => rustc_span::DUMMY_SP,
}
}
+}
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
/// Be helpful when the user wrote `{... expr; }` and taking the `;` off
/// is enough to fix the error.
pub fn could_remove_semicolon(
@@ -2930,7 +3176,7 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else {
return None;
};
- let last_expr_ty = self.in_progress_typeck_results?.borrow().expr_ty_opt(*last_expr)?;
+ let last_expr_ty = self.typeck_results.as_ref()?.expr_ty_opt(*last_expr)?;
let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
_ if last_expr_ty.references_error() => return None,
_ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => {
@@ -3013,8 +3259,9 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
&& let Some(pat_ty) = self
- .in_progress_typeck_results
- .and_then(|typeck_results| typeck_results.borrow().node_type_opt(*hir_id))
+ .typeck_results
+ .as_ref()
+ .and_then(|typeck_results| typeck_results.node_type_opt(*hir_id))
{
let pat_ty = self.resolve_vars_if_possible(pat_ty);
if self.same_type_modulo_infer(pat_ty, expected_ty)
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 561d1354e..7b3178e61 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
@@ -1,6 +1,12 @@
+use crate::errors::{
+ AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
+ SourceKindMultiSuggestion, SourceKindSubdiag,
+};
+use crate::infer::error_reporting::TypeErrCtxt;
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::InferCtxt;
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::IntoDiagnostic;
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
@@ -11,8 +17,8 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
use rustc_middle::ty::{self, DefIdTree, InferConst};
+use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
use rustc_span::symbol::{kw, Ident};
use rustc_span::{BytePos, Span};
@@ -60,38 +66,49 @@ pub struct InferenceDiagnosticsParentData {
name: String,
}
+#[derive(Clone)]
pub enum UnderspecifiedArgKind {
Type { prefix: Cow<'static, str> },
Const { is_parameter: bool },
}
impl InferenceDiagnosticsData {
- /// Generate a label for a generic argument which can't be inferred. When not
- /// much is known about the argument, `use_diag` may be used to describe the
- /// labeled value.
- fn cannot_infer_msg(&self) -> String {
- if self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }) {
- return "cannot infer type".to_string();
- }
-
- let suffix = match &self.parent {
- Some(parent) => parent.suffix_string(),
- None => String::new(),
- };
-
- // For example: "cannot infer type for type parameter `T`"
- format!("cannot infer {} `{}`{}", self.kind.prefix_string(), self.name, suffix)
+ fn can_add_more_info(&self) -> bool {
+ !(self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }))
}
- fn where_x_is_specified(&self, in_type: Ty<'_>) -> String {
+ fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str {
if in_type.is_ty_infer() {
- String::new()
+ "empty"
} else if self.name == "_" {
// FIXME: Consider specializing this message if there is a single `_`
// in the type.
- ", where the placeholders `_` are specified".to_string()
+ "underscore"
} else {
- format!(", where the {} `{}` is specified", self.kind.prefix_string(), self.name)
+ "has_name"
+ }
+ }
+
+ /// Generate a label for a generic argument which can't be inferred. When not
+ /// much is known about the argument, `use_diag` may be used to describe the
+ /// labeled value.
+ fn make_bad_error(&self, span: Span) -> InferenceBadError<'_> {
+ let has_parent = self.parent.is_some();
+ let bad_kind = if self.can_add_more_info() { "more_info" } else { "other" };
+ let (parent_prefix, parent_name) = self
+ .parent
+ .as_ref()
+ .map(|parent| (parent.prefix, parent.name.clone()))
+ .unwrap_or_default();
+ InferenceBadError {
+ span,
+ bad_kind,
+ prefix_kind: self.kind.clone(),
+ prefix: self.kind.try_get_prefix().unwrap_or_default(),
+ name: self.name.clone(),
+ has_parent,
+ parent_prefix,
+ parent_name,
}
}
}
@@ -113,23 +130,29 @@ impl InferenceDiagnosticsParentData {
fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
Self::for_parent_def_id(tcx, tcx.parent(def_id))
}
+}
- fn suffix_string(&self) -> String {
- format!(" declared on the {} `{}`", self.prefix, self.name)
+impl IntoDiagnosticArg for UnderspecifiedArgKind {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ let kind = match self {
+ Self::Type { .. } => "type",
+ Self::Const { is_parameter: true } => "const_with_param",
+ Self::Const { is_parameter: false } => "const",
+ };
+ rustc_errors::DiagnosticArgValue::Str(kind.into())
}
}
impl UnderspecifiedArgKind {
- fn prefix_string(&self) -> Cow<'static, str> {
+ fn try_get_prefix(&self) -> Option<&str> {
match self {
- Self::Type { prefix } => format!("type for {}", prefix).into(),
- Self::Const { is_parameter: true } => "the value of const parameter".into(),
- Self::Const { is_parameter: false } => "the value of the constant".into(),
+ Self::Type { prefix } => Some(prefix.as_ref()),
+ Self::Const { .. } => None,
}
}
}
-fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
+fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
let mut printer = FmtPrinter::new(infcx.tcx, ns);
let ty_getter = move |ty_vid| {
if infcx.probe_ty_var(ty_vid).is_ok() {
@@ -160,7 +183,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPr
printer
}
-fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+fn ty_to_string<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
let printer = fmt_printer(infcx, Namespace::TypeNS);
let ty = infcx.resolve_vars_if_possible(ty);
match ty.kind() {
@@ -177,9 +200,9 @@ fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
}
/// We don't want to directly use `ty_to_string` for closures as their type isn't really
-/// something users are familar with. Directly printing the `fn_sig` of closures also
+/// something users are familiar with. Directly printing the `fn_sig` of closures also
/// doesn't work as they actually use the "rust-call" API.
-fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
let ty::Closure(_, substs) = ty.kind() else { unreachable!() };
let fn_sig = substs.as_closure().sig();
let args = fn_sig
@@ -203,7 +226,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String
format!("fn({}){}", args, ret)
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Extracts data used by diagnostic for either types or constants
/// which were stuck during inference.
pub fn extract_inference_diagnostics_data(
@@ -295,7 +318,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
- /// Used as a fallback in [InferCtxt::emit_inference_failure_err]
+ /// Used as a fallback in [TypeErrCtxt::emit_inference_failure_err]
/// in case we weren't able to get a better error.
fn bad_inference_failure_err(
&self,
@@ -303,13 +326,48 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
arg_data: InferenceDiagnosticsData,
error_code: TypeAnnotationNeeded,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let error_code = error_code.into();
- let mut err =
- self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);
- err.span_label(span, arg_data.cannot_infer_msg());
- err
+ let source_kind = "other";
+ let source_name = "";
+ let failure_span = None;
+ let infer_subdiags = Vec::new();
+ let multi_suggestions = Vec::new();
+ let bad_label = Some(arg_data.make_bad_error(span));
+ match error_code {
+ TypeAnnotationNeeded::E0282 => AnnotationRequired {
+ span,
+ source_kind,
+ source_name,
+ failure_span,
+ infer_subdiags,
+ multi_suggestions,
+ bad_label,
+ }
+ .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
+ TypeAnnotationNeeded::E0283 => AmbigousImpl {
+ span,
+ source_kind,
+ source_name,
+ failure_span,
+ infer_subdiags,
+ multi_suggestions,
+ bad_label,
+ }
+ .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
+ TypeAnnotationNeeded::E0284 => AmbigousReturn {
+ span,
+ source_kind,
+ source_name,
+ failure_span,
+ infer_subdiags,
+ multi_suggestions,
+ bad_label,
+ }
+ .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
+ }
}
+}
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pub fn emit_inference_failure_err(
&self,
body_id: Option<hir::BodyId>,
@@ -321,14 +379,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let arg = self.resolve_vars_if_possible(arg);
let arg_data = self.extract_inference_diagnostics_data(arg, None);
- let Some(typeck_results) = self.in_progress_typeck_results else {
+ let Some(typeck_results) = &self.typeck_results else {
// If we don't have any typeck results we're outside
// of a body, so we won't be able to get better info
// here.
return self.bad_inference_failure_err(failure_span, arg_data, error_code);
};
- let typeck_results = typeck_results.borrow();
- let typeck_results = &typeck_results;
let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg);
if let Some(body_id) = body_id {
@@ -340,48 +396,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
return self.bad_inference_failure_err(failure_span, arg_data, error_code)
};
- let error_code = error_code.into();
- let mut err = self.tcx.sess.struct_span_err_with_code(
- span,
- &format!("type annotations needed{}", kind.ty_msg(self)),
- error_code,
- );
-
- if should_label_span && !failure_span.overlaps(span) {
- err.span_label(failure_span, "type must be known at this point");
- }
+ let (source_kind, name) = kind.ty_localized_msg(self);
+ let failure_span = if should_label_span && !failure_span.overlaps(span) {
+ Some(failure_span)
+ } else {
+ None
+ };
+ let mut infer_subdiags = Vec::new();
+ let mut multi_suggestions = Vec::new();
match kind {
InferSourceKind::LetBinding { insert_span, pattern_name, ty } => {
- let suggestion_msg = if let Some(name) = pattern_name {
- format!(
- "consider giving `{}` an explicit type{}",
- name,
- arg_data.where_x_is_specified(ty)
- )
- } else {
- format!(
- "consider giving this pattern a type{}",
- arg_data.where_x_is_specified(ty)
- )
- };
- err.span_suggestion_verbose(
- insert_span,
- &suggestion_msg,
- format!(": {}", ty_to_string(self, ty)),
- Applicability::HasPlaceholders,
- );
+ infer_subdiags.push(SourceKindSubdiag::LetLike {
+ span: insert_span,
+ name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new),
+ x_kind: arg_data.where_x_is_kind(ty),
+ prefix_kind: arg_data.kind.clone(),
+ prefix: arg_data.kind.try_get_prefix().unwrap_or_default(),
+ arg_name: arg_data.name,
+ kind: if pattern_name.is_some() { "with_pattern" } else { "other" },
+ type_name: ty_to_string(self, ty),
+ });
}
InferSourceKind::ClosureArg { insert_span, ty } => {
- err.span_suggestion_verbose(
- insert_span,
- &format!(
- "consider giving this closure parameter an explicit type{}",
- arg_data.where_x_is_specified(ty)
- ),
- format!(": {}", ty_to_string(self, ty)),
- Applicability::HasPlaceholders,
- );
+ infer_subdiags.push(SourceKindSubdiag::LetLike {
+ span: insert_span,
+ name: String::new(),
+ x_kind: arg_data.where_x_is_kind(ty),
+ prefix_kind: arg_data.kind.clone(),
+ prefix: arg_data.kind.try_get_prefix().unwrap_or_default(),
+ arg_name: arg_data.name,
+ kind: "closure",
+ type_name: ty_to_string(self, ty),
+ });
}
InferSourceKind::GenericArg {
insert_span,
@@ -389,23 +436,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
generics_def_id,
def_id: _,
generic_args,
+ have_turbofish,
} => {
let generics = self.tcx.generics_of(generics_def_id);
let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
- let cannot_infer_msg = format!(
- "cannot infer {} of the {} parameter `{}`{}",
- if is_type { "type" } else { "the value" },
- if is_type { "type" } else { "const" },
- generics.params[argument_index].name,
- // We use the `generics_def_id` here, as even when suggesting `None::<T>`,
- // the type parameter `T` was still declared on the enum, not on the
- // variant.
+ let (parent_exists, parent_prefix, parent_name) =
InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id)
- .map_or(String::new(), |parent| parent.suffix_string()),
- );
+ .map_or((false, String::new(), String::new()), |parent| {
+ (true, parent.prefix.to_string(), parent.name)
+ });
- err.span_label(span, cannot_infer_msg);
+ infer_subdiags.push(SourceKindSubdiag::GenericLabel {
+ span,
+ is_type,
+ param_name: generics.params[argument_index].name.to_string(),
+ parent_exists,
+ parent_prefix,
+ parent_name,
+ });
let args = fmt_printer(self, Namespace::TypeNS)
.comma_sep(generic_args.iter().copied().map(|arg| {
@@ -435,15 +484,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.unwrap()
.into_buffer();
- err.span_suggestion_verbose(
- insert_span,
- &format!(
- "consider specifying the generic argument{}",
- pluralize!(generic_args.len()),
- ),
- format!("::<{}>", args),
- Applicability::HasPlaceholders,
- );
+ if !have_turbofish {
+ infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
+ span: insert_span,
+ arg_count: generic_args.len(),
+ args,
+ });
+ }
}
InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
let printer = fmt_printer(self, Namespace::ValueNS);
@@ -468,39 +515,58 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => "",
};
- let suggestion = vec![
- (receiver.span.shrink_to_lo(), format!("{def_path}({adjustment}")),
- (receiver.span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
- ];
- err.multipart_suggestion_verbose(
- "try using a fully qualified path to specify the expected types",
- suggestion,
- Applicability::HasPlaceholders,
- );
+ multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
+ receiver.span,
+ def_path,
+ adjustment,
+ successor,
+ ));
}
InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
- let ret = ty_to_string(self, ty);
- let (arrow, post) = match data {
- FnRetTy::DefaultReturn(_) => ("-> ", " "),
- _ => ("", ""),
- };
- let suggestion = match should_wrap_expr {
- Some(end_span) => vec![
- (data.span(), format!("{}{}{}{{ ", arrow, ret, post)),
- (end_span, " }".to_string()),
- ],
- None => vec![(data.span(), format!("{}{}{}", arrow, ret, post))],
- };
- err.multipart_suggestion_verbose(
- "try giving this closure an explicit return type",
- suggestion,
- Applicability::HasPlaceholders,
- );
+ let ty_info = ty_to_string(self, ty);
+ multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
+ ty_info,
+ data,
+ should_wrap_expr,
+ ));
}
}
- err
+ match error_code {
+ TypeAnnotationNeeded::E0282 => AnnotationRequired {
+ span,
+ source_kind,
+ source_name: &name,
+ failure_span,
+ infer_subdiags,
+ multi_suggestions,
+ bad_label: None,
+ }
+ .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
+ TypeAnnotationNeeded::E0283 => AmbigousImpl {
+ span,
+ source_kind,
+ source_name: &name,
+ failure_span,
+ infer_subdiags,
+ multi_suggestions,
+ bad_label: None,
+ }
+ .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
+ TypeAnnotationNeeded::E0284 => AmbigousReturn {
+ span,
+ source_kind,
+ source_name: &name,
+ failure_span,
+ infer_subdiags,
+ multi_suggestions,
+ bad_label: None,
+ }
+ .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
+ }
}
+}
+impl<'tcx> InferCtxt<'tcx> {
pub fn need_type_info_err_in_generator(
&self,
kind: hir::GeneratorKind,
@@ -510,15 +576,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let ty = self.resolve_vars_if_possible(ty);
let data = self.extract_inference_diagnostics_data(ty.into(), None);
- let mut err = struct_span_err!(
- self.tcx.sess,
+ NeedTypeInfoInGenerator {
+ bad_label: data.make_bad_error(span),
span,
- E0698,
- "type inside {} must be known in this context",
- kind,
- );
- err.span_label(span, data.cannot_infer_msg());
- err
+ generator_kind: GeneratorKindAsDiagArg(kind),
+ }
+ .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
+ }
+}
+
+pub struct GeneratorKindAsDiagArg(pub hir::GeneratorKind);
+
+impl IntoDiagnosticArg for GeneratorKindAsDiagArg {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ let kind = match self.0 {
+ hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "async_block",
+ hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "async_closure",
+ hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "async_fn",
+ hir::GeneratorKind::Gen => "generator",
+ };
+ rustc_errors::DiagnosticArgValue::Str(kind.into())
}
}
@@ -545,6 +622,7 @@ enum InferSourceKind<'tcx> {
generics_def_id: DefId,
def_id: DefId,
generic_args: &'tcx [GenericArg<'tcx>],
+ have_turbofish: bool,
},
FullyQualifiedMethodCall {
receiver: &'tcx Expr<'tcx>,
@@ -579,22 +657,22 @@ impl<'tcx> InferSource<'tcx> {
}
impl<'tcx> InferSourceKind<'tcx> {
- fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String {
+ fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String) {
match *self {
InferSourceKind::LetBinding { ty, .. }
| InferSourceKind::ClosureArg { ty, .. }
| InferSourceKind::ClosureReturn { ty, .. } => {
if ty.is_closure() {
- format!(" for the closure `{}`", closure_as_fn_str(infcx, ty))
+ ("closure", closure_as_fn_str(infcx, ty))
} else if !ty.is_ty_infer() {
- format!(" for `{}`", ty_to_string(infcx, ty))
+ ("normal", ty_to_string(infcx, ty))
} else {
- String::new()
+ ("other", String::new())
}
}
// FIXME: We should be able to add some additional info here.
InferSourceKind::GenericArg { .. }
- | InferSourceKind::FullyQualifiedMethodCall { .. } => String::new(),
+ | InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new()),
}
}
}
@@ -605,6 +683,7 @@ struct InsertableGenericArgs<'tcx> {
substs: SubstsRef<'tcx>,
generics_def_id: DefId,
def_id: DefId,
+ have_turbofish: bool,
}
/// A visitor which searches for the "best" spot to use in the inference error.
@@ -615,7 +694,7 @@ struct InsertableGenericArgs<'tcx> {
/// While doing so, the currently best spot is stored in `infer_source`.
/// For details on how we rank spots, see [Self::source_cost]
struct FindInferSourceVisitor<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
target: GenericArg<'tcx>,
@@ -627,7 +706,7 @@ struct FindInferSourceVisitor<'a, 'tcx> {
impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
target: GenericArg<'tcx>,
) -> Self {
@@ -823,14 +902,21 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
// impl is currently the `DefId` of `Output` in the trait definition
// which makes this somewhat difficult and prevents us from just
// using `self.path_inferred_subst_iter` here.
- hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _) => {
- if let Some(ty) = self.opt_node_type(expr.hir_id) {
- if let ty::Adt(_, substs) = ty.kind() {
- return Box::new(self.resolved_path_inferred_subst_iter(path, substs));
- }
+ hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _)
+ // FIXME(TaKO8Ki): Ideally we should support this. For that
+ // we have to map back from the self type to the
+ // type alias though. That's difficult.
+ //
+ // See the `need_type_info/issue-103053.rs` test for
+ // a example.
+ if !matches!(path.res, Res::Def(DefKind::TyAlias, _)) => {
+ if let Some(ty) = self.opt_node_type(expr.hir_id)
+ && let ty::Adt(_, substs) = ty.kind()
+ {
+ return Box::new(self.resolved_path_inferred_subst_iter(path, substs));
}
}
- hir::ExprKind::MethodCall(segment, _, _) => {
+ hir::ExprKind::MethodCall(segment, ..) => {
if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) {
let generics = tcx.generics_of(def_id);
let insertable: Option<_> = try {
@@ -838,13 +924,14 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
None?
}
let substs = self.node_substs_opt(expr.hir_id)?;
- let span = tcx.hir().span(segment.hir_id?);
+ let span = tcx.hir().span(segment.hir_id);
let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
InsertableGenericArgs {
insert_span,
substs,
generics_def_id: def_id,
def_id,
+ have_turbofish: false,
}
};
return Box::new(insertable.into_iter());
@@ -862,6 +949,9 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs: SubstsRef<'tcx>,
) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
let tcx = self.infcx.tcx;
+ let have_turbofish = path.segments.iter().any(|segment| {
+ segment.args.map_or(false, |args| args.args.iter().any(|arg| arg.is_ty_or_const()))
+ });
// The last segment of a path often has `Res::Err` and the
// correct `Res` is the one of the whole path.
//
@@ -871,7 +961,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
let generics_def_id = tcx.res_generics_def_id(path.res)?;
let generics = tcx.generics_of(generics_def_id);
if generics.has_impl_trait() {
- None?
+ None?;
}
let insert_span =
path.segments.last().unwrap().ident.span.shrink_to_hi().with_hi(path.span.hi());
@@ -880,25 +970,27 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs,
generics_def_id,
def_id: path.res.def_id(),
+ have_turbofish,
}
};
path.segments
.iter()
.filter_map(move |segment| {
- let res = segment.res?;
+ let res = segment.res;
let generics_def_id = tcx.res_generics_def_id(res)?;
let generics = tcx.generics_of(generics_def_id);
if generics.has_impl_trait() {
return None;
}
- let span = tcx.hir().span(segment.hir_id?);
+ let span = tcx.hir().span(segment.hir_id);
let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
Some(InsertableGenericArgs {
insert_span,
substs,
generics_def_id,
def_id: res.def_id(),
+ have_turbofish,
})
})
.chain(last_segment_using_path_data)
@@ -925,9 +1017,15 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
if !segment.infer_args || generics.has_impl_trait() {
None?;
}
- let span = tcx.hir().span(segment.hir_id?);
+ let span = tcx.hir().span(segment.hir_id);
let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
- InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id }
+ InsertableGenericArgs {
+ insert_span,
+ substs,
+ generics_def_id: def_id,
+ def_id,
+ have_turbofish: false,
+ }
};
let parent_def_id = generics.parent.unwrap();
@@ -950,7 +1048,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
}
// There cannot be inference variables in the self type,
// so there's nothing for us to do here.
- Res::SelfTy { .. } => {}
+ Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {}
_ => warn!(
"unexpected path: def={:?} substs={:?} path={:?}",
def, substs, path,
@@ -1050,7 +1148,13 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
for args in self.expr_inferred_subst_iter(expr) {
debug!(?args);
- let InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } = args;
+ let InsertableGenericArgs {
+ insert_span,
+ substs,
+ generics_def_id,
+ def_id,
+ have_turbofish,
+ } = args;
let generics = tcx.generics_of(generics_def_id);
if let Some(argument_index) = generics
.own_substs(substs)
@@ -1061,7 +1165,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
let generic_args = &generics.own_substs_no_defaults(tcx, substs)
[generics.own_counts().lifetimes..];
let span = match expr.kind {
- ExprKind::MethodCall(path, _, _) => path.ident.span,
+ ExprKind::MethodCall(path, ..) => path.ident.span,
_ => expr.span,
};
@@ -1073,6 +1177,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
generics_def_id,
def_id,
generic_args,
+ have_turbofish,
},
});
}
@@ -1110,7 +1215,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
})
.any(|generics| generics.has_impl_trait())
};
- if let ExprKind::MethodCall(path, args, span) = expr.kind
+ if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind
&& let Some(substs) = self.node_substs_opt(expr.hir_id)
&& substs.iter().any(|arg| self.generic_arg_contains_target(arg))
&& let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
@@ -1118,12 +1223,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
&& !has_impl_trait(def_id)
{
let successor =
- args.get(1).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
+ args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
let substs = self.infcx.resolve_vars_if_possible(substs);
self.update_infer_source(InferSource {
span: path.ident.span,
kind: InferSourceKind::FullyQualifiedMethodCall {
- receiver: args.first().unwrap(),
+ receiver,
successor,
substs,
def_id,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index 9a2ab3e32..da0271a34 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -1,6 +1,9 @@
//! Error Reporting for Anonymous Region Lifetime Errors
//! where both the regions are anonymous.
+use crate::errors::AddLifetimeParamsSuggestion;
+use crate::errors::LifetimeMismatch;
+use crate::errors::LifetimeMismatchLabels;
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
@@ -8,11 +11,10 @@ use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::SubregionOrigin;
use crate::infer::TyCtxt;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
-use rustc_hir as hir;
-use rustc_hir::{GenericParamKind, Ty};
+use rustc_errors::AddToDiagnostic;
+use rustc_errors::{Diagnostic, ErrorGuaranteed};
+use rustc_hir::Ty;
use rustc_middle::ty::Region;
-use rustc_span::symbol::kw;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -98,137 +100,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let sub_is_ret_type =
self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
- let span_label_var1 = match anon_param_sup.pat.simple_ident() {
- Some(simple_ident) => format!(" from `{}`", simple_ident),
- None => String::new(),
- };
-
- let span_label_var2 = match anon_param_sub.pat.simple_ident() {
- Some(simple_ident) => format!(" into `{}`", simple_ident),
- None => String::new(),
- };
-
debug!(
"try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
sub_is_ret_type, sup_is_ret_type
);
- let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
-
- match (sup_is_ret_type, sub_is_ret_type) {
+ let labels = match (sup_is_ret_type, sub_is_ret_type) {
(ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => {
let param_span =
if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span };
-
- err.span_label(
+ LifetimeMismatchLabels::InRet {
param_span,
- "this parameter and the return type are declared with different lifetimes...",
- );
- err.span_label(ret_span, "");
- err.span_label(span, format!("...but data{} is returned here", span_label_var1));
- }
-
- (None, None) => {
- if ty_sup.hir_id == ty_sub.hir_id {
- err.span_label(ty_sup.span, "this type is declared with multiple lifetimes...");
- err.span_label(ty_sub.span, "");
- err.span_label(span, "...but data with one lifetime flows into the other here");
- } else {
- err.span_label(
- ty_sup.span,
- "these two types are declared with different lifetimes...",
- );
- err.span_label(ty_sub.span, "");
- err.span_label(
- span,
- format!("...but data{} flows{} here", span_label_var1, span_label_var2),
- );
+ ret_span,
+ span,
+ label_var1: anon_param_sup.pat.simple_ident(),
}
}
- }
- if suggest_adding_lifetime_params(self.tcx(), sub, ty_sup, ty_sub, &mut err) {
- err.note("each elided lifetime in input position becomes a distinct lifetime");
- }
+ (None, None) => LifetimeMismatchLabels::Normal {
+ hir_equal: ty_sup.hir_id == ty_sub.hir_id,
+ ty_sup: ty_sup.span,
+ ty_sub: ty_sub.span,
+ span,
+ sup: anon_param_sup.pat.simple_ident(),
+ sub: anon_param_sub.pat.simple_ident(),
+ },
+ };
- let reported = err.emit();
+ let suggestion =
+ AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true };
+ let err = LifetimeMismatch { span, labels, suggestion };
+ let reported = self.tcx().sess.emit_err(err);
Some(reported)
}
}
+/// Currently only used in rustc_borrowck, probably should be
+/// removed in favour of public_errors::AddLifetimeParamsSuggestion
pub fn suggest_adding_lifetime_params<'tcx>(
tcx: TyCtxt<'tcx>,
sub: Region<'tcx>,
- ty_sup: &Ty<'_>,
- ty_sub: &Ty<'_>,
+ ty_sup: &'tcx Ty<'_>,
+ ty_sub: &'tcx Ty<'_>,
err: &mut Diagnostic,
-) -> bool {
- let (
- hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
- hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
- ) = (ty_sub, ty_sup) else {
- return false;
- };
-
- if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
- return false;
- };
-
- let Some(anon_reg) = tcx.is_suitable_region(sub) else {
- return false;
- };
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
-
- let node = tcx.hir().get(hir_id);
- let is_impl = matches!(&node, hir::Node::ImplItem(_));
- let generics = match node {
- hir::Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. })
- | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
- | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
- _ => return false,
- };
-
- let suggestion_param_name = generics
- .params
- .iter()
- .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
- .map(|p| p.name.ident().name)
- .find(|i| *i != kw::UnderscoreLifetime);
- let introduce_new = suggestion_param_name.is_none();
- let suggestion_param_name =
- suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
-
- debug!(?lifetime_sup.span);
- debug!(?lifetime_sub.span);
- let make_suggestion = |span: rustc_span::Span| {
- if span.is_empty() {
- (span, format!("{}, ", suggestion_param_name))
- } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() {
- (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
- } else {
- (span, suggestion_param_name.clone())
- }
- };
- let mut suggestions =
- vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
-
- if introduce_new {
- let new_param_suggestion =
- if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) {
- (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
- } else {
- (generics.span, format!("<{}>", suggestion_param_name))
- };
-
- suggestions.push(new_param_suggestion);
- }
-
- let mut sugg = String::from("consider introducing a named lifetime parameter");
- if is_impl {
- sugg.push_str(" and update trait if needed");
- }
- err.multipart_suggestion(sugg, suggestions, Applicability::MaybeIncorrect);
-
- true
+) {
+ let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false };
+ suggestion.add_to_diagnostic(err);
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index c1b201da6..d8f540b74 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -91,7 +91,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
hir::TyKind::TraitObject(bounds, ..) => {
for bound in bounds {
self.current_index.shift_in(1);
- self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
+ self.visit_poly_trait_ref(bound);
self.current_index.shift_out(1);
}
}
@@ -103,7 +103,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
// Find the index of the named region that was part of the
// error. We will then search the function parameters for a bound
// region at the right depth with the same index
- (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
+ (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
if id == def_id {
self.found_type = Some(arg);
@@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
Some(
rl::Region::Static
| rl::Region::Free(_, _)
- | rl::Region::EarlyBound(_, _)
+ | rl::Region::EarlyBound(_)
| rl::Region::LateBound(_, _, _),
)
| None,
@@ -188,7 +188,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
// the lifetime of the TyPath!
- (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
+ (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
if id == def_id {
self.found_it = true;
@@ -209,7 +209,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
(
Some(
rl::Region::Static
- | rl::Region::EarlyBound(_, _)
+ | rl::Region::EarlyBound(_)
| rl::Region::LateBound(_, _, _)
| rl::Region::Free(_, _),
)
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index 893ca3cf7..c5f2a1a3f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -1,13 +1,16 @@
//! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
//! to hold.
+use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
+use crate::errors::{
+ DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag, MismatchedStaticLifetime,
+};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use crate::infer::error_reporting::note_and_explain_region;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::ObligationCauseCode;
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_middle::ty::TypeVisitor;
@@ -35,15 +38,27 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else {
return None;
};
- let ObligationCauseCode::BindingObligation(_def_id, binding_span) = *parent.code() else {
+ let (ObligationCauseCode::BindingObligation(_, binding_span) | ObligationCauseCode::ExprBindingObligation(_, binding_span, ..))
+ = *parent.code() else {
return None;
};
- let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type");
+
// FIXME: we should point at the lifetime
- let mut multi_span: MultiSpan = vec![binding_span].into();
- multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement");
- err.span_note(multi_span, "because this has an unmet lifetime requirement");
- note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
+ let multi_span: MultiSpan = vec![binding_span].into();
+ let multispan_subdiag = IntroducesStaticBecauseUnmetLifetimeReq {
+ unmet_requirements: multi_span,
+ binding_span,
+ };
+
+ let expl = note_and_explain::RegionExplanation::new(
+ self.tcx(),
+ sup,
+ Some(binding_span),
+ note_and_explain::PrefixKind::Empty,
+ note_and_explain::SuffixKind::Continues,
+ );
+ let mut impl_span = None;
+ let mut implicit_static_lifetimes = Vec::new();
if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
// If an impl is local, then maybe this isn't what they want. Try to
// be as helpful as possible with implicit lifetimes.
@@ -72,31 +87,34 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// there aren't trait objects or because none are implicit, then just
// write a single note on the impl itself.
- let impl_span = self.tcx().def_span(*impl_def_id);
- err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+ impl_span = Some(self.tcx().def_span(*impl_def_id));
} else {
// Otherwise, point at all implicit static lifetimes
- err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
for span in &traits {
- err.span_note(*span, "this has an implicit `'static` lifetime requirement");
+ implicit_static_lifetimes
+ .push(ImplicitStaticLifetimeSubdiag::Note { span: *span });
// It would be nice to put this immediately under the above note, but they get
// pushed to the end.
- err.span_suggestion_verbose(
- span.shrink_to_hi(),
- "consider relaxing the implicit `'static` requirement",
- " + '_",
- Applicability::MaybeIncorrect,
- );
+ implicit_static_lifetimes
+ .push(ImplicitStaticLifetimeSubdiag::Sugg { span: span.shrink_to_hi() });
}
}
} else {
// Otherwise just point out the impl.
- let impl_span = self.tcx().def_span(*impl_def_id);
- err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+ impl_span = Some(self.tcx().def_span(*impl_def_id));
}
- let reported = err.emit();
+ let err = MismatchedStaticLifetime {
+ cause_span: cause.span,
+ unmet_lifetime_reqs: multispan_subdiag,
+ expl,
+ does_not_outlive_static_from_impl: impl_span
+ .map(|span| DoesNotOutliveStaticFromImpl::Spanned { span })
+ .unwrap_or(DoesNotOutliveStaticFromImpl::Unspanned),
+ implicit_static_lifetimes,
+ };
+ let reported = self.tcx().sess.emit_err(err);
Some(reported)
}
}
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 53d9acf7d..aaf5a7af0 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
@@ -1,6 +1,6 @@
+use crate::infer::error_reporting::TypeErrCtxt;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::lexical_region_resolve::RegionResolutionError::*;
-use crate::infer::InferCtxt;
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::source_map::Span;
@@ -19,34 +19,34 @@ pub use find_anon_type::find_anon_type;
pub use static_impl_trait::{suggest_new_region_bound, HirTraitObjectVisitor, TraitObjectVisitor};
pub use util::find_param_with_region;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
- pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
+impl<'cx, 'tcx> TypeErrCtxt<'cx, 'tcx> {
+ pub fn try_report_nice_region_error(&'cx self, error: &RegionResolutionError<'tcx>) -> bool {
NiceRegionError::new(self, error.clone()).try_report().is_some()
}
}
pub struct NiceRegionError<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ cx: &'cx TypeErrCtxt<'cx, 'tcx>,
error: Option<RegionResolutionError<'tcx>>,
regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
}
impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
- pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
- Self { infcx, error: Some(error), regions: None }
+ pub fn new(cx: &'cx TypeErrCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
+ Self { cx, error: Some(error), regions: None }
}
pub fn new_from_span(
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ cx: &'cx TypeErrCtxt<'cx, 'tcx>,
span: Span,
sub: ty::Region<'tcx>,
sup: ty::Region<'tcx>,
) -> Self {
- Self { infcx, error: None, regions: Some((span, sub, sup)) }
+ Self { cx, error: None, regions: Some((span, sub, sup)) }
}
fn tcx(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
+ self.cx.tcx
}
pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
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 998699158..a58516829 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
@@ -211,7 +211,10 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
);
let mut err = self.tcx().sess.struct_span_err(span, &msg);
- let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = *cause.code() {
+ let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id)
+ | ObligationCauseCode::ExprItemObligation(def_id, ..) =
+ *cause.code()
+ {
err.span_label(span, "doesn't satisfy where-clause");
err.span_label(
self.tcx().def_span(def_id),
@@ -223,12 +226,12 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
false
};
- let expected_trait_ref = self.infcx.resolve_vars_if_possible(ty::TraitRef {
+ let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef {
def_id: trait_def_id,
substs: expected_substs,
});
let actual_trait_ref = self
- .infcx
+ .cx
.resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
// Search the expected and actual trait references to see (a)
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 9886c572a..9bf755d7f 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
@@ -185,8 +185,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
| ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
{
let parent_id = tcx.hir().get_parent_item(*hir_id);
- let parent_id = tcx.hir().local_def_id_to_hir_id(parent_id);
- if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) {
+ if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
let mut span: MultiSpan = fn_decl.output.span().into();
let mut add_label = true;
if let hir::FnRetTy::Return(ty) = fn_decl.output {
@@ -232,7 +231,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
ObligationCauseCode::MatchImpl(parent, ..) => parent.code(),
_ => cause.code(),
}
- && let (&ObligationCauseCode::ItemObligation(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:
@@ -287,8 +286,8 @@ pub fn suggest_new_region_bound(
) {
debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
- let consider = "consider changing the";
- let declare = "to declare that the";
+ let consider = "consider changing";
+ let declare = "to declare that";
let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
let explicit_static =
arg.map(|arg| format!("explicit `'static` bound to the lifetime of {}", arg));
@@ -300,12 +299,16 @@ pub fn suggest_new_region_bound(
continue;
}
match fn_return.kind {
- TyKind::OpaqueDef(item_id, _) => {
+ TyKind::OpaqueDef(item_id, _, _) => {
let item = tcx.hir().item(item_id);
let ItemKind::OpaqueTy(opaque) = &item.kind else {
return;
};
+ // Get the identity type for this RPIT
+ let did = item_id.owner_id.to_def_id();
+ let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
+
if let Some(span) = opaque
.bounds
.iter()
@@ -322,7 +325,7 @@ pub fn suggest_new_region_bound(
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
span,
- &format!("{} `impl Trait`'s {}", consider, explicit_static),
+ &format!("{consider} `{ty}`'s {explicit_static}"),
&lifetime_name,
Applicability::MaybeIncorrect,
);
@@ -352,12 +355,7 @@ pub fn suggest_new_region_bound(
} else {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
- &format!(
- "{declare} `impl Trait` {captures}, {explicit}",
- declare = declare,
- captures = captures,
- explicit = explicit,
- ),
+ &format!("{declare} `{ty}` {captures}, {explicit}",),
&plus_lt,
Applicability::MaybeIncorrect,
);
@@ -368,7 +366,7 @@ pub fn suggest_new_region_bound(
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
&format!(
- "{declare} trait object {captures}, {explicit}",
+ "{declare} the trait object {captures}, {explicit}",
declare = declare,
captures = captures,
explicit = explicit,
@@ -385,7 +383,7 @@ pub fn suggest_new_region_bound(
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
lt.span,
- &format!("{} trait object's {}", consider, explicit_static),
+ &format!("{} the trait object's {}", consider, explicit_static),
&lifetime_name,
Applicability::MaybeIncorrect,
);
@@ -415,7 +413,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let tcx = self.tcx();
match tcx.hir().get_if_local(def_id) {
Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) {
+ match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+ {
Some(Node::Item(Item {
kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
..
@@ -425,7 +424,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
Some(Node::TraitItem(trait_item)) => {
let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did) {
+ match tcx.hir().find_by_def_id(trait_did.def_id) {
Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
// The method being called is defined in the `trait`, but the `'static`
// obligation comes from the `impl`. Find that `impl` so that we can point
@@ -486,7 +485,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
tcx,
ctxt.param_env,
ctxt.assoc_item.def_id,
- self.infcx.resolve_vars_if_possible(ctxt.substs),
+ self.cx.resolve_vars_if_possible(ctxt.substs),
) else {
return false;
};
@@ -544,7 +543,7 @@ pub struct TraitObjectVisitor(pub FxHashSet<DefId>);
impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
- ty::Dynamic(preds, re) if re.is_static() => {
+ ty::Dynamic(preds, re, _) if re.is_static() => {
if let Some(def_id) = preds.principal_def_id() {
self.0.insert(def_id);
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index da465a764..5d536e982 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -84,12 +84,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
let expected = self
- .infcx
+ .cx
.extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
.name;
let found_highlight = HighlightBuilder::build(self.tcx(), found);
let found =
- self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
+ self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
err.span_label(sp, &format!("found `{}`", found));
err.span_label(trait_sp, &format!("expected `{}`", expected));
@@ -154,16 +154,12 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
}
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
[segment]
- if segment
- .res
- .map(|res| {
- matches!(
- res,
- Res::SelfTy { trait_: _, alias_to: _ }
- | Res::Def(hir::def::DefKind::TyParam, _)
- )
- })
- .unwrap_or(false) =>
+ if matches!(
+ segment.res,
+ Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
+ | Res::Def(hir::def::DefKind::TyParam, _)
+ ) =>
{
self.types.push(path.span);
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index 3e9d491af..f1461d701 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -130,7 +130,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let ret_ty = fn_ty.fn_sig(self.tcx()).output();
let span = hir_sig.decl.output.span();
let future_output = if hir_sig.header.is_async() {
- ret_ty.map_bound(|ty| self.infcx.get_impl_future_output_ty(ty)).transpose()
+ ret_ty.map_bound(|ty| self.cx.get_impl_future_output_ty(ty)).transpose()
} else {
None
};
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index c1940c5c0..41b115f33 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -1,100 +1,90 @@
-use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt};
-use crate::infer::{self, InferCtxt, SubregionOrigin};
-use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use crate::errors::RegionOriginNote;
+use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
+use crate::infer::{self, SubregionOrigin};
+use rustc_errors::{
+ fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+};
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, Region};
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+use super::ObligationCauseAsDiagArg;
+
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
- let mut label_or_note = |span, msg: &str| {
- let sub_count = err.children.iter().filter(|d| d.span.is_dummy()).count();
- let expanded_sub_count = err.children.iter().filter(|d| !d.span.is_dummy()).count();
- let span_is_primary = err.span.primary_spans().iter().all(|&sp| sp == span);
- if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
- err.span_label(span, msg);
- } else if span_is_primary && expanded_sub_count == 0 {
- err.note(msg);
- } else {
- err.span_note(span, msg);
- }
- };
match *origin {
- infer::Subtype(ref trace) => {
- if let Some((expected, found)) = self.values_str(trace.values) {
- label_or_note(
- trace.cause.span,
- &format!("...so that the {}", trace.cause.as_requirement_str()),
- );
-
- err.note_expected_found(&"", expected, &"", found);
- } else {
- // FIXME: this really should be handled at some earlier stage. Our
- // handling of region checking when type errors are present is
- // *terrible*.
-
- label_or_note(
- trace.cause.span,
- &format!("...so that {}", trace.cause.as_requirement_str()),
- );
- }
+ infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
+ span: trace.cause.span,
+ requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
+ expected_found: self.values_str(trace.values),
}
+ .add_to_diagnostic(err),
infer::Reborrow(span) => {
- label_or_note(span, "...so that reference does not outlive borrowed content");
+ RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
}
infer::ReborrowUpvar(span, ref upvar_id) => {
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
- label_or_note(span, &format!("...so that closure can access `{}`", var_name));
+ RegionOriginNote::WithName {
+ span,
+ msg: fluent::infer_reborrow,
+ name: &var_name.to_string(),
+ continues: false,
+ }
+ .add_to_diagnostic(err);
}
infer::RelateObjectBound(span) => {
- label_or_note(span, "...so that it can be closed over into an object");
+ RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
+ .add_to_diagnostic(err);
}
infer::DataBorrowed(ty, span) => {
- label_or_note(
+ RegionOriginNote::WithName {
span,
- &format!(
- "...so that the type `{}` is not borrowed for too long",
- self.ty_to_string(ty)
- ),
- );
+ msg: fluent::infer_data_borrowed,
+ name: &self.ty_to_string(ty),
+ continues: false,
+ }
+ .add_to_diagnostic(err);
}
infer::ReferenceOutlivesReferent(ty, span) => {
- label_or_note(
+ RegionOriginNote::WithName {
span,
- &format!(
- "...so that the reference type `{}` does not outlive the data it points at",
- self.ty_to_string(ty)
- ),
- );
+ msg: fluent::infer_reference_outlives_referent,
+ name: &self.ty_to_string(ty),
+ continues: false,
+ }
+ .add_to_diagnostic(err);
}
- infer::RelateParamBound(span, t, opt_span) => {
- label_or_note(
+ infer::RelateParamBound(span, ty, opt_span) => {
+ RegionOriginNote::WithName {
span,
- &format!(
- "...so that the type `{}` will meet its required lifetime bounds{}",
- self.ty_to_string(t),
- if opt_span.is_some() { "..." } else { "" },
- ),
- );
+ msg: fluent::infer_relate_param_bound,
+ name: &self.ty_to_string(ty),
+ continues: opt_span.is_some(),
+ }
+ .add_to_diagnostic(err);
if let Some(span) = opt_span {
- err.span_note(span, "...that is required by this bound");
+ RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
+ .add_to_diagnostic(err);
}
}
infer::RelateRegionParamBound(span) => {
- label_or_note(
- span,
- "...so that the declared lifetime parameter bounds are satisfied",
- );
+ RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
+ .add_to_diagnostic(err);
}
infer::CompareImplItemObligation { span, .. } => {
- label_or_note(
- span,
- "...so that the definition in impl matches the definition from the trait",
- );
+ RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
+ .add_to_diagnostic(err);
}
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
self.note_region_origin(err, &parent);
}
+ infer::AscribeUserTypeProvePredicate(span) => {
+ RegionOriginNote::Plain {
+ span,
+ msg: fluent::infer_ascribe_user_type_prove_predicate,
+ }
+ .add_to_diagnostic(err);
+ }
}
}
@@ -107,7 +97,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
match origin {
infer::Subtype(box trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
- let mut err = self.report_and_explain_type_error(trace, &terr);
+ let mut err = self.report_and_explain_type_error(trace, terr);
match (*sub, *sup) {
(ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
(ty::RePlaceholder(_), _) => {
@@ -374,6 +364,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err
}
+ infer::AscribeUserTypeProvePredicate(span) => {
+ let mut err =
+ struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
+ note_and_explain_region(
+ self.tcx,
+ &mut err,
+ "lifetime instantiated with ",
+ sup,
+ "",
+ None,
+ );
+ note_and_explain_region(
+ self.tcx,
+ &mut err,
+ "but lifetime must outlive ",
+ sub,
+ "",
+ None,
+ );
+ err
+ }
}
}
@@ -390,10 +401,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
if matches!(
&trace.cause.code().peel_derives(),
ObligationCauseCode::BindingObligation(..)
+ | ObligationCauseCode::ExprBindingObligation(..)
) =>
{
// Hack to get around the borrow checker because trace.cause has an `Rc`.
- if let ObligationCauseCode::BindingObligation(_, span) =
+ if let ObligationCauseCode::BindingObligation(_, span)
+ | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
&trace.cause.code().peel_derives()
{
let span = *span;
@@ -406,7 +419,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
infer::Subtype(box trace) => {
let terr = TypeError::RegionsPlaceholderMismatch;
- return self.report_and_explain_type_error(trace, &terr);
+ return self.report_and_explain_type_error(trace, terr);
}
_ => return self.report_concrete_failure(placeholder_origin, sub, sup),
}
diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs
index d566634a4..728d691a2 100644
--- a/compiler/rustc_infer/src/infer/free_regions.rs
+++ b/compiler/rustc_infer/src/infer/free_regions.rs
@@ -27,13 +27,13 @@ impl<'a, 'tcx> RegionRelations<'a, 'tcx> {
}
}
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Debug)]
pub struct FreeRegionMap<'tcx> {
// Stores the relation `a < b`, where `a` and `b` are regions.
//
// Invariant: only free regions like `'x` or `'static` are stored
// in this relation, not scopes.
- relation: TransitiveRelation<Region<'tcx>>,
+ pub(crate) relation: TransitiveRelation<Region<'tcx>>,
}
impl<'tcx> FreeRegionMap<'tcx> {
@@ -45,15 +45,6 @@ impl<'tcx> FreeRegionMap<'tcx> {
self.relation.is_empty()
}
- // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
- // (with the exception that `'static: 'x` is not notable)
- pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
- debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
- if sub.is_free_or_static() && sup.is_free() {
- self.relation.add(sub, sup)
- }
- }
-
/// Tests whether `r_a <= r_b`.
///
/// Both regions must meet `is_free_or_static`.
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 84004d2b2..ff5d1a05a 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -38,7 +38,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVi
use std::collections::hash_map::Entry;
pub struct TypeFreshener<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
ty_freshen_count: u32,
const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
@@ -47,7 +47,7 @@ pub struct TypeFreshener<'a, 'tcx> {
}
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
+ pub fn new(infcx: &'a InferCtxt<'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
TypeFreshener {
infcx,
ty_freshen_count: 0,
@@ -126,7 +126,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
| ty::ReFree(_)
| ty::ReVar(_)
| ty::RePlaceholder(..)
- | ty::ReEmpty(_)
| ty::ReErased => {
// replace all free regions with 'erased
self.tcx().lifetimes.re_erased
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index 2f0eadce6..6dd6c4e1f 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -43,7 +43,7 @@ struct VariableLengths {
region_constraints_len: usize,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
fn variable_lengths(&self) -> VariableLengths {
let mut inner = self.inner.borrow_mut();
VariableLengths {
@@ -167,7 +167,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
pub struct InferenceFudger<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
int_vars: Range<IntVid>,
float_vars: Range<FloatVid>,
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 1570a08f3..6ffefcb7a 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -113,7 +113,7 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
}
impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, 'tcx> {
- fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> {
+ fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
self.fields.infcx
}
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index d0d9efe15..28c87a115 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -59,7 +59,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
}
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Replaces all bound variables (lifetimes, types, and constants) bound by
/// `binder` with placeholder variables in a new universe. This means that the
/// new placeholders can only be named by inference variables created after
@@ -69,7 +69,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// For more details visit the relevant sections of the [rustc dev guide].
///
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
where
T: TypeFoldable<'tcx> + Copy,
@@ -81,19 +81,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let next_universe = self.create_next_universe();
let delegate = FnMutDelegate {
- regions: |br: ty::BoundRegion| {
+ regions: &mut |br: ty::BoundRegion| {
self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion {
universe: next_universe,
name: br.kind,
}))
},
- types: |bound_ty: ty::BoundTy| {
+ types: &mut |bound_ty: ty::BoundTy| {
self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: next_universe,
name: bound_ty.var,
}))
},
- consts: |bound_var: ty::BoundVar, ty| {
+ consts: &mut |bound_var: ty::BoundVar, ty| {
self.tcx.mk_const(ty::ConstS {
kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
universe: next_universe,
@@ -104,9 +104,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
},
};
- let result = self.tcx.replace_bound_vars_uncached(binder, delegate);
- debug!(?next_universe, ?result);
- result
+ debug!(?next_universe);
+ self.tcx.replace_bound_vars_uncached(binder, delegate)
}
/// See [RegionConstraintCollector::leak_check][1].
@@ -115,7 +114,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn leak_check(
&self,
overly_polymorphic: bool,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
+ snapshot: &CombinedSnapshot<'tcx>,
) -> RelateResult<'tcx, ()> {
// If the user gave `-Zno-leak-check`, or we have been
// configured to skip the leak check, then skip the leak check
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index 1e3293efa..eba65361a 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -31,7 +31,7 @@ use rustc_middle::ty::{self, Ty};
/// GLB moves "down" the lattice (to smaller values); LUB moves
/// "up" the lattice (to bigger values).
pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
- fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
+ fn infcx(&self) -> &'f InferCtxt<'tcx>;
fn cause(&self) -> &ObligationCause<'tcx>;
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 3783cfb4c..5f13b2b3d 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -15,8 +15,9 @@ use rustc_data_structures::graph::implementation::{
use rustc_data_structures::intern::Interned;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::PlaceholderRegion;
use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
+use rustc_middle::ty::{ReEarlyBound, ReErased, ReFree, ReStatic};
use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
use rustc_middle::ty::{Region, RegionVid};
use rustc_span::Span;
@@ -51,6 +52,13 @@ pub struct LexicalRegionResolutions<'tcx> {
#[derive(Copy, Clone, Debug)]
pub(crate) enum VarValue<'tcx> {
+ /// Empty lifetime is for data that is never accessed. We tag the
+ /// empty lifetime with a universe -- the idea is that we don't
+ /// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable.
+ /// Therefore, the `'empty` in a universe `U` is less than all
+ /// regions visible from `U`, but not less than regions not visible
+ /// from `U`.
+ Empty(ty::UniverseIndex),
Value(Region<'tcx>),
ErrorValue,
}
@@ -117,7 +125,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
&mut self,
errors: &mut Vec<RegionResolutionError<'tcx>>,
) -> LexicalRegionResolutions<'tcx> {
- let mut var_data = self.construct_var_data(self.tcx());
+ let mut var_data = self.construct_var_data();
if cfg!(debug_assertions) {
self.dump_constraints();
@@ -137,13 +145,12 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
/// Initially, the value for all variables is set to `'empty`, the
/// empty region. The `expansion` phase will grow this larger.
- fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
+ fn construct_var_data(&self) -> LexicalRegionResolutions<'tcx> {
LexicalRegionResolutions {
values: IndexVec::from_fn_n(
|vid| {
let vid_universe = self.var_infos[vid].universe;
- let re_empty = tcx.mk_region(ty::ReEmpty(vid_universe));
- VarValue::Value(re_empty)
+ VarValue::Empty(vid_universe)
},
self.num_vars(),
),
@@ -189,20 +196,131 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}
+ /// Gets the LUb of a given region and the empty region
+ fn lub_empty(&self, a_region: Region<'tcx>) -> Result<Region<'tcx>, PlaceholderRegion> {
+ match *a_region {
+ ReLateBound(..) | ReErased => {
+ bug!("cannot relate region: {:?}", a_region);
+ }
+
+ ReVar(v_id) => {
+ span_bug!(
+ self.var_infos[v_id].origin.span(),
+ "lub invoked with non-concrete regions: {:?}",
+ a_region,
+ );
+ }
+
+ ReStatic => {
+ // nothing lives longer than `'static`
+ Ok(self.tcx().lifetimes.re_static)
+ }
+
+ ReEarlyBound(_) | ReFree(_) => {
+ // All empty regions are less than early-bound, free,
+ // and scope regions.
+ Ok(a_region)
+ }
+
+ RePlaceholder(placeholder) => Err(placeholder),
+ }
+ }
+
fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
+ // In the first pass, we expand region vids according to constraints we
+ // have previously found. In the second pass, we loop through the region
+ // vids we expanded and expand *across* region vids (effectively
+ // "expanding" new `RegSubVar` constraints).
+
+ // Tracks the `VarSubVar` constraints generated for each region vid. We
+ // later use this to expand across vids.
let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len());
+ // Tracks the changed region vids.
let mut changes = Vec::new();
for constraint in self.data.constraints.keys() {
- let (a_vid, a_region, b_vid, b_data) = match *constraint {
+ match *constraint {
Constraint::RegSubVar(a_region, b_vid) => {
let b_data = var_values.value_mut(b_vid);
- (None, a_region, b_vid, b_data)
+
+ if self.expand_node(a_region, b_vid, b_data) {
+ changes.push(b_vid);
+ }
}
Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
VarValue::ErrorValue => continue,
+ VarValue::Empty(a_universe) => {
+ let b_data = var_values.value_mut(b_vid);
+
+ let changed = (|| match *b_data {
+ VarValue::Empty(b_universe) => {
+ // Empty regions are ordered according to the universe
+ // they are associated with.
+ let ui = a_universe.min(b_universe);
+
+ debug!(
+ "Expanding value of {:?} \
+ from empty lifetime with universe {:?} \
+ to empty lifetime with universe {:?}",
+ b_vid, b_universe, ui
+ );
+
+ *b_data = VarValue::Empty(ui);
+ true
+ }
+ VarValue::Value(cur_region) => {
+ let lub = match self.lub_empty(cur_region) {
+ Ok(r) => r,
+ // If the empty and placeholder regions are in the same universe,
+ // then the LUB is the Placeholder region (which is the cur_region).
+ // If they are not in the same universe, the LUB is the Static lifetime.
+ Err(placeholder) if a_universe == placeholder.universe => {
+ cur_region
+ }
+ Err(_) => self.tcx().lifetimes.re_static,
+ };
+
+ if lub == cur_region {
+ return false;
+ }
+
+ debug!(
+ "Expanding value of {:?} from {:?} to {:?}",
+ b_vid, cur_region, lub
+ );
+
+ *b_data = VarValue::Value(lub);
+ true
+ }
+
+ VarValue::ErrorValue => false,
+ })();
+
+ if changed {
+ changes.push(b_vid);
+ }
+ match b_data {
+ VarValue::Value(Region(Interned(ReStatic, _)))
+ | VarValue::ErrorValue => (),
+ _ => {
+ constraints[a_vid].push((a_vid, b_vid));
+ constraints[b_vid].push((a_vid, b_vid));
+ }
+ }
+ }
VarValue::Value(a_region) => {
let b_data = var_values.value_mut(b_vid);
- (Some(a_vid), a_region, b_vid, b_data)
+
+ if self.expand_node(a_region, b_vid, b_data) {
+ changes.push(b_vid);
+ }
+ match b_data {
+ VarValue::Value(Region(Interned(ReStatic, _)))
+ | VarValue::ErrorValue => (),
+ _ => {
+ constraints[a_vid].push((a_vid, b_vid));
+ constraints[b_vid].push((a_vid, b_vid));
+ }
+ }
}
},
Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
@@ -210,18 +328,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// is done, in `collect_errors`.
continue;
}
- };
- if self.expand_node(a_region, b_vid, b_data) {
- changes.push(b_vid);
- }
- if let Some(a_vid) = a_vid {
- match b_data {
- VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue => (),
- _ => {
- constraints[a_vid].push((a_vid, b_vid));
- constraints[b_vid].push((a_vid, b_vid));
- }
- }
}
}
@@ -242,6 +348,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}
+ /// Expands the value of the region represented with `b_vid` with current
+ /// value `b_data` to the lub of `b_data` and `a_region`. The corresponds
+ /// with the constraint `'?b: 'a` (`'a <: '?b`), where `'a` is some known
+ /// region and `'?b` is some region variable.
fn expand_node(
&self,
a_region: Region<'tcx>,
@@ -263,14 +373,28 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
match *b_data {
+ VarValue::Empty(empty_ui) => {
+ let lub = match self.lub_empty(a_region) {
+ Ok(r) => r,
+ // If this empty region is from a universe that can
+ // name the placeholder, then the placeholder is
+ // larger; otherwise, the only ancestor is `'static`.
+ Err(placeholder) if empty_ui.can_name(placeholder.universe) => {
+ self.tcx().mk_region(RePlaceholder(placeholder))
+ }
+ Err(_) => self.tcx().lifetimes.re_static,
+ };
+
+ debug!("Expanding value of {:?} from empty lifetime to {:?}", b_vid, lub);
+
+ *b_data = VarValue::Value(lub);
+ true
+ }
VarValue::Value(cur_region) => {
// This is a specialized version of the `lub_concrete_regions`
// check below for a common case, here purely as an
// optimization.
let b_universe = self.var_infos[b_vid].universe;
- if let ReEmpty(a_universe) = *a_region && a_universe == b_universe {
- return false;
- }
let mut lub = self.lub_concrete_regions(a_region, cur_region);
if lub == cur_region {
@@ -300,6 +424,78 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}
+ /// True if `a <= b`.
+ fn sub_region_values(&self, a: VarValue<'tcx>, b: VarValue<'tcx>) -> bool {
+ match (a, b) {
+ // Error region is `'static`
+ (VarValue::ErrorValue, _) | (_, VarValue::ErrorValue) => return true,
+ (VarValue::Empty(a_ui), VarValue::Empty(b_ui)) => {
+ // Empty regions are ordered according to the universe
+ // they are associated with.
+ a_ui.min(b_ui) == b_ui
+ }
+ (VarValue::Value(a), VarValue::Empty(_)) => {
+ match *a {
+ ReLateBound(..) | ReErased => {
+ bug!("cannot relate region: {:?}", a);
+ }
+
+ ReVar(v_id) => {
+ span_bug!(
+ self.var_infos[v_id].origin.span(),
+ "lub_concrete_regions invoked with non-concrete region: {:?}",
+ a
+ );
+ }
+
+ ReStatic | ReEarlyBound(_) | ReFree(_) => {
+ // nothing lives longer than `'static`
+
+ // All empty regions are less than early-bound, free,
+ // and scope regions.
+
+ false
+ }
+
+ RePlaceholder(_) => {
+ // The LUB is either `a` or `'static`
+ false
+ }
+ }
+ }
+ (VarValue::Empty(a_ui), VarValue::Value(b)) => {
+ match *b {
+ ReLateBound(..) | ReErased => {
+ bug!("cannot relate region: {:?}", b);
+ }
+
+ ReVar(v_id) => {
+ span_bug!(
+ self.var_infos[v_id].origin.span(),
+ "lub_concrete_regions invoked with non-concrete regions: {:?}",
+ b
+ );
+ }
+
+ ReStatic | ReEarlyBound(_) | ReFree(_) => {
+ // nothing lives longer than `'static`
+ // All empty regions are less than early-bound, free,
+ // and scope regions.
+ true
+ }
+
+ RePlaceholder(placeholder) => {
+ // If this empty region is from a universe that can
+ // name the placeholder, then the placeholder is
+ // larger; otherwise, the only ancestor is `'static`.
+ if a_ui.can_name(placeholder.universe) { true } else { false }
+ }
+ }
+ }
+ (VarValue::Value(a), VarValue::Value(b)) => self.sub_concrete_regions(a, b),
+ }
+ }
+
/// True if `a <= b`, but not defined over inference variables.
#[instrument(level = "trace", skip(self))]
fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
@@ -333,9 +529,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
///
/// Neither `a` nor `b` may be an inference variable (hence the
/// term "concrete regions").
- #[instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self), ret)]
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
- let r = match (*a, *b) {
+ match (*a, *b) {
(ReLateBound(..), _) | (_, ReLateBound(..)) | (ReErased, _) | (_, ReErased) => {
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
}
@@ -355,37 +551,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
self.tcx().lifetimes.re_static
}
- (ReEmpty(_), ReEarlyBound(_) | ReFree(_)) => {
- // All empty regions are less than early-bound, free,
- // and scope regions.
- b
- }
-
- (ReEarlyBound(_) | ReFree(_), ReEmpty(_)) => {
- // All empty regions are less than early-bound, free,
- // and scope regions.
- a
- }
-
- (ReEmpty(a_ui), ReEmpty(b_ui)) => {
- // Empty regions are ordered according to the universe
- // they are associated with.
- let ui = a_ui.min(b_ui);
- self.tcx().mk_region(ReEmpty(ui))
- }
-
- (ReEmpty(empty_ui), RePlaceholder(placeholder))
- | (RePlaceholder(placeholder), ReEmpty(empty_ui)) => {
- // If this empty region is from a universe that can
- // name the placeholder, then the placeholder is
- // larger; otherwise, the only ancestor is `'static`.
- if empty_ui.can_name(placeholder.universe) {
- self.tcx().mk_region(RePlaceholder(placeholder))
- } else {
- self.tcx().lifetimes.re_static
- }
- }
-
(ReEarlyBound(_) | ReFree(_), ReEarlyBound(_) | ReFree(_)) => {
self.region_rels.lub_free_regions(a, b)
}
@@ -399,11 +564,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
self.tcx().lifetimes.re_static
}
}
- };
-
- debug!("lub_concrete_regions({:?}, {:?}) = {:?}", a, b, r);
-
- r
+ }
}
/// After expansion is complete, go and check upper bounds (i.e.,
@@ -512,7 +673,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
for (node_vid, value) in var_data.values.iter_enumerated() {
match *value {
- VarValue::Value(_) => { /* Inference successful */ }
+ VarValue::Empty(_) | VarValue::Value(_) => { /* Inference successful */ }
VarValue::ErrorValue => {
// Inference impossible: this value contains
// inconsistent constraints.
@@ -833,12 +994,25 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
VerifyBound::OutlivedBy(r) => {
- self.sub_concrete_regions(min, var_values.normalize(self.tcx(), *r))
+ let a = match *min {
+ ty::ReVar(rid) => var_values.values[rid],
+ _ => VarValue::Value(min),
+ };
+ let b = match **r {
+ ty::ReVar(rid) => var_values.values[rid],
+ _ => VarValue::Value(*r),
+ };
+ self.sub_region_values(a, b)
}
- VerifyBound::IsEmpty => {
- matches!(*min, ty::ReEmpty(_))
- }
+ VerifyBound::IsEmpty => match *min {
+ ty::ReVar(rid) => match var_values.values[rid] {
+ VarValue::ErrorValue => false,
+ VarValue::Empty(_) => true,
+ VarValue::Value(_) => false,
+ },
+ _ => false,
+ },
VerifyBound::AnyBound(bs) => {
bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min))
@@ -880,6 +1054,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
) -> ty::Region<'tcx> {
let result = match *r {
ty::ReVar(rid) => match self.values[rid] {
+ VarValue::Empty(_) => r,
VarValue::Value(r) => r,
VarValue::ErrorValue => tcx.lifetimes.re_static,
},
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index 9f96d52c8..d6e56fcb7 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -119,7 +119,7 @@ impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> {
}
impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> {
- fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> {
+ fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
self.fields.infcx
}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index d7d1b5fa2..ffb020398 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -20,6 +20,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
+use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::select;
use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -32,12 +33,13 @@ pub use rustc_middle::ty::IntVarValue;
use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
-use std::cell::{Cell, Ref, RefCell};
+use std::cell::{Cell, RefCell};
use std::fmt;
use self::combine::CombineFields;
+use self::error_reporting::TypeErrCtxt;
use self::free_regions::RegionRelations;
use self::lexical_region_resolve::LexicalRegionResolutions;
use self::outlives::env::OutlivesEnvironment;
@@ -251,7 +253,7 @@ pub enum DefiningAnchor {
Error,
}
-pub struct InferCtxt<'a, 'tcx> {
+pub struct InferCtxt<'tcx> {
pub tcx: TyCtxt<'tcx>,
/// The `DefId` of the item in whose context we are performing inference or typeck.
@@ -271,12 +273,6 @@ pub struct InferCtxt<'a, 'tcx> {
/// solving is left to borrowck instead.
pub considering_regions: bool,
- /// During type-checking/inference of a body, `in_progress_typeck_results`
- /// contains a reference to the typeck results being built up, which are
- /// used for reading closure kinds/signatures as they are inferred,
- /// and for error reporting logic to read arbitrary node types.
- pub in_progress_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
-
pub inner: RefCell<InferCtxtInner<'tcx>>,
/// If set, this flag causes us to skip the 'leak check' during
@@ -316,12 +312,12 @@ pub struct InferCtxt<'a, 'tcx> {
///
/// Don't read this flag directly, call `is_tainted_by_errors()`
/// and `set_tainted_by_errors()`.
- tainted_by_errors_flag: Cell<bool>,
+ tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
/// Track how many errors were reported when this infcx is created.
/// If the number of errors increases, that's also a sign (line
/// `tainted_by_errors`) to avoid reporting certain kinds of errors.
- // FIXME(matthewjasper) Merge into `tainted_by_errors_flag`
+ // FIXME(matthewjasper) Merge into `tainted_by_errors`
err_count_on_creation: usize,
/// This flag is true while there is an active snapshot.
@@ -337,6 +333,9 @@ pub struct InferCtxt<'a, 'tcx> {
/// when we enter into a higher-ranked (`for<..>`) type or trait
/// bound.
universe: Cell<ty::UniverseIndex>,
+
+ normalize_fn_sig_for_diagnostic:
+ Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
}
/// See the `error_reporting` module for more details.
@@ -350,12 +349,11 @@ pub enum ValuePairs<'tcx> {
impl<'tcx> ValuePairs<'tcx> {
pub fn ty(&self) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
- if let ValuePairs::Terms(ExpectedFound {
- expected: ty::Term::Ty(expected),
- found: ty::Term::Ty(found),
- }) = self
+ if let ValuePairs::Terms(ExpectedFound { expected, found }) = self
+ && let Some(expected) = expected.ty()
+ && let Some(found) = found.ty()
{
- Some((*expected, *found))
+ Some((expected, found))
} else {
None
}
@@ -406,7 +404,11 @@ pub enum SubregionOrigin<'tcx> {
/// Comparing the signature and requirements of an impl method against
/// the containing trait.
- CompareImplItemObligation { span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId },
+ CompareImplItemObligation {
+ span: Span,
+ impl_item_def_id: LocalDefId,
+ trait_item_def_id: DefId,
+ },
/// Checking that the bounds of a trait's associated type hold for a given impl
CheckAssociatedTypeBounds {
@@ -414,12 +416,24 @@ pub enum SubregionOrigin<'tcx> {
impl_item_def_id: LocalDefId,
trait_item_def_id: DefId,
},
+
+ AscribeUserTypeProvePredicate(Span),
}
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(SubregionOrigin<'_>, 32);
+impl<'tcx> SubregionOrigin<'tcx> {
+ pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
+ match self {
+ Self::Subtype(type_trace) => type_trace.cause.to_constraint_category(),
+ Self::AscribeUserTypeProvePredicate(span) => ConstraintCategory::Predicate(*span),
+ _ => ConstraintCategory::BoringNoLocation,
+ }
+ }
+}
+
/// Times when we replace late-bound regions with variables:
#[derive(Clone, Copy, Debug)]
pub enum LateBoundRegionConversionTime {
@@ -504,7 +518,7 @@ pub enum FixupError<'tcx> {
}
/// See the `region_obligations` field for more information.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct RegionObligation<'tcx> {
pub sub_region: ty::Region<'tcx>,
pub sup_type: Ty<'tcx>,
@@ -532,14 +546,13 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
}
}
-/// A temporary returned by `tcx.infer_ctxt()`. This is necessary
-/// for multiple `InferCtxt` to share the same `in_progress_typeck_results`
-/// without using `Rc` or something similar.
+/// Used to configure inference contexts before their creation
pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
defining_use_anchor: DefiningAnchor,
considering_regions: bool,
- fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
+ normalize_fn_sig_for_diagnostic:
+ Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
}
pub trait TyCtxtInferExt<'tcx> {
@@ -552,25 +565,17 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
tcx: self,
defining_use_anchor: DefiningAnchor::Error,
considering_regions: true,
- fresh_typeck_results: None,
+ normalize_fn_sig_for_diagnostic: None,
}
}
}
impl<'tcx> InferCtxtBuilder<'tcx> {
- /// Used only by `rustc_typeck` during body type-checking/inference,
- /// will initialize `in_progress_typeck_results` with fresh `TypeckResults`.
- /// Will also change the scope for opaque type defining use checks to the given owner.
- pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
- self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
- self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner))
- }
-
/// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
/// you need to call this function. Otherwise the opaque type will be treated opaquely.
///
/// It is only meant to be called in two places, for typeck
- /// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
+ /// (via `Inherited::build`) and for the inference context used
/// in mir borrowck.
pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor) -> Self {
self.defining_use_anchor = defining_use_anchor;
@@ -582,6 +587,14 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
self
}
+ pub fn with_normalize_fn_sig_for_diagnostic(
+ mut self,
+ fun: Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>,
+ ) -> Self {
+ self.normalize_fn_sig_for_diagnostic = Some(fun);
+ self
+ }
+
/// Given a canonical value `C` as a starting point, create an
/// inference context that contains each of the bound values
/// within instantiated as a fresh variable. The `f` closure is
@@ -589,47 +602,45 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
/// `V` and a substitution `S`. This substitution `S` maps from
/// the bound values in `C` to their instantiated values in `V`
/// (in other words, `S(C) = V`).
- pub fn enter_with_canonical<T, R>(
+ pub fn build_with_canonical<T>(
&mut self,
span: Span,
canonical: &Canonical<'tcx, T>,
- f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>, T, CanonicalVarValues<'tcx>) -> R,
- ) -> R
+ ) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>)
where
T: TypeFoldable<'tcx>,
{
- self.enter(|infcx| {
- let (value, subst) =
- infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
- f(infcx, value, subst)
- })
+ let infcx = self.build();
+ let (value, subst) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
+ (infcx, value, subst)
}
- pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
+ pub fn build(&mut self) -> InferCtxt<'tcx> {
let InferCtxtBuilder {
tcx,
defining_use_anchor,
considering_regions,
- ref fresh_typeck_results,
+ ref normalize_fn_sig_for_diagnostic,
} = *self;
- let in_progress_typeck_results = fresh_typeck_results.as_ref();
- f(InferCtxt {
+ InferCtxt {
tcx,
defining_use_anchor,
considering_regions,
- in_progress_typeck_results,
inner: RefCell::new(InferCtxtInner::new()),
lexical_region_resolutions: RefCell::new(None),
selection_cache: Default::default(),
evaluation_cache: Default::default(),
reported_trait_errors: Default::default(),
reported_closure_mismatch: Default::default(),
- tainted_by_errors_flag: Cell::new(false),
+ tainted_by_errors: Cell::new(None),
err_count_on_creation: tcx.sess.err_count(),
in_snapshot: Cell::new(false),
skip_leak_check: Cell::new(false),
universe: Cell::new(ty::UniverseIndex::ROOT),
- })
+ normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic
+ .as_ref()
+ .map(|f| f.clone()),
+ }
}
}
@@ -641,7 +652,7 @@ impl<'tcx, T> InferOk<'tcx, T> {
/// Extracts `value`, registering any obligations into `fulfill_cx`.
pub fn into_value_registering_obligations(
self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
fulfill_cx: &mut dyn TraitEngine<'tcx>,
) -> T {
let InferOk { value, obligations } = self;
@@ -657,29 +668,34 @@ impl<'tcx> InferOk<'tcx, ()> {
}
#[must_use = "once you start a snapshot, you should always consume it"]
-pub struct CombinedSnapshot<'a, 'tcx> {
+pub struct CombinedSnapshot<'tcx> {
undo_snapshot: Snapshot<'tcx>,
region_constraints_snapshot: RegionSnapshot,
universe: ty::UniverseIndex,
was_in_snapshot: bool,
- _in_progress_typeck_results: Option<Ref<'a, ty::TypeckResults<'tcx>>>,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
+ /// Creates a `TypeErrCtxt` for emitting various inference errors.
+ /// During typeck, use `FnCtxt::infer_err` instead.
+ pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
+ TypeErrCtxt { infcx: self, typeck_results: None }
+ }
+
/// calls `tcx.try_unify_abstract_consts` after
/// canonicalizing the consts.
#[instrument(skip(self), level = "debug")]
pub fn try_unify_abstract_consts(
&self,
- a: ty::Unevaluated<'tcx, ()>,
- b: ty::Unevaluated<'tcx, ()>,
+ a: ty::UnevaluatedConst<'tcx>,
+ b: ty::UnevaluatedConst<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
// Reject any attempt to unify two unevaluated constants that contain inference
// variables, since inference variables in queries lead to ICEs.
- if a.substs.has_infer_types_or_consts()
- || b.substs.has_infer_types_or_consts()
- || param_env.has_infer_types_or_consts()
+ if a.substs.has_non_region_infer()
+ || b.substs.has_non_region_infer()
+ || param_env.has_non_region_infer()
{
debug!("a or b or param_env contain infer vars in its substs -> cannot unify");
return false;
@@ -704,7 +720,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// if this is not a type variable.
///
/// No attempt is made to resolve `ty`.
- pub fn type_var_origin(&'a self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
+ pub fn type_var_origin(&self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
match *ty.kind() {
ty::Infer(ty::TyVar(vid)) => {
Some(*self.inner.borrow_mut().type_variables().var_origin(vid))
@@ -745,7 +761,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
vars
}
- fn combine_fields(
+ fn combine_fields<'a>(
&'a self,
trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -787,7 +803,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
result
}
- fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> {
+ fn start_snapshot(&self) -> CombinedSnapshot<'tcx> {
debug!("start_snapshot()");
let in_snapshot = self.in_snapshot.replace(true);
@@ -799,22 +815,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
universe: self.universe(),
was_in_snapshot: in_snapshot,
- // Borrow typeck results "in progress" (i.e., during typeck)
- // to ban writes from within a snapshot to them.
- _in_progress_typeck_results: self
- .in_progress_typeck_results
- .map(|typeck_results| typeck_results.borrow()),
}
}
#[instrument(skip(self, snapshot), level = "debug")]
- fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
+ fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'tcx>) {
let CombinedSnapshot {
undo_snapshot,
region_constraints_snapshot,
universe,
was_in_snapshot,
- _in_progress_typeck_results,
} = snapshot;
self.in_snapshot.set(was_in_snapshot);
@@ -826,13 +836,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
#[instrument(skip(self, snapshot), level = "debug")]
- fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
+ fn commit_from(&self, snapshot: CombinedSnapshot<'tcx>) {
let CombinedSnapshot {
undo_snapshot,
region_constraints_snapshot: _,
universe: _,
was_in_snapshot,
- _in_progress_typeck_results,
} = snapshot;
self.in_snapshot.set(was_in_snapshot);
@@ -844,7 +853,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self, f), level = "debug")]
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
where
- F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>,
+ F: FnOnce(&CombinedSnapshot<'tcx>) -> Result<T, E>,
{
let snapshot = self.start_snapshot();
let r = f(&snapshot);
@@ -864,7 +873,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self, f), level = "debug")]
pub fn probe<R, F>(&self, f: F) -> R
where
- F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
+ F: FnOnce(&CombinedSnapshot<'tcx>) -> R,
{
let snapshot = self.start_snapshot();
let r = f(&snapshot);
@@ -876,7 +885,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self, f), level = "debug")]
pub fn probe_maybe_skip_leak_check<R, F>(&self, should_skip: bool, f: F) -> R
where
- F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
+ F: FnOnce(&CombinedSnapshot<'tcx>) -> R,
{
let snapshot = self.start_snapshot();
let was_skip_leak_check = self.skip_leak_check.get();
@@ -896,7 +905,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders
pub fn region_constraints_added_in_snapshot(
&self,
- snapshot: &CombinedSnapshot<'a, 'tcx>,
+ snapshot: &CombinedSnapshot<'tcx>,
) -> Option<bool> {
self.inner
.borrow_mut()
@@ -904,7 +913,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.region_constraints_added_in_snapshot(&snapshot.undo_snapshot)
}
- pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'a, 'tcx>) -> bool {
+ pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'tcx>) -> bool {
self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
}
@@ -988,7 +997,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
predicate: ty::PolyCoercePredicate<'tcx>,
- ) -> Option<InferResult<'tcx, ()>> {
+ ) -> Result<InferResult<'tcx, ()>, (TyVid, TyVid)> {
let subtype_predicate = predicate.map_bound(|p| ty::SubtypePredicate {
a_is_expected: false, // when coercing from `a` to `b`, `b` is expected
a: p.a,
@@ -1002,7 +1011,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
predicate: ty::PolySubtypePredicate<'tcx>,
- ) -> Option<InferResult<'tcx, ()>> {
+ ) -> Result<InferResult<'tcx, ()>, (TyVid, TyVid)> {
// Check for two unresolved inference variables, in which case we can
// make no progress. This is partly a micro-optimization, but it's
// also an opportunity to "sub-unify" the variables. This isn't
@@ -1021,12 +1030,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
match (r_a.kind(), r_b.kind()) {
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
self.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
- return None;
+ return Err((a_vid, b_vid));
}
_ => {}
}
- Some(self.commit_if_ok(|_snapshot| {
+ Ok(self.commit_if_ok(|_snapshot| {
let ty::SubtypePredicate { a_is_expected, a, b } =
self.replace_bound_vars_with_placeholders(predicate);
@@ -1141,8 +1150,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Return the universe that the region `r` was created in. For
/// most regions (e.g., `'static`, named regions from the user,
/// etc) this is the root universe U0. For inference variables or
- /// placeholders, however, it will return the universe which which
- /// they are associated.
+ /// placeholders, however, it will return the universe which they
+ /// are associated.
pub fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex {
self.inner.borrow_mut().unwrap_region_constraints().universe(r)
}
@@ -1227,23 +1236,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn is_tainted_by_errors(&self) -> bool {
debug!(
"is_tainted_by_errors(err_count={}, err_count_on_creation={}, \
- tainted_by_errors_flag={})",
+ tainted_by_errors={})",
self.tcx.sess.err_count(),
self.err_count_on_creation,
- self.tainted_by_errors_flag.get()
+ self.tainted_by_errors.get().is_some()
);
if self.tcx.sess.err_count() > self.err_count_on_creation {
return true; // errors reported since this infcx was made
}
- self.tainted_by_errors_flag.get()
+ self.tainted_by_errors.get().is_some()
}
/// Set the "tainted by errors" flag to true. We call this when we
/// observe an error from a prior pass.
pub fn set_tainted_by_errors(&self) {
debug!("set_tainted_by_errors()");
- self.tainted_by_errors_flag.set(true)
+ self.tainted_by_errors.set(Some(
+ self.tcx.sess.delay_span_bug(DUMMY_SP, "`InferCtxt` incorrectly tainted by errors"),
+ ));
}
pub fn skip_region_resolution(&self) {
@@ -1272,7 +1283,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
assert!(old_value.is_none());
}
- /// Process the region constraints and return any any errors that
+ /// Process the region constraints and return any errors that
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_vars_if_possible` as well as `fully_resolve`.
@@ -1306,32 +1317,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
errors
}
-
- /// Process the region constraints and report any errors that
- /// result. After this, no more unification operations should be
- /// done -- or the compiler will panic -- but it is legal to use
- /// `resolve_vars_if_possible` as well as `fully_resolve`.
- ///
- /// Make sure to call [`InferCtxt::process_registered_region_obligations`]
- /// first, or preferrably use [`InferCtxt::check_region_obligations_and_report_errors`]
- /// to do both of these operations together.
- pub fn resolve_regions_and_report_errors(
- &self,
- generic_param_scope: LocalDefId,
- outlives_env: &OutlivesEnvironment<'tcx>,
- ) {
- let errors = self.resolve_regions(outlives_env);
-
- if !self.is_tainted_by_errors() {
- // As a heuristic, just skip reporting region errors
- // altogether if other errors have been reported while
- // this infcx was in use. This is totally hokey but
- // otherwise we have a hard time separating legit region
- // errors from silly ones.
- self.report_region_errors(generic_param_scope, &errors);
- }
- }
-
/// Obtains (and clears) the current set of region
/// constraints. The inference context is still usable: further
/// unifications will simply add new constraints.
@@ -1484,62 +1469,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
* except during the writeback phase.
*/
- resolve::fully_resolve(self, value)
- }
-
- // [Note-Type-error-reporting]
- // An invariant is that anytime the expected or actual type is Error (the special
- // error type, meaning that an error occurred when typechecking this expression),
- // this is a derived error. The error cascaded from another error (that was already
- // reported), so it's not useful to display it to the user.
- // The following methods implement this logic.
- // They check if either the actual or expected type is Error, and don't print the error
- // in this case. The typechecker should only ever report type errors involving mismatched
- // types using one of these methods, and should not call span_err directly for such
- // errors.
-
- pub fn type_error_struct_with_diag<M>(
- &self,
- sp: Span,
- mk_diag: M,
- actual_ty: Ty<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
- where
- M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>,
- {
- let actual_ty = self.resolve_vars_if_possible(actual_ty);
- debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
-
- let mut err = mk_diag(self.ty_to_string(actual_ty));
-
- // Don't report an error if actual type is `Error`.
- if actual_ty.references_error() {
- err.downgrade_to_delayed_bug();
- }
-
- err
- }
-
- pub fn report_mismatched_types(
- &self,
- cause: &ObligationCause<'tcx>,
- expected: Ty<'tcx>,
- actual: Ty<'tcx>,
- err: TypeError<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let trace = TypeTrace::types(cause, true, expected, actual);
- self.report_and_explain_type_error(trace, &err)
- }
-
- pub fn report_mismatched_consts(
- &self,
- cause: &ObligationCause<'tcx>,
- expected: ty::Const<'tcx>,
- actual: ty::Const<'tcx>,
- err: TypeError<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let trace = TypeTrace::consts(cause, true, expected, actual);
- self.report_and_explain_type_error(trace, &err)
+ let value = resolve::fully_resolve(self, value);
+ assert!(
+ value.as_ref().map_or(true, |value| !value.needs_infer()),
+ "`{value:?}` is not fully resolved"
+ );
+ value
}
pub fn replace_bound_vars_with_fresh_vars<T>(
@@ -1556,7 +1491,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
struct ToFreshVars<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
span: Span,
lbrct: LateBoundRegionConversionTime,
map: FxHashMap<ty::BoundVar, ty::GenericArg<'tcx>>,
@@ -1656,7 +1591,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn try_const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
- unevaluated: ty::Unevaluated<'tcx>,
+ unevaluated: ty::UnevaluatedConst<'tcx>,
ty: Ty<'tcx>,
span: Option<Span>,
) -> Result<ty::Const<'tcx>, ErrorHandled> {
@@ -1691,7 +1626,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn const_eval_resolve(
&self,
mut param_env: ty::ParamEnv<'tcx>,
- unevaluated: ty::Unevaluated<'tcx>,
+ unevaluated: ty::UnevaluatedConst<'tcx>,
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
let mut substs = self.resolve_vars_if_possible(unevaluated.substs);
@@ -1699,8 +1634,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// Postpone the evaluation of constants whose substs depend on inference
// variables
- if substs.has_infer_types_or_consts() {
- let ac = AbstractConst::new(self.tcx, unevaluated.shrink());
+ if substs.has_non_region_infer() {
+ let ac = AbstractConst::new(self.tcx, unevaluated);
match ac {
Ok(None) => {
substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did);
@@ -1722,11 +1657,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
debug!(?param_env_erased);
debug!(?substs_erased);
- let unevaluated = ty::Unevaluated {
- def: unevaluated.def,
- substs: substs_erased,
- promoted: unevaluated.promoted,
- };
+ let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, substs: substs_erased };
// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
@@ -1785,6 +1716,86 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+ /// Process the region constraints and report any errors that
+ /// result. After this, no more unification operations should be
+ /// done -- or the compiler will panic -- but it is legal to use
+ /// `resolve_vars_if_possible` as well as `fully_resolve`.
+ ///
+ /// Make sure to call [`InferCtxt::process_registered_region_obligations`]
+ /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
+ /// to do both of these operations together.
+ pub fn resolve_regions_and_report_errors(
+ &self,
+ generic_param_scope: LocalDefId,
+ outlives_env: &OutlivesEnvironment<'tcx>,
+ ) {
+ let errors = self.resolve_regions(outlives_env);
+
+ if !self.is_tainted_by_errors() {
+ // As a heuristic, just skip reporting region errors
+ // altogether if other errors have been reported while
+ // this infcx was in use. This is totally hokey but
+ // otherwise we have a hard time separating legit region
+ // errors from silly ones.
+ self.report_region_errors(generic_param_scope, &errors);
+ }
+ }
+
+ // [Note-Type-error-reporting]
+ // An invariant is that anytime the expected or actual type is Error (the special
+ // error type, meaning that an error occurred when typechecking this expression),
+ // this is a derived error. The error cascaded from another error (that was already
+ // reported), so it's not useful to display it to the user.
+ // The following methods implement this logic.
+ // They check if either the actual or expected type is Error, and don't print the error
+ // in this case. The typechecker should only ever report type errors involving mismatched
+ // types using one of these methods, and should not call span_err directly for such
+ // errors.
+
+ pub fn type_error_struct_with_diag<M>(
+ &self,
+ sp: Span,
+ mk_diag: M,
+ actual_ty: Ty<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
+ where
+ M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ {
+ let actual_ty = self.resolve_vars_if_possible(actual_ty);
+ debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
+
+ let mut err = mk_diag(self.ty_to_string(actual_ty));
+
+ // Don't report an error if actual type is `Error`.
+ if actual_ty.references_error() {
+ err.downgrade_to_delayed_bug();
+ }
+
+ err
+ }
+
+ pub fn report_mismatched_types(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ expected: Ty<'tcx>,
+ actual: Ty<'tcx>,
+ err: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
+ }
+
+ pub fn report_mismatched_consts(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ expected: ty::Const<'tcx>,
+ actual: ty::Const<'tcx>,
+ err: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
+ }
+}
+
/// Helper for `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)]
@@ -1814,7 +1825,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> {
/// Tries to extract an inference variable from a type, returns `None`
/// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`).
- pub fn maybe_from_ty(ty: Ty<'tcx>) -> Option<Self> {
+ fn maybe_from_ty(ty: Ty<'tcx>) -> Option<Self> {
match *ty.kind() {
ty::Infer(ty::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)),
ty::Infer(ty::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)),
@@ -1825,7 +1836,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> {
/// Tries to extract an inference variable from a constant, returns `None`
/// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
- pub fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
+ fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
match ct.kind() {
ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
_ => None,
@@ -1854,7 +1865,7 @@ impl<'tcx> TypeFolder<'tcx> for InferenceLiteralEraser<'tcx> {
}
struct ShallowResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
@@ -1937,6 +1948,18 @@ impl<'tcx> TypeTrace<'tcx> {
}
}
+ pub fn poly_trait_refs(
+ cause: &ObligationCause<'tcx>,
+ a_is_expected: bool,
+ a: ty::PolyTraitRef<'tcx>,
+ b: ty::PolyTraitRef<'tcx>,
+ ) -> TypeTrace<'tcx> {
+ TypeTrace {
+ cause: cause.clone(),
+ values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+ }
+ }
+
pub fn consts(
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
@@ -1962,6 +1985,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
DataBorrowed(_, a) => a,
ReferenceOutlivesReferent(_, a) => a,
CompareImplItemObligation { span, .. } => span,
+ AscribeUserTypeProvePredicate(span) => span,
CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
}
}
@@ -1994,6 +2018,10 @@ impl<'tcx> SubregionOrigin<'tcx> {
parent: Box::new(default()),
},
+ traits::ObligationCauseCode::AscribeUserTypeProvePredicate(span) => {
+ SubregionOrigin::AscribeUserTypeProvePredicate(span)
+ }
+
_ => default(),
}
}
@@ -2015,16 +2043,6 @@ impl RegionVariableOrigin {
}
}
-impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(
- f,
- "RegionObligation(sub_region={:?}, sup_type={:?})",
- self.sub_region, self.sup_type
- )
- }
-}
-
/// Replaces substs that reference param or infer variables with suitable
/// placeholders. This function is meant to remove these param and infer
/// substs when they're not actually needed to evaluate a constant.
@@ -2034,21 +2052,17 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
) -> SubstsRef<'tcx> {
tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| {
match arg.unpack() {
- GenericArgKind::Type(_)
- if arg.has_param_types_or_consts() || arg.has_infer_types_or_consts() =>
- {
+ GenericArgKind::Type(_) if arg.has_non_region_param() || arg.has_non_region_infer() => {
tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::ROOT,
name: ty::BoundVar::from_usize(idx),
}))
.into()
}
- GenericArgKind::Const(ct)
- if ct.has_infer_types_or_consts() || ct.has_param_types_or_consts() =>
- {
+ GenericArgKind::Const(ct) if ct.has_non_region_infer() || ct.has_non_region_param() => {
let ty = ct.ty();
// If the type references param or infer, replace that too...
- if ty.has_param_types_or_consts() || ty.has_infer_types_or_consts() {
+ if ty.has_non_region_param() || ty.has_non_region_infer() {
bug!("const `{ct}`'s type should not reference params or types");
}
tcx.mk_const(ty::ConstS {
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index bab4f3e9e..600f94f09 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -25,7 +25,9 @@ use crate::infer::combine::ConstEquateRelation;
use crate::infer::InferCtxt;
use crate::infer::{ConstVarValue, ConstVariableValue};
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::traits::PredicateObligation;
use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
@@ -44,7 +46,7 @@ pub struct TypeRelating<'me, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
/// Callback to use when we deduce an outlives relationship.
delegate: D,
@@ -91,11 +93,9 @@ pub trait TypeRelatingDelegate<'tcx> {
);
fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
- fn register_opaque_type(
+ fn register_opaque_type_obligations(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- a_is_expected: bool,
+ obligations: Vec<PredicateObligation<'tcx>>,
) -> Result<(), TypeError<'tcx>>;
/// Creates a new universe index. Used when instantiating placeholders.
@@ -149,11 +149,7 @@ impl<'me, 'tcx, D> TypeRelating<'me, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
- pub fn new(
- infcx: &'me InferCtxt<'me, 'tcx>,
- delegate: D,
- ambient_variance: ty::Variance,
- ) -> Self {
+ pub fn new(infcx: &'me InferCtxt<'tcx>, delegate: D, ambient_variance: ty::Variance) -> Self {
Self {
infcx,
delegate,
@@ -357,7 +353,7 @@ where
// In NLL, we don't have type inference variables
// floating around, so we can do this rather imprecise
// variant of the occurs-check.
- assert!(!generalized_ty.has_infer_types_or_consts());
+ assert!(!generalized_ty.has_non_region_infer());
}
self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty);
@@ -396,6 +392,37 @@ where
generalizer.relate(value, value)
}
+
+ fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
+ let mut generalize = |ty, ty_is_expected| {
+ let var = self.infcx.next_ty_var_id_in_universe(
+ TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span: self.delegate.span(),
+ },
+ ty::UniverseIndex::ROOT,
+ );
+ if ty_is_expected {
+ self.relate_ty_var((ty, var))
+ } else {
+ self.relate_ty_var((var, ty))
+ }
+ };
+ let (a, b) = match (a.kind(), b.kind()) {
+ (&ty::Opaque(..), _) => (a, generalize(b, false)?),
+ (_, &ty::Opaque(..)) => (generalize(a, true)?, b),
+ _ => unreachable!(),
+ };
+ let cause = ObligationCause::dummy_with_span(self.delegate.span());
+ let obligations = self
+ .infcx
+ .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())?
+ .obligations;
+ self.delegate.register_opaque_type_obligations(obligations)?;
+ trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
+ Ok(a)
+ }
}
/// When we instantiate an inference variable with a value in
@@ -516,7 +543,7 @@ where
true
}
- #[instrument(skip(self, info), level = "trace")]
+ #[instrument(skip(self, info), level = "trace", ret)]
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
@@ -534,8 +561,6 @@ where
self.ambient_variance = old_ambient_variance;
- debug!(?r);
-
Ok(r)
}
@@ -572,32 +597,16 @@ where
(&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
(&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
- self.infcx.super_combine_tys(self, a, b)
+ infcx.super_combine_tys(self, a, b).or_else(|err| {
+ self.tcx().sess.delay_span_bug(
+ self.delegate.span(),
+ "failure to relate an opaque to itself should result in an error later on",
+ );
+ if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
+ })
}
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => {
- let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
- let mut generalize = |ty, ty_is_expected| {
- let var = infcx.next_ty_var_id_in_universe(
- TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: self.delegate.span(),
- },
- ty::UniverseIndex::ROOT,
- );
- if ty_is_expected {
- self.relate_ty_var((ty, var))
- } else {
- self.relate_ty_var((var, ty))
- }
- };
- let (a, b) = match (a.kind(), b.kind()) {
- (&ty::Opaque(..), _) => (a, generalize(b, false)?),
- (_, &ty::Opaque(..)) => (generalize(a, true)?, b),
- _ => unreachable!(),
- };
- self.delegate.register_opaque_type(a, b, true)?;
- trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
- Ok(a)
+ self.relate_opaques(a, b)
}
(&ty::Projection(projection_ty), _)
@@ -859,7 +868,7 @@ struct TypeGeneralizer<'me, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
delegate: &'me mut D,
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index e579afbf3..a982f11f7 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,13 +1,16 @@
+use crate::errors::OpaqueHiddenTypeDiag;
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
use crate::traits;
+use hir::def::DefKind;
use hir::def_id::{DefId, LocalDefId};
use hir::{HirId, OpaqueTyOrigin};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
use rustc_middle::traits::ObligationCause;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::subst::{GenericArgKind, Subst};
+use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::{
self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitor,
@@ -39,7 +42,7 @@ pub struct OpaqueTypeDecl<'tcx> {
pub origin: hir::OpaqueTyOrigin,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// This is a backwards compatibility hack to prevent breaking changes from
/// lazy TAIT around RPIT handling.
pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>(
@@ -72,7 +75,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// for opaque types, and then use that kind to fix the spans for type errors
// that we see later on.
let ty_var = self.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
+ kind: TypeVariableOriginKind::OpaqueTypeInference(def_id),
span,
});
obligations.extend(
@@ -100,7 +103,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
return Ok(InferOk { value: (), obligations: vec![] });
}
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
- let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
+ let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
ty::Opaque(def_id, substs) if def_id.is_local() => {
let def_id = def_id.expect_local();
let origin = match self.defining_use_anchor {
@@ -153,22 +156,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
if let Some(OpaqueTyOrigin::TyAlias) =
did2.as_local().and_then(|did2| self.opaque_type_origin(did2, cause.span))
{
- self.tcx
- .sess
- .struct_span_err(
- cause.span,
- "opaque type's hidden type cannot be another opaque type from the same scope",
- )
- .span_label(cause.span, "one of the two opaque types used here has to be outside its defining scope")
- .span_note(
- self.tcx.def_span(def_id),
- "opaque type whose hidden type is being assigned",
- )
- .span_note(
- self.tcx.def_span(did2),
- "opaque type being used as hidden type",
- )
- .emit();
+ self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
+ span: cause.span,
+ hidden_type: self.tcx.def_span(did2),
+ opaque_type: self.tcx.def_span(def_id),
+ });
}
}
Some(self.register_hidden_type(
@@ -177,25 +169,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
param_env,
b,
origin,
+ a_is_expected,
))
}
_ => None,
};
- if let Some(res) = process(a, b) {
+ if let Some(res) = process(a, b, true) {
res
- } else if let Some(res) = process(b, a) {
+ } else if let Some(res) = process(b, a, false) {
res
} else {
- // Rerun equality check, but this time error out due to
- // different types.
- match self.at(cause, param_env).define_opaque_types(false).eq(a, b) {
- Ok(_) => span_bug!(
- cause.span,
- "opaque types are never equal to anything but themselves: {:#?}",
- (a.kind(), b.kind())
- ),
- Err(e) => Err(e),
- }
+ let (a, b) = self.resolve_vars_if_possible((a, b));
+ Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
}
}
@@ -400,7 +385,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
});
}
- #[instrument(skip(self), level = "trace")]
+ #[instrument(skip(self), level = "trace", ret)]
pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<OpaqueTyOrigin> {
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let parent_def_id = match self.defining_use_anchor {
@@ -431,16 +416,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
in_definition_scope.then_some(*origin)
}
- #[instrument(skip(self), level = "trace")]
+ #[instrument(skip(self), level = "trace", ret)]
fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin {
- let origin = match self.tcx.hir().expect_item(def_id).kind {
+ match self.tcx.hir().expect_item(def_id).kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
ref itemkind => {
span_bug!(span, "weird opaque type: {:?}, {:#?}", def_id, itemkind)
}
- };
- trace!(?origin);
- origin
+ }
}
}
@@ -530,15 +513,16 @@ impl UseKind {
}
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
#[instrument(skip(self), level = "debug")]
- pub fn register_hidden_type(
+ fn register_hidden_type(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
origin: hir::OpaqueTyOrigin,
+ a_is_expected: bool,
) -> InferResult<'tcx, ()> {
let tcx = self.tcx;
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
@@ -557,21 +541,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin,
);
if let Some(prev) = prev {
- obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations;
+ obligations =
+ self.at(&cause, param_env).eq_exp(a_is_expected, prev, hidden_ty)?.obligations;
}
let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id());
- for predicate in item_bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
- debug!(?predicate);
- let predicate = predicate.subst(tcx, substs);
-
+ for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) {
let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| match *ty.kind() {
// We can't normalize associated types from `rustc_infer`,
// but we can eagerly register inference variables for them.
- ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
+ // FIXME(RPITIT): Don't replace RPITITs with inference vars.
+ ty::Projection(projection_ty)
+ if !projection_ty.has_escaping_bound_vars()
+ && tcx.def_kind(projection_ty.item_def_id)
+ != DefKind::ImplTraitPlaceholder =>
+ {
self.infer_projection(
param_env,
projection_ty,
@@ -587,6 +574,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
{
hidden_ty
}
+ // FIXME(RPITIT): This can go away when we move to associated types
+ ty::Projection(proj)
+ if def_id.to_def_id() == proj.item_def_id && substs == proj.substs =>
+ {
+ hidden_ty
+ }
_ => ty,
},
lt_op: |lt| lt,
@@ -635,7 +628,7 @@ fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hi
let scope = tcx.hir().get_defining_scope(opaque_hir_id);
// We walk up the node tree until we hit the root or the scope of the opaque type.
while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
- hir_id = tcx.hir().local_def_id_to_hir_id(tcx.hir().get_parent_item(hir_id));
+ hir_id = tcx.hir().get_parent_item(hir_id).into();
}
// Syntactically, we are allowed to define the concrete type if:
let res = hir_id == scope;
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index fb12da0cc..4d124554a 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -29,7 +29,7 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
}
}
- #[instrument(level = "debug")]
+ #[instrument(level = "debug", ret)]
pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> {
std::mem::take(&mut self.opaque_types)
}
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index b2d7f4a66..14ee9f051 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -3,8 +3,9 @@
// RFC for reference.
use rustc_data_structures::sso::SsoHashSet;
+use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitable};
use smallvec::{smallvec, SmallVec};
#[derive(Debug)]
@@ -45,6 +46,8 @@ pub enum Component<'tcx> {
// them. This gives us room to improve the regionck reasoning in
// the future without breaking backwards compat.
EscapingProjection(Vec<Component<'tcx>>),
+
+ Opaque(DefId, SubstsRef<'tcx>),
}
/// Push onto `out` all the things that must outlive `'a` for the condition
@@ -120,6 +123,17 @@ fn compute_components<'tcx>(
out.push(Component::Param(p));
}
+ // Ignore lifetimes found in opaque types. Opaque types can
+ // have lifetimes in their substs which their hidden type doesn't
+ // actually use. If we inferred that an opaque type is outlived by
+ // its parameter lifetimes, then we could prove that any lifetime
+ // outlives any other lifetime, which is unsound.
+ // See https://github.com/rust-lang/rust/issues/84305 for
+ // more details.
+ ty::Opaque(def_id, substs) => {
+ out.push(Component::Opaque(def_id, substs));
+ },
+
// For projections, we prefer to generate an obligation like
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
// regionck more ways to prove that it holds. However,
@@ -168,7 +182,6 @@ fn compute_components<'tcx>(
ty::Float(..) | // OutlivesScalar
ty::Never | // ...
ty::Adt(..) | // OutlivesNominalType
- ty::Opaque(..) | // OutlivesNominalType (ish)
ty::Foreign(..) | // OutlivesNominalType
ty::Str | // OutlivesScalar (ish)
ty::Slice(..) | // ...
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index b2decd64f..33543135d 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -2,6 +2,7 @@ use crate::infer::free_regions::FreeRegionMap;
use crate::infer::{GenericKind, InferCtxt};
use crate::traits::query::OutlivesBound;
use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region};
use super::explicit_outlives_bounds;
@@ -51,23 +52,49 @@ pub struct OutlivesEnvironment<'tcx> {
region_bound_pairs: RegionBoundPairs<'tcx>,
}
+/// Builder of OutlivesEnvironment.
+#[derive(Debug)]
+struct OutlivesEnvironmentBuilder<'tcx> {
+ param_env: ty::ParamEnv<'tcx>,
+ region_relation: TransitiveRelationBuilder<Region<'tcx>>,
+ region_bound_pairs: RegionBoundPairs<'tcx>,
+}
+
/// "Region-bound pairs" tracks outlives relations that are known to
/// be true, either because of explicit where-clauses like `T: 'a` or
/// because of implied bounds.
pub type RegionBoundPairs<'tcx> =
FxIndexSet<ty::OutlivesPredicate<GenericKind<'tcx>, Region<'tcx>>>;
-impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
- pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
- let mut env = OutlivesEnvironment {
+impl<'tcx> OutlivesEnvironment<'tcx> {
+ /// Create a builder using `ParamEnv` and add explicit outlives bounds into it.
+ fn builder(param_env: ty::ParamEnv<'tcx>) -> OutlivesEnvironmentBuilder<'tcx> {
+ let mut builder = OutlivesEnvironmentBuilder {
param_env,
- free_region_map: Default::default(),
+ region_relation: Default::default(),
region_bound_pairs: Default::default(),
};
- env.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
+ builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
- env
+ builder
+ }
+
+ #[inline]
+ /// Create a new `OutlivesEnvironment` without extra outlives bounds.
+ pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
+ Self::builder(param_env).build()
+ }
+
+ /// Create a new `OutlivesEnvironment` with extra outlives bounds.
+ pub fn with_bounds(
+ param_env: ty::ParamEnv<'tcx>,
+ infcx: Option<&InferCtxt<'tcx>>,
+ extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
+ ) -> Self {
+ let mut builder = Self::builder(param_env);
+ builder.add_outlives_bounds(infcx, extra_bounds);
+ builder.build()
}
/// Borrows current value of the `free_region_map`.
@@ -79,6 +106,18 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
&self.region_bound_pairs
}
+}
+
+impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
+ #[inline]
+ #[instrument(level = "debug")]
+ fn build(self) -> OutlivesEnvironment<'tcx> {
+ OutlivesEnvironment {
+ param_env: self.param_env,
+ free_region_map: FreeRegionMap { relation: self.region_relation.freeze() },
+ region_bound_pairs: self.region_bound_pairs,
+ }
+ }
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
///
@@ -86,11 +125,8 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
/// contain inference variables, it must be supplied, in which
/// case we will register "givens" on the inference context. (See
/// `RegionConstraintData`.)
- pub fn add_outlives_bounds<I>(
- &mut self,
- infcx: Option<&InferCtxt<'a, 'tcx>>,
- outlives_bounds: I,
- ) where
+ fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I)
+ where
I: IntoIterator<Item = OutlivesBound<'tcx>>,
{
// Record relationships such as `T:'x` that don't go into the
@@ -106,6 +142,10 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
}
+ OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
+ self.region_bound_pairs
+ .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+ }
OutlivesBound::RegionSubRegion(r_a, r_b) => {
if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
infcx
@@ -122,7 +162,9 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
// system to be more general and to make use
// of *every* relationship that arises here,
// but presently we do not.)
- self.free_region_map.relate_regions(r_a, r_b);
+ if r_a.is_free_or_static() && r_b.is_free() {
+ self.region_relation.add(r_a, r_b)
+ }
}
}
}
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 2a085288f..2d19d1823 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -9,7 +9,7 @@ pub mod verify;
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty;
-#[instrument(level = "debug", skip(param_env))]
+#[instrument(level = "debug", skip(param_env), ret)]
pub fn explicit_outlives_bounds<'tcx>(
param_env: ty::ParamEnv<'tcx>,
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index ad052f58c..6ca884799 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -68,12 +68,14 @@ use crate::infer::{
};
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::undo_log::UndoLogs;
+use rustc_hir::def_id::DefId;
use rustc_hir::def_id::LocalDefId;
+use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
use smallvec::smallvec;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Registers that the given region obligation must be resolved
/// from within the scope of `body_id`. These regions are enqueued
/// and later processed by regionck, when full type information is
@@ -92,12 +94,14 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
sub_region: Region<'tcx>,
cause: &ObligationCause<'tcx>,
) {
+ debug!(?sup_type, ?sub_region, ?cause);
let origin = SubregionOrigin::from_obligation_cause(cause, || {
infer::RelateParamBound(
cause.span,
sup_type,
match cause.code().peel_derives() {
- ObligationCauseCode::BindingObligation(_, span) => Some(*span),
+ ObligationCauseCode::BindingObligation(_, span)
+ | ObligationCauseCode::ExprBindingObligation(_, span, ..) => Some(*span),
_ => None,
},
)
@@ -161,7 +165,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
let outlives =
&mut TypeOutlives::new(self, self.tcx, &region_bound_pairs, None, param_env);
- outlives.type_must_outlive(origin, sup_type, sub_region);
+ let category = origin.to_constraint_category();
+ outlives.type_must_outlive(origin, sup_type, sub_region, category);
}
}
@@ -178,7 +183,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
outlives_env.param_env,
);
- self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
+ self.err_ctxt().resolve_regions_and_report_errors(generic_param_scope, outlives_env)
}
}
@@ -205,6 +210,7 @@ pub trait TypeOutlivesDelegate<'tcx> {
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
+ constraint_category: ConstraintCategory<'tcx>,
);
fn push_verify(
@@ -247,19 +253,19 @@ where
/// - `origin`, the reason we need this constraint
/// - `ty`, the type `T`
/// - `region`, the region `'a`
+ #[instrument(level = "debug", skip(self))]
pub fn type_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,
ty: Ty<'tcx>,
region: ty::Region<'tcx>,
+ category: ConstraintCategory<'tcx>,
) {
- debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})", ty, region, origin);
-
assert!(!ty.has_escaping_bound_vars());
let mut components = smallvec![];
push_outlives_components(self.tcx, ty, &mut components);
- self.components_must_outlive(origin, &components, region);
+ self.components_must_outlive(origin, &components, region, category);
}
fn components_must_outlive(
@@ -267,21 +273,25 @@ where
origin: infer::SubregionOrigin<'tcx>,
components: &[Component<'tcx>],
region: ty::Region<'tcx>,
+ category: ConstraintCategory<'tcx>,
) {
for component in components.iter() {
let origin = origin.clone();
match component {
Component::Region(region1) => {
- self.delegate.push_sub_region_constraint(origin, region, *region1);
+ self.delegate.push_sub_region_constraint(origin, region, *region1, category);
}
Component::Param(param_ty) => {
self.param_ty_must_outlive(origin, region, *param_ty);
}
+ Component::Opaque(def_id, substs) => {
+ self.opaque_must_outlive(*def_id, substs, origin, region)
+ }
Component::Projection(projection_ty) => {
self.projection_must_outlive(origin, region, *projection_ty);
}
Component::EscapingProjection(subcomponents) => {
- self.components_must_outlive(origin, &subcomponents, region);
+ self.components_must_outlive(origin, &subcomponents, region, category);
}
Component::UnresolvedInferenceVariable(v) => {
// ignore this, we presume it will yield an error
@@ -308,17 +318,69 @@ where
);
let generic = GenericKind::Param(param_ty);
- let verify_bound = self.verify_bound.generic_bound(generic);
+ let verify_bound = self.verify_bound.param_bound(param_ty);
self.delegate.push_verify(origin, generic, region, verify_bound);
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
+ fn opaque_must_outlive(
+ &mut self,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ ) {
+ self.generic_must_outlive(
+ origin,
+ region,
+ GenericKind::Opaque(def_id, substs),
+ def_id,
+ substs,
+ true,
+ |ty| match *ty.kind() {
+ ty::Opaque(def_id, substs) => (def_id, substs),
+ _ => bug!("expected only projection types from env, not {:?}", ty),
+ },
+ );
+ }
+
+ #[instrument(level = "debug", skip(self))]
fn projection_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,
region: ty::Region<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
) {
+ self.generic_must_outlive(
+ origin,
+ region,
+ GenericKind::Projection(projection_ty),
+ projection_ty.item_def_id,
+ projection_ty.substs,
+ false,
+ |ty| match ty.kind() {
+ ty::Projection(projection_ty) => (projection_ty.item_def_id, projection_ty.substs),
+ _ => bug!("expected only projection types from env, not {:?}", ty),
+ },
+ );
+ }
+
+ #[instrument(level = "debug", skip(self, filter))]
+ fn generic_must_outlive(
+ &mut self,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ generic: GenericKind<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ is_opaque: bool,
+ filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>),
+ ) {
+ // An optimization for a common case with opaque types.
+ if substs.is_empty() {
+ return;
+ }
+
// This case is thorny for inference. The fundamental problem is
// that there are many cases where we have choice, and inference
// doesn't like choice (the current region inference in
@@ -337,16 +399,15 @@ where
// These are guaranteed to apply, no matter the inference
// results.
let trait_bounds: Vec<_> =
- self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect();
+ self.verify_bound.declared_region_bounds(def_id, substs).collect();
debug!(?trait_bounds);
// Compute the bounds we can derive from the environment. This
// is an "approximate" match -- in some cases, these bounds
// may not apply.
- let mut approx_env_bounds =
- self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty);
- debug!("projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds);
+ let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic);
+ debug!(?approx_env_bounds);
// Remove outlives bounds that we get from the environment but
// which are also deducible from the trait. This arises (cc
@@ -360,14 +421,8 @@ where
// If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
// will be invoked with `['b => ^1]` and so we will get `^1` returned.
let bound = bound_outlives.skip_binder();
- match *bound.0.kind() {
- ty::Projection(projection_ty) => self
- .verify_bound
- .projection_declared_bounds_from_trait(projection_ty)
- .all(|r| r != bound.1),
-
- _ => panic!("expected only projection types from env, not {:?}", bound.0),
- }
+ let (def_id, substs) = filter(bound.0);
+ self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1)
});
// If declared bounds list is empty, the only applicable rule is
@@ -384,23 +439,11 @@ where
// the problem is to add `T: 'r`, which isn't true. So, if there are no
// inference variables, we use a verify constraint instead of adding
// edges, which winds up enforcing the same condition.
- let needs_infer = projection_ty.needs_infer();
- if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
- debug!("projection_must_outlive: no declared bounds");
-
- for k in projection_ty.substs {
- match k.unpack() {
- GenericArgKind::Lifetime(lt) => {
- self.delegate.push_sub_region_constraint(origin.clone(), region, lt);
- }
- GenericArgKind::Type(ty) => {
- self.type_must_outlive(origin.clone(), ty, region);
- }
- GenericArgKind::Const(_) => {
- // Const parameters don't impose constraints.
- }
- }
- }
+ let needs_infer = substs.needs_infer();
+ if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) {
+ debug!("no declared bounds");
+
+ self.substs_must_outlive(substs, origin, region);
return;
}
@@ -430,9 +473,10 @@ where
.all(|b| b == Some(trait_bounds[0]))
{
let unique_bound = trait_bounds[0];
- debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
- debug!("projection_must_outlive: unique declared bound appears in trait ref");
- self.delegate.push_sub_region_constraint(origin, region, unique_bound);
+ debug!(?unique_bound);
+ debug!("unique declared bound appears in trait ref");
+ let category = origin.to_constraint_category();
+ self.delegate.push_sub_region_constraint(origin, region, unique_bound, category);
return;
}
@@ -441,19 +485,51 @@ where
// projection outlive; in some cases, this may add insufficient
// edges into the inference graph, leading to inference failures
// even though a satisfactory solution exists.
- let generic = GenericKind::Projection(projection_ty);
- let verify_bound = self.verify_bound.generic_bound(generic);
+ let verify_bound = self.verify_bound.projection_opaque_bounds(
+ generic,
+ def_id,
+ substs,
+ &mut Default::default(),
+ );
debug!("projection_must_outlive: pushing {:?}", verify_bound);
self.delegate.push_verify(origin, generic, region, verify_bound);
}
+
+ fn substs_must_outlive(
+ &mut self,
+ substs: SubstsRef<'tcx>,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ ) {
+ let constraint = origin.to_constraint_category();
+ for k in substs {
+ match k.unpack() {
+ GenericArgKind::Lifetime(lt) => {
+ self.delegate.push_sub_region_constraint(
+ origin.clone(),
+ region,
+ lt,
+ constraint,
+ );
+ }
+ GenericArgKind::Type(ty) => {
+ self.type_must_outlive(origin.clone(), ty, region, constraint);
+ }
+ GenericArgKind::Const(_) => {
+ // Const parameters don't impose constraints.
+ }
+ }
+ }
+ }
}
-impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> {
+impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'tcx> {
fn push_sub_region_constraint(
&mut self,
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
+ _constraint_category: ConstraintCategory<'tcx>,
) {
self.sub_regions(origin, a, b)
}
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 772e297b7..a5c21f0fb 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -34,7 +34,7 @@ use crate::infer::region_constraints::VerifyIfEq;
/// like are used. This is a particular challenge since this function is invoked
/// very late in inference and hence cannot make use of the normal inference
/// machinery.
-#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+#[instrument(level = "debug", skip(tcx, param_env))]
pub fn extract_verify_if_eq<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -71,7 +71,7 @@ pub fn extract_verify_if_eq<'tcx>(
}
/// True if a (potentially higher-ranked) outlives
-#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+#[instrument(level = "debug", skip(tcx, param_env))]
pub(super) fn can_match_erased_ty<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -110,7 +110,7 @@ impl<'tcx> Match<'tcx> {
/// Binds the pattern variable `br` to `value`; returns an `Err` if the pattern
/// is already bound to a different value.
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self))]
fn bind(
&mut self,
br: ty::BoundRegion,
@@ -174,7 +174,14 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
#[instrument(skip(self), level = "debug")]
fn tys(&mut self, pattern: Ty<'tcx>, value: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- if pattern == value { Ok(pattern) } else { relate::super_relate_tys(self, pattern, value) }
+ if let ty::Error(_) = pattern.kind() {
+ // Unlike normal `TypeRelation` rules, `ty::Error` does not equal any type.
+ self.no_match()
+ } else if pattern == value {
+ Ok(pattern)
+ } else {
+ relate::super_relate_tys(self, pattern, value)
+ }
}
#[instrument(skip(self), level = "debug")]
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index c7d7ef40d..f470b2eb8 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -2,11 +2,10 @@ use crate::infer::outlives::components::{compute_components_recursive, Component
use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::region_constraints::VerifyIfEq;
use crate::infer::{GenericKind, VerifyBound};
-use rustc_data_structures::captures::Captures;
use rustc_data_structures::sso::SsoHashSet;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{GenericArg, Subst};
-use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, Ty, TyCtxt};
+use rustc_middle::ty::GenericArg;
+use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
use smallvec::smallvec;
@@ -38,25 +37,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
Self { tcx, region_bound_pairs, implicit_region_bound, param_env }
}
- /// Returns a "verify bound" that encodes what we know about
- /// `generic` and the regions it outlives.
- pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
- let mut visited = SsoHashSet::new();
- match generic {
- GenericKind::Param(param_ty) => self.param_bound(param_ty),
- GenericKind::Projection(projection_ty) => {
- self.projection_bound(projection_ty, &mut visited)
- }
- }
- }
-
- fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
- debug!("param_bound(param_ty={:?})", param_ty);
-
+ #[instrument(level = "debug", skip(self))]
+ pub fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
// Start with anything like `T: 'a` we can scrape from the
// environment. If the environment contains something like
// `for<'a> T: 'a`, then we know that `T` outlives everything.
let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty);
+ debug!(?declared_bounds_from_env);
let mut param_bounds = vec![];
for declared_bound in declared_bounds_from_env {
let bound_region = declared_bound.map_bound(|outlives| outlives.1);
@@ -65,6 +52,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
param_bounds.push(VerifyBound::OutlivedBy(region));
} else {
// This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here.
+ debug!("found that {param_ty:?} outlives any lifetime, returning empty vector");
return VerifyBound::AllBounds(vec![]);
}
}
@@ -72,6 +60,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
// Add in the default bound of fn body that applies to all in
// scope type parameters:
if let Some(r) = self.implicit_region_bound {
+ debug!("adding implicit region bound of {r:?}");
param_bounds.push(VerifyBound::OutlivedBy(r));
}
@@ -103,41 +92,31 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// the clause from the environment only applies if `'0 = 'a`,
/// which we don't know yet. But we would still include `'b` in
/// this list.
- pub fn projection_approx_declared_bounds_from_env(
+ pub fn approx_declared_bounds_from_env(
&self,
- projection_ty: ty::ProjectionTy<'tcx>,
+ generic: GenericKind<'tcx>,
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
- let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
+ let projection_ty = generic.to_ty(self.tcx);
let erased_projection_ty = self.tcx.erase_regions(projection_ty);
self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
}
- /// Searches the where-clauses in scope for regions that
- /// `projection_ty` is known to outlive. Currently requires an
- /// exact match.
- pub fn projection_declared_bounds_from_trait(
+ #[instrument(level = "debug", skip(self, visited))]
+ pub fn projection_opaque_bounds(
&self,
- projection_ty: ty::ProjectionTy<'tcx>,
- ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
- self.declared_projection_bounds_from_trait(projection_ty)
- }
-
- pub fn projection_bound(
- &self,
- projection_ty: ty::ProjectionTy<'tcx>,
+ generic: GenericKind<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> {
- debug!("projection_bound(projection_ty={:?})", projection_ty);
-
- let projection_ty_as_ty =
- self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
+ let generic_ty = generic.to_ty(self.tcx);
// Search the env for where clauses like `P: 'a`.
- let env_bounds = self
- .projection_approx_declared_bounds_from_env(projection_ty)
+ let projection_opaque_bounds = self
+ .approx_declared_bounds_from_env(generic)
.into_iter()
.map(|binder| {
- if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == projection_ty_as_ty {
+ if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty {
// Micro-optimize if this is an exact match (this
// occurs often when there are no region variables
// involved).
@@ -147,21 +126,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
VerifyBound::IfEq(verify_if_eq_b)
}
});
-
// Extend with bounds that we can find from the trait.
- let trait_bounds = self
- .projection_declared_bounds_from_trait(projection_ty)
- .map(|r| VerifyBound::OutlivedBy(r));
+ let trait_bounds =
+ self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r));
// see the extensive comment in projection_must_outlive
let recursive_bound = {
let mut components = smallvec![];
- let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
- compute_components_recursive(self.tcx, ty.into(), &mut components, visited);
+ compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited);
self.bound_from_components(&components, visited)
};
- VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
+ VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect())
+ .or(recursive_bound)
}
fn bound_from_components(
@@ -193,7 +170,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
match *component {
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
Component::Param(param_ty) => self.param_bound(param_ty),
- Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited),
+ Component::Opaque(did, substs) => self.projection_opaque_bounds(
+ GenericKind::Opaque(did, substs),
+ did,
+ substs,
+ visited,
+ ),
+ Component::Projection(projection_ty) => self.projection_opaque_bounds(
+ GenericKind::Projection(projection_ty),
+ projection_ty.item_def_id,
+ projection_ty.substs,
+ visited,
+ ),
Component::EscapingProjection(ref components) => {
self.bound_from_components(components, visited)
}
@@ -291,30 +279,6 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// }
/// ```
///
- /// then this function would return `'x`. This is subject to the
- /// limitations around higher-ranked bounds described in
- /// `region_bounds_declared_on_associated_item`.
- fn declared_projection_bounds_from_trait(
- &self,
- projection_ty: ty::ProjectionTy<'tcx>,
- ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
- debug!("projection_bounds(projection_ty={:?})", projection_ty);
- let tcx = self.tcx;
- self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
- .map(move |r| EarlyBinder(r).subst(tcx, projection_ty.substs))
- }
-
- /// Given the `DefId` of an associated item, returns any region
- /// bounds attached to that associated item from the trait definition.
- ///
- /// For example:
- ///
- /// ```rust
- /// trait Foo<'a> {
- /// type Bar: 'a;
- /// }
- /// ```
- ///
/// If we were given the `DefId` of `Foo::Bar`, we would return
/// `'a`. You could then apply the substitutions from the
/// projection to convert this into your namespace. This also
@@ -334,17 +298,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
///
/// This is for simplicity, and because we are not really smart
/// enough to cope with such bounds anywhere.
- fn region_bounds_declared_on_associated_item(
+ pub fn declared_region_bounds(
&self,
- assoc_item_def_id: DefId,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
) -> impl Iterator<Item = ty::Region<'tcx>> {
let tcx = self.tcx;
- let bounds = tcx.item_bounds(assoc_item_def_id);
+ let bounds = tcx.item_bounds(def_id);
+ trace!("{:#?}", bounds);
bounds
.into_iter()
.filter_map(|p| p.to_opt_type_outlives())
.filter_map(|p| p.no_bound_vars())
.map(|b| b.1)
+ .map(move |r| EarlyBinder(r).subst(tcx, substs))
}
/// Searches through a predicate list for a predicate `T: 'a`.
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index b45a6514d..9f12bc972 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -6,7 +6,7 @@ use crate::traits::{Obligation, PredicateObligation};
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::InferCtxt;
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Instead of normalizing an associated type projection,
/// this function generates an inference variable and registers
/// an obligation that this inference variable must be the result
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index 397efe6ee..90858e307 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -66,7 +66,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
tcx: TyCtxt<'tcx>,
overly_polymorphic: bool,
max_universe: ty::UniverseIndex,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
+ snapshot: &CombinedSnapshot<'tcx>,
) -> RelateResult<'tcx, ()> {
debug!(
"leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})",
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 0d4472a1c..67b3da687 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -12,8 +12,10 @@ use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify as ut;
+use rustc_hir::def_id::DefId;
use rustc_index::vec::IndexVec;
use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
+use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::ReStatic;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReLateBound, ReVar};
@@ -168,6 +170,7 @@ pub struct Verify<'tcx> {
pub enum GenericKind<'tcx> {
Param(ty::ParamTy),
Projection(ty::ProjectionTy<'tcx>),
+ Opaque(DefId, SubstsRef<'tcx>),
}
/// Describes the things that some `GenericKind` value `G` is known to
@@ -187,7 +190,7 @@ pub enum GenericKind<'tcx> {
/// }
/// ```
/// This is described with an `AnyRegion('a, 'b)` node.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
pub enum VerifyBound<'tcx> {
/// See [`VerifyIfEq`] docs
IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>),
@@ -426,21 +429,21 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
data
}
- pub fn data(&self) -> &RegionConstraintData<'tcx> {
+ pub(super) fn data(&self) -> &RegionConstraintData<'tcx> {
&self.data
}
- pub fn start_snapshot(&mut self) -> RegionSnapshot {
+ pub(super) fn start_snapshot(&mut self) -> RegionSnapshot {
debug!("RegionConstraintCollector: start_snapshot");
RegionSnapshot { any_unifications: self.any_unifications }
}
- pub fn rollback_to(&mut self, snapshot: RegionSnapshot) {
+ pub(super) fn rollback_to(&mut self, snapshot: RegionSnapshot) {
debug!("RegionConstraintCollector: rollback_to({:?})", snapshot);
self.any_unifications = snapshot.any_unifications;
}
- pub fn new_region_var(
+ pub(super) fn new_region_var(
&mut self,
universe: ty::UniverseIndex,
origin: RegionVariableOrigin,
@@ -455,12 +458,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
/// Returns the universe for the given variable.
- pub fn var_universe(&self, vid: RegionVid) -> ty::UniverseIndex {
+ pub(super) fn var_universe(&self, vid: RegionVid) -> ty::UniverseIndex {
self.var_infos[vid].universe
}
/// Returns the origin for the given variable.
- pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
+ pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
self.var_infos[vid].origin
}
@@ -492,7 +495,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
self.undo_log.push(AddVerify(index));
}
- pub fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
+ pub(super) fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
// cannot add givens once regions are resolved
if self.data.givens.insert((sub, sup)) {
debug!("add_given({:?} <= {:?})", sub, sup);
@@ -501,7 +504,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
}
- pub fn make_eqregion(
+ pub(super) fn make_eqregion(
&mut self,
origin: SubregionOrigin<'tcx>,
sub: Region<'tcx>,
@@ -530,7 +533,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
}
- pub fn member_constraint(
+ pub(super) fn member_constraint(
&mut self,
key: ty::OpaqueTypeKey<'tcx>,
definition_span: Span,
@@ -554,7 +557,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
#[instrument(skip(self, origin), level = "debug")]
- pub fn make_subregion(
+ pub(super) fn make_subregion(
&mut self,
origin: SubregionOrigin<'tcx>,
sub: Region<'tcx>,
@@ -585,7 +588,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
}
- pub fn verify_generic_bound(
+ pub(super) fn verify_generic_bound(
&mut self,
origin: SubregionOrigin<'tcx>,
kind: GenericKind<'tcx>,
@@ -595,7 +598,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
self.add_verify(Verify { kind, origin, region: sub, bound });
}
- pub fn lub_regions(
+ pub(super) fn lub_regions(
&mut self,
tcx: TyCtxt<'tcx>,
origin: SubregionOrigin<'tcx>,
@@ -613,7 +616,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
}
- pub fn glb_regions(
+ pub(super) fn glb_regions(
&mut self,
tcx: TyCtxt<'tcx>,
origin: SubregionOrigin<'tcx>,
@@ -634,7 +637,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
/// Resolves the passed RegionVid to the root RegionVid in the unification table
- pub fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid {
+ pub(super) fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid {
self.unification_table().find(rid).vid
}
@@ -699,7 +702,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
ty::ReStatic | ty::ReErased | ty::ReFree(..) | ty::ReEarlyBound(..) => {
ty::UniverseIndex::ROOT
}
- ty::ReEmpty(ui) => ui,
ty::RePlaceholder(placeholder) => placeholder.universe,
ty::ReVar(vid) => self.var_universe(vid),
ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region),
@@ -748,6 +750,9 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => write!(f, "{:?}", p),
GenericKind::Projection(ref p) => write!(f, "{:?}", p),
+ GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
+ write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
+ }),
}
}
}
@@ -757,6 +762,9 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => write!(f, "{}", p),
GenericKind::Projection(ref p) => write!(f, "{}", p),
+ GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
+ write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
+ }),
}
}
}
@@ -766,6 +774,7 @@ impl<'tcx> GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => p.to_ty(tcx),
GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs),
+ GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs),
}
}
}
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 3d99f0958..4db4ff238 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,6 +1,5 @@
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::{FixupError, FixupResult, InferCtxt, Span};
-use rustc_middle::mir;
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor};
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable};
@@ -16,12 +15,12 @@ use std::ops::ControlFlow;
/// useful for printing messages etc but also required at various
/// points for correctness.
pub struct OpportunisticVarResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
#[inline]
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
OpportunisticVarResolver { infcx }
}
}
@@ -32,7 +31,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.has_infer_types_or_consts() {
+ if !t.has_non_region_infer() {
t // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.infcx.shallow_resolve(t);
@@ -41,17 +40,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
}
fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
- if !ct.has_infer_types_or_consts() {
+ if !ct.has_non_region_infer() {
ct // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let ct = self.infcx.shallow_resolve(ct);
ct.super_fold_with(self)
}
}
-
- fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
- constant.super_fold_with(self)
- }
}
/// The opportunistic region resolver opportunistically resolves regions
@@ -62,11 +57,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
/// If you want to resolve type and const variables as well, call
/// [InferCtxt::resolve_vars_if_possible] first.
pub struct OpportunisticRegionResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
OpportunisticRegionResolver { infcx }
}
}
@@ -116,11 +111,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
/// It does not construct the fully resolved type (which might
/// involve some hashing and so forth).
pub struct UnresolvedTypeFinder<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
UnresolvedTypeFinder { infcx }
}
}
@@ -167,7 +162,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
/// 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<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> FixupResult<'tcx, T>
+pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<'tcx, T>
where
T: TypeFoldable<'tcx>,
{
@@ -177,7 +172,7 @@ where
// N.B. This type is not public because the protocol around checking the
// `err` field is not enforceable otherwise.
struct FullTypeResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index b27571275..97354ba5d 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -2,7 +2,6 @@ use super::combine::{CombineFields, RelationDir};
use super::SubregionOrigin;
use crate::infer::combine::ConstEquateRelation;
-use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::traits::Obligation;
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::TypeVisitable;
@@ -11,8 +10,8 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use std::mem;
/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
-pub struct Sub<'combine, 'infcx, 'tcx> {
- fields: &'combine mut CombineFields<'infcx, 'tcx>,
+pub struct Sub<'combine, 'a, 'tcx> {
+ fields: &'combine mut CombineFields<'a, 'tcx>,
a_is_expected: bool,
}
@@ -129,30 +128,37 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
if self.fields.define_opaque_types && did.is_local() =>
{
- let mut generalize = |ty, ty_is_expected| {
- let var = infcx.next_ty_var_id_in_universe(
- TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: self.fields.trace.cause.span,
- },
- ty::UniverseIndex::ROOT,
- );
- self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?;
- Ok(infcx.tcx.mk_ty_var(var))
- };
- let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
- let (a, b) = match (a.kind(), b.kind()) {
- (&ty::Opaque(..), _) => (a, generalize(b, true)?),
- (_, &ty::Opaque(..)) => (generalize(a, false)?, b),
- _ => unreachable!(),
- };
self.fields.obligations.extend(
infcx
- .handle_opaque_type(a, b, true, &self.fields.trace.cause, self.param_env())?
+ .handle_opaque_type(
+ a,
+ b,
+ self.a_is_expected,
+ &self.fields.trace.cause,
+ self.param_env(),
+ )?
.obligations,
);
Ok(a)
}
+ // Optimization of GeneratorWitness relation since we know that all
+ // free regions are replaced with bound regions during construction.
+ // This greatly speeds up subtyping of GeneratorWitness.
+ (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => {
+ let a_types = infcx.tcx.anonymize_bound_vars(a_types);
+ let b_types = infcx.tcx.anonymize_bound_vars(b_types);
+ if a_types.bound_vars() == b_types.bound_vars() {
+ let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders(
+ a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
+ );
+ for (a, b) in std::iter::zip(a_types, b_types) {
+ self.relate(a, b)?;
+ }
+ Ok(a)
+ } else {
+ Err(ty::error::TypeError::Sorts(ty::relate::expected_found(self, a, b)))
+ }
+ }
_ => {
self.fields.infcx.super_combine_tys(self, a, b)?;
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index a0e2965b6..7ff086452 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -122,6 +122,7 @@ pub enum TypeVariableOriginKind {
MiscVariable,
NormalizeProjectionType,
TypeInference,
+ OpaqueTypeInference(DefId),
TypeParameterDefinition(Symbol, Option<DefId>),
/// One of the upvars or closure kind parameters in a `ClosureSubsts`
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 74a26ebc3..611961ab1 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -100,7 +100,7 @@ impl Default for InferCtxtUndoLogs<'_> {
}
/// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any
-/// action that is convertable into an UndoLog (per the From impls above).
+/// action that is convertible into an UndoLog (per the From impls above).
impl<'tcx, T> UndoLogs<T> for InferCtxtUndoLogs<'tcx>
where
UndoLog<'tcx>: From<T>,
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 7769a68ba..e040634ed 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -2,7 +2,7 @@
//!
//! - **Type inference.** The type inference code can be found in the `infer` module;
//! this code handles low-level equality and subtyping operations. The
-//! type check pass in the compiler is found in the `rustc_typeck` crate.
+//! type check pass in the compiler is found in the `rustc_hir_analysis` crate.
//!
//! For more information about how rustc works, see the [rustc dev guide].
//!
@@ -17,9 +17,8 @@
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(extend_one)]
-#![feature(label_break_value)]
#![feature(let_chains)]
-#![feature(let_else)]
+#![feature(if_let_guard)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(try_blocks)]
@@ -35,5 +34,6 @@ extern crate tracing;
#[macro_use]
extern crate rustc_middle;
+mod errors;
pub mod infer;
pub mod traits;
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 736278ba0..b2b985a22 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -10,7 +10,7 @@ use super::{ObligationCause, PredicateObligation};
pub trait TraitEngine<'tcx>: 'tcx {
fn normalize_projection_type(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
@@ -21,7 +21,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
/// parameters (except for `Self`).
fn register_bound(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
@@ -41,14 +41,13 @@ pub trait TraitEngine<'tcx>: 'tcx {
fn register_predicate_obligation(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
);
- fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
- fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
- -> Vec<FulfillmentError<'tcx>>;
+ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
@@ -58,7 +57,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
pub trait TraitEngineExt<'tcx> {
fn register_predicate_obligations(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
);
}
@@ -66,7 +65,7 @@ pub trait TraitEngineExt<'tcx> {
impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
fn register_predicate_obligations(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
) {
for obligation in obligations {
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index 95b6c4ce1..f8b5009a5 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -10,7 +10,7 @@ use rustc_span::Span;
use std::fmt;
use std::iter;
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
pub fn report_extra_impl_obligation(
&self,
error_span: Span,
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 4df4de21a..c8600ded9 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -67,6 +67,14 @@ impl<'tcx> PredicateObligation<'tcx> {
recursion_depth: self.recursion_depth,
})
}
+
+ pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> PredicateObligation<'tcx> {
+ self.param_env = self.param_env.without_const();
+ if let ty::PredicateKind::Trait(trait_pred) = self.predicate.kind().skip_binder() && trait_pred.is_const_if_const() {
+ self.predicate = tcx.mk_predicate(self.predicate.kind().map_bound(|_| ty::PredicateKind::Trait(trait_pred.without_const())));
+ }
+ self
+ }
}
impl<'tcx> TraitObligation<'tcx> {
@@ -105,6 +113,8 @@ pub struct FulfillmentError<'tcx> {
#[derive(Clone)]
pub enum FulfillmentErrorCode<'tcx> {
+ /// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented.
+ CodeCycle(Vec<Obligation<'tcx, ty::Predicate<'tcx>>>),
CodeSelectionError(SelectionError<'tcx>),
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 573d2d1e3..1c6ab6a08 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -47,6 +47,7 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
}
super::CodeAmbiguity => write!(f, "Ambiguity"),
+ super::CodeCycle(ref cycle) => write!(f, "Cycle({:?})", cycle),
}
}
}
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index f5a1edf6d..e12c069dc 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -246,6 +246,13 @@ impl<'tcx> Elaborator<'tcx> {
Component::UnresolvedInferenceVariable(_) => None,
+ Component::Opaque(def_id, substs) => {
+ let ty = tcx.mk_opaque(def_id, substs);
+ Some(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
+ ty, r_min,
+ )))
+ }
+
Component::Projection(projection) => {
// We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
// With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
@@ -262,8 +269,9 @@ impl<'tcx> Elaborator<'tcx> {
None
}
})
- .map(ty::Binder::dummy)
- .map(|predicate_kind| predicate_kind.to_predicate(tcx))
+ .map(|predicate_kind| {
+ bound_predicate.rebind(predicate_kind).to_predicate(tcx)
+ })
.filter(|&predicate| visited.insert(predicate))
.map(|predicate| {
predicate_obligation(