summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:29 +0000
commit631cd5845e8de329d0e227aaa707d7ea228b8f8f (patch)
treea1b87c8f8cad01cf18f7c5f57a08f102771ed303 /compiler/rustc_infer
parentAdding debian version 1.69.0+dfsg1-1. (diff)
downloadrustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.tar.xz
rustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.zip
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_infer')
-rw-r--r--compiler/rustc_infer/messages.ftl (renamed from compiler/rustc_infer/locales/en-US.ftl)51
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs395
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs126
-rw-r--r--compiler/rustc_infer/src/infer/at.rs158
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs77
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs12
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs28
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs104
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs16
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs620
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs23
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs20
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs2
-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.rs9
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs217
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs17
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs18
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs14
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs6
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs53
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs18
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs333
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs326
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs22
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs48
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs107
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs47
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs8
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs7
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs89
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs15
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs17
-rw-r--r--compiler/rustc_infer/src/infer/type_variable.rs5
-rw-r--r--compiler/rustc_infer/src/lib.rs2
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs6
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs22
-rw-r--r--compiler/rustc_infer/src/traits/structural_impls.rs3
-rw-r--r--compiler/rustc_infer/src/traits/util.rs246
41 files changed, 1825 insertions, 1474 deletions
diff --git a/compiler/rustc_infer/locales/en-US.ftl b/compiler/rustc_infer/messages.ftl
index 15780898d..c8998ea91 100644
--- a/compiler/rustc_infer/locales/en-US.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -30,8 +30,8 @@ infer_source_kind_subdiag_let = {$kind ->
}{$x_kind ->
[has_name] , where the {$prefix_kind ->
*[type] type for {$prefix}
- [const_with_param] the value of const parameter
- [const] the value of the constant
+ [const_with_param] value of const parameter
+ [const] value of the constant
} `{$arg_name}` is specified
[underscore] , where the placeholders `_` are specified
*[empty] {""}
@@ -163,7 +163,6 @@ infer_region_explanation = {$pref_kind ->
[as_defined] the lifetime `{$desc_arg}` as defined here
[as_defined_anon] the anonymous lifetime as defined here
[defined_here] the anonymous lifetime defined here
- [anon_num_here] the anonymous lifetime #{$desc_num_arg} defined here
[defined_here_reg] the lifetime `{$desc_arg}` as defined here
}{$suff_kind ->
*[should_not_happen] [{$suff_kind}]
@@ -174,7 +173,7 @@ infer_region_explanation = {$pref_kind ->
infer_outlives_content = lifetime of reference outlives lifetime of borrowed content...
infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
-infer_fullfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
+infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
infer_lf_bound_not_satisfied = lifetime bound not satisfied
infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long
infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references
@@ -348,3 +347,47 @@ infer_prlf_known_limitation = this is a known limitation that will be removed in
infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
.label = opaque type defined here
+
+infer_fps_use_ref = consider using a reference
+infer_fps_remove_ref = consider removing the reference
+infer_fps_cast = consider casting to a fn pointer
+infer_fps_items_are_distinct = fn items are distinct from fn pointers
+infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
+
+infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same
+infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
+
+infer_sarwa_option = you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`
+infer_sarwa_result = you can convert from `&Result<T, E>` to `Result<&T, &E>` using `.as_ref()`
+
+infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}`
+
+infer_sbfrit_change_return_type = you could change the return type to be a boxed trait object
+infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions
+
+infer_stp_wrap_one = try wrapping the pattern in `{$variant}`
+infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}`
+
+infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element
+
+infer_oc_method_compat = method not compatible with trait
+infer_oc_type_compat = type not compatible with trait
+infer_oc_const_compat = const not compatible with trait
+infer_oc_try_compat = `?` operator has incompatible types
+infer_oc_match_compat = `match` arms have incompatible types
+infer_oc_if_else_different = `if` and `else` have incompatible types
+infer_oc_no_else = `if` may be missing an `else` clause
+infer_oc_no_diverge = `else` clause of `let...else` does not diverge
+infer_oc_fn_main_correct_type = `main` function has wrong type
+infer_oc_fn_start_correct_type = `#[start]` function has wrong type
+infer_oc_intristic_correct_type = intrinsic has wrong type
+infer_oc_method_correct_type = mismatched `self` parameter type
+infer_oc_closure_selfref = closure/generator type that references itself
+infer_oc_cant_coerce = cannot coerce intrinsics to function pointers
+infer_oc_generic = mismatched types
+
+infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b`
+infer_meant_char_literal = if you meant to write a `char` literal, use single quotes
+infer_meant_str_literal = if you meant to write a `str` literal, use double quotes
+infer_consider_specifying_length = consider specifying the actual array length
+infer_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}`
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 6bbd3fd3e..65b3dd1a8 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -53,7 +53,7 @@ pub struct AnnotationRequired<'a> {
// Copy of `AnnotationRequired` for E0283
#[derive(Diagnostic)]
#[diag(infer_type_annotations_needed, code = "E0283")]
-pub struct AmbigousImpl<'a> {
+pub struct AmbiguousImpl<'a> {
#[primary_span]
pub span: Span,
pub source_kind: &'static str,
@@ -184,18 +184,6 @@ pub enum SourceKindMultiSuggestion<'a> {
},
}
-#[derive(Subdiagnostic)]
-#[suggestion(
- infer_suggest_add_let_for_letchains,
- style = "verbose",
- applicability = "machine-applicable",
- code = "let "
-)]
-pub(crate) struct SuggAddLetForLetChains {
- #[primary_span]
- pub span: Span,
-}
-
impl<'a> SourceKindMultiSuggestion<'a> {
pub fn new_fully_qualified(
span: Span,
@@ -954,8 +942,8 @@ pub struct OutlivesBound<'a> {
}
#[derive(Diagnostic)]
-#[diag(infer_fullfill_req_lifetime, code = "E0477")]
-pub struct FullfillReqLifetime<'a> {
+#[diag(infer_fulfill_req_lifetime, code = "E0477")]
+pub struct FulfillReqLifetime<'a> {
#[primary_span]
pub span: Span,
pub ty: Ty<'a>,
@@ -1157,3 +1145,380 @@ pub struct OpaqueCapturesLifetime<'tcx> {
pub opaque_ty_span: Span,
pub opaque_ty: Ty<'tcx>,
}
+
+#[derive(Subdiagnostic)]
+pub enum FunctionPointerSuggestion<'a> {
+ #[suggestion(
+ infer_fps_use_ref,
+ code = "&{fn_name}",
+ style = "verbose",
+ applicability = "maybe-incorrect"
+ )]
+ UseRef {
+ #[primary_span]
+ span: Span,
+ #[skip_arg]
+ fn_name: String,
+ },
+ #[suggestion(
+ infer_fps_remove_ref,
+ code = "{fn_name}",
+ style = "verbose",
+ applicability = "maybe-incorrect"
+ )]
+ RemoveRef {
+ #[primary_span]
+ span: Span,
+ #[skip_arg]
+ fn_name: String,
+ },
+ #[suggestion(
+ infer_fps_cast,
+ code = "&({fn_name} as {sig})",
+ style = "verbose",
+ applicability = "maybe-incorrect"
+ )]
+ CastRef {
+ #[primary_span]
+ span: Span,
+ #[skip_arg]
+ fn_name: String,
+ #[skip_arg]
+ sig: Binder<'a, FnSig<'a>>,
+ },
+ #[suggestion(
+ infer_fps_cast,
+ code = "{fn_name} as {sig}",
+ style = "verbose",
+ applicability = "maybe-incorrect"
+ )]
+ Cast {
+ #[primary_span]
+ span: Span,
+ #[skip_arg]
+ fn_name: String,
+ #[skip_arg]
+ sig: Binder<'a, FnSig<'a>>,
+ },
+ #[suggestion(
+ infer_fps_cast_both,
+ code = "{fn_name} as {found_sig}",
+ style = "hidden",
+ applicability = "maybe-incorrect"
+ )]
+ CastBoth {
+ #[primary_span]
+ span: Span,
+ #[skip_arg]
+ fn_name: String,
+ #[skip_arg]
+ found_sig: Binder<'a, FnSig<'a>>,
+ expected_sig: Binder<'a, FnSig<'a>>,
+ },
+ #[suggestion(
+ infer_fps_cast_both,
+ code = "&({fn_name} as {found_sig})",
+ style = "hidden",
+ applicability = "maybe-incorrect"
+ )]
+ CastBothRef {
+ #[primary_span]
+ span: Span,
+ #[skip_arg]
+ fn_name: String,
+ #[skip_arg]
+ found_sig: Binder<'a, FnSig<'a>>,
+ expected_sig: Binder<'a, FnSig<'a>>,
+ },
+}
+
+#[derive(Subdiagnostic)]
+#[note(infer_fps_items_are_distinct)]
+pub struct FnItemsAreDistinct;
+
+#[derive(Subdiagnostic)]
+#[note(infer_fn_uniq_types)]
+pub struct FnUniqTypes;
+
+#[derive(Subdiagnostic)]
+#[help(infer_fn_consider_casting)]
+pub struct FnConsiderCasting {
+ pub casting: String,
+}
+
+#[derive(Subdiagnostic)]
+pub enum SuggestAsRefWhereAppropriate<'a> {
+ #[suggestion(
+ infer_sarwa_option,
+ code = "{snippet}.as_ref()",
+ applicability = "machine-applicable"
+ )]
+ Option {
+ #[primary_span]
+ span: Span,
+ snippet: &'a str,
+ },
+ #[suggestion(
+ infer_sarwa_result,
+ code = "{snippet}.as_ref()",
+ applicability = "machine-applicable"
+ )]
+ Result {
+ #[primary_span]
+ span: Span,
+ snippet: &'a str,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub enum SuggestAccessingField<'a> {
+ #[suggestion(
+ infer_suggest_accessing_field,
+ code = "{snippet}.{name}",
+ applicability = "maybe-incorrect"
+ )]
+ Safe {
+ #[primary_span]
+ span: Span,
+ snippet: String,
+ name: Symbol,
+ ty: Ty<'a>,
+ },
+ #[suggestion(
+ infer_suggest_accessing_field,
+ code = "unsafe {{ {snippet}.{name} }}",
+ applicability = "maybe-incorrect"
+ )]
+ Unsafe {
+ #[primary_span]
+ span: Span,
+ snippet: String,
+ name: Symbol,
+ ty: Ty<'a>,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub enum SuggestBoxingForReturnImplTrait {
+ #[multipart_suggestion(infer_sbfrit_change_return_type, applicability = "maybe-incorrect")]
+ ChangeReturnType {
+ #[suggestion_part(code = "Box<dyn")]
+ start_sp: Span,
+ #[suggestion_part(code = ">")]
+ end_sp: Span,
+ },
+ #[multipart_suggestion(infer_sbfrit_box_return_expr, applicability = "maybe-incorrect")]
+ BoxReturnExpr {
+ #[suggestion_part(code = "Box::new(")]
+ starts: Vec<Span>,
+ #[suggestion_part(code = ")")]
+ ends: Vec<Span>,
+ },
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(infer_stp_wrap_one, applicability = "maybe-incorrect")]
+pub struct SuggestTuplePatternOne {
+ pub variant: String,
+ #[suggestion_part(code = "{variant}(")]
+ pub span_low: Span,
+ #[suggestion_part(code = ")")]
+ pub span_high: Span,
+}
+
+pub struct SuggestTuplePatternMany {
+ pub path: String,
+ pub cause_span: Span,
+ pub compatible_variants: Vec<String>,
+}
+
+impl AddToDiagnostic for SuggestTuplePatternMany {
+ fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, f: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
+ diag.set_arg("path", self.path);
+ let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into());
+ diag.multipart_suggestions(
+ message,
+ self.compatible_variants.into_iter().map(|variant| {
+ vec![
+ (self.cause_span.shrink_to_lo(), format!("{}(", variant)),
+ (self.cause_span.shrink_to_hi(), ")".to_string()),
+ ]
+ }),
+ rustc_errors::Applicability::MaybeIncorrect,
+ );
+ }
+}
+
+#[derive(Subdiagnostic)]
+pub enum TypeErrorAdditionalDiags {
+ #[suggestion(
+ infer_meant_byte_literal,
+ code = "b'{code}'",
+ applicability = "machine-applicable"
+ )]
+ MeantByteLiteral {
+ #[primary_span]
+ span: Span,
+ code: String,
+ },
+ #[suggestion(
+ infer_meant_char_literal,
+ code = "'{code}'",
+ applicability = "machine-applicable"
+ )]
+ MeantCharLiteral {
+ #[primary_span]
+ span: Span,
+ code: String,
+ },
+ #[suggestion(
+ infer_meant_str_literal,
+ code = "\"{code}\"",
+ applicability = "machine-applicable"
+ )]
+ MeantStrLiteral {
+ #[primary_span]
+ span: Span,
+ code: String,
+ },
+ #[suggestion(
+ infer_consider_specifying_length,
+ code = "{length}",
+ applicability = "maybe-incorrect"
+ )]
+ ConsiderSpecifyingLength {
+ #[primary_span]
+ span: Span,
+ length: u64,
+ },
+ #[note(infer_try_cannot_convert)]
+ TryCannotConvert { found: String, expected: String },
+ #[suggestion(infer_tuple_trailing_comma, code = ",", applicability = "machine-applicable")]
+ TupleOnlyComma {
+ #[primary_span]
+ span: Span,
+ },
+ #[multipart_suggestion(infer_tuple_trailing_comma, applicability = "machine-applicable")]
+ TupleAlsoParentheses {
+ #[suggestion_part(code = "(")]
+ span_low: Span,
+ #[suggestion_part(code = ",)")]
+ span_high: Span,
+ },
+ #[suggestion(
+ infer_suggest_add_let_for_letchains,
+ style = "verbose",
+ applicability = "machine-applicable",
+ code = "let "
+ )]
+ AddLetForLetChains {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Diagnostic)]
+pub enum ObligationCauseFailureCode {
+ #[diag(infer_oc_method_compat, code = "E0308")]
+ MethodCompat {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+ #[diag(infer_oc_type_compat, code = "E0308")]
+ TypeCompat {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+ #[diag(infer_oc_const_compat, code = "E0308")]
+ ConstCompat {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+ #[diag(infer_oc_try_compat, code = "E0308")]
+ TryCompat {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+ #[diag(infer_oc_match_compat, code = "E0308")]
+ MatchCompat {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+ #[diag(infer_oc_if_else_different, code = "E0308")]
+ IfElseDifferent {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+ #[diag(infer_oc_no_else, code = "E0317")]
+ NoElse {
+ #[primary_span]
+ span: Span,
+ },
+ #[diag(infer_oc_no_diverge, code = "E0308")]
+ NoDiverge {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+ #[diag(infer_oc_fn_main_correct_type, code = "E0580")]
+ FnMainCorrectType {
+ #[primary_span]
+ span: Span,
+ },
+ #[diag(infer_oc_fn_start_correct_type, code = "E0308")]
+ FnStartCorrectType {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+ #[diag(infer_oc_intristic_correct_type, code = "E0308")]
+ IntristicCorrectType {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+ #[diag(infer_oc_method_correct_type, code = "E0308")]
+ MethodCorrectType {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+ #[diag(infer_oc_closure_selfref, code = "E0644")]
+ ClosureSelfref {
+ #[primary_span]
+ span: Span,
+ },
+ #[diag(infer_oc_cant_coerce, code = "E0308")]
+ CantCoerce {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+ #[diag(infer_oc_generic, code = "E0308")]
+ Generic {
+ #[primary_span]
+ span: Span,
+ #[subdiagnostic]
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ },
+}
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index ef543b1fb..7328241df 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -4,12 +4,10 @@ use rustc_errors::{self, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, Subdiag
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> {
@@ -18,103 +16,74 @@ impl<'a> DescriptionCtx<'a> {
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,
-
- ty::ReError(_) => 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 {
+ let (span, kind, arg) = match *region {
ty::ReEarlyBound(ref br) => {
- let mut sp = tcx.def_span(scope);
- if let Some(param) =
+ let scope = region.free_region_binding_scope(tcx).expect_local();
+ let span = 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();
+ param.span
} else {
- me.kind = "as_defined_anon";
+ tcx.def_span(scope)
};
- me.span = Some(sp)
+ if br.has_name() {
+ (Some(span), "as_defined", br.name.to_string())
+ } else {
+ (Some(span), "as_defined_anon", String::new())
+ }
}
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);
+ (Some(ty.span), "defined_here", String::new())
} else {
+ let scope = region.free_region_binding_scope(tcx).expect_local();
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))
+ let span = 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";
+ param.span
} else {
- me.kind = "as_defined";
- me.arg = name.to_string();
+ tcx.def_span(scope)
};
- me.span = Some(sp);
+ if name == kw::UnderscoreLifetime {
+ (Some(span), "as_defined_anon", String::new())
+ } else {
+ (Some(span), "as_defined", name.to_string())
+ }
}
- ty::BrAnon(idx, span) => {
- me.kind = "anon_num_here";
- me.num_arg = idx+1;
- me.span = match span {
+ ty::BrAnon(span) => {
+ let span = match span {
Some(_) => span,
None => Some(tcx.def_span(scope)),
- }
- },
+ };
+ (span, "defined_here", String::new())
+ }
_ => {
- me.kind = "defined_here_reg";
- me.arg = region.to_string();
- me.span = Some(tcx.def_span(scope));
- },
+ (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string())
+ }
}
}
}
- _ => 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);
+ ty::ReStatic => (alt_span, "restatic", String::new()),
+
+ ty::RePlaceholder(_) | ty::ReError(_) => 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 => {
+ (alt_span, "revar", format!("{:?}", region))
+ }
+ };
+ Some(DescriptionCtx { span, kind, arg })
}
}
@@ -199,10 +168,11 @@ impl AddToDiagnostic for RegionExplanation<'_> {
{
diag.set_arg("pref_kind", self.prefix);
diag.set_arg("suff_kind", self.suffix);
- let desc_span = self.desc.span;
- self.desc.add_to(diag);
+ diag.set_arg("desc_kind", self.desc.kind);
+ diag.set_arg("desc_arg", self.desc.arg);
+
let msg = f(diag, fluent::infer_region_explanation.into());
- if let Some(span) = desc_span {
+ if let Some(span) = self.desc.span {
diag.span_note(span, msg);
} else {
diag.note(msg);
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 7d9bae735..d240d8e49 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -30,16 +30,22 @@ use super::*;
use rustc_middle::ty::relate::{Relate, TypeRelation};
use rustc_middle::ty::{Const, ImplSubject};
+use std::cell::Cell;
+
+/// Whether we should define opaque types or just treat them opaquely.
+///
+/// Currently only used to prevent predicate matching from matching anything
+/// against opaque types.
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum DefineOpaqueTypes {
+ Yes,
+ No,
+}
+
pub struct At<'a, 'tcx> {
pub infcx: &'a InferCtxt<'tcx>,
pub cause: &'a ObligationCause<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
- /// Whether we should define opaque types
- /// or just treat them opaquely.
- /// Currently only used to prevent predicate
- /// matching from matching anything against opaque
- /// types.
- pub define_opaque_types: bool,
}
pub struct Trace<'a, 'tcx> {
@@ -55,7 +61,7 @@ impl<'tcx> InferCtxt<'tcx> {
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> At<'a, 'tcx> {
- At { infcx: self, cause, param_env, define_opaque_types: false }
+ At { infcx: self, cause, param_env }
}
/// Forks the inference context, creating a new inference context with the same inference
@@ -78,13 +84,13 @@ impl<'tcx> InferCtxt<'tcx> {
in_snapshot: self.in_snapshot.clone(),
universe: self.universe.clone(),
intercrate: self.intercrate,
+ inside_canonicalization_ctxt: Cell::new(self.inside_canonicalization_ctxt()),
}
}
}
pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
fn to_trace(
- tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -93,33 +99,21 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
}
impl<'a, 'tcx> At<'a, 'tcx> {
- pub fn define_opaque_types(self, define_opaque_types: bool) -> Self {
- Self { define_opaque_types, ..self }
- }
-
- /// Hacky routine for equating two impl headers in coherence.
- pub fn eq_impl_headers(
- self,
- expected: &ty::ImplHeader<'tcx>,
- actual: &ty::ImplHeader<'tcx>,
- ) -> InferResult<'tcx, ()> {
- debug!("eq_impl_header({:?} = {:?})", expected, actual);
- match (expected.trait_ref, actual.trait_ref) {
- (Some(a_ref), Some(b_ref)) => self.eq(a_ref, b_ref),
- (None, None) => self.eq(expected.self_ty, actual.self_ty),
- _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
- }
- }
-
/// Makes `a <: b`, where `a` may or may not be expected.
///
/// See [`At::trace_exp`] and [`Trace::sub`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn sub_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()>
+ pub fn sub_exp<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ a_is_expected: bool,
+ a: T,
+ b: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
- self.trace_exp(a_is_expected, a, b).sub(a, b)
+ self.trace_exp(a_is_expected, a, b).sub(define_opaque_types, a, b)
}
/// Makes `actual <: expected`. For example, if type-checking a
@@ -129,54 +123,81 @@ impl<'a, 'tcx> At<'a, 'tcx> {
///
/// See [`At::trace`] and [`Trace::sub`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn sup<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
+ pub fn sup<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ actual: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
- self.sub_exp(false, actual, expected)
+ self.sub_exp(define_opaque_types, false, actual, expected)
}
/// Makes `expected <: actual`.
///
/// See [`At::trace`] and [`Trace::sub`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn sub<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
+ pub fn sub<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ actual: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
- self.sub_exp(true, expected, actual)
+ self.sub_exp(define_opaque_types, true, expected, actual)
}
/// Makes `expected <: actual`.
///
/// See [`At::trace_exp`] and [`Trace::eq`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn eq_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()>
+ pub fn eq_exp<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ a_is_expected: bool,
+ a: T,
+ b: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
- self.trace_exp(a_is_expected, a, b).eq(a, b)
+ self.trace_exp(a_is_expected, a, b).eq(define_opaque_types, a, b)
}
/// Makes `expected <: actual`.
///
/// See [`At::trace`] and [`Trace::eq`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn eq<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
+ pub fn eq<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ actual: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
- self.trace(expected, actual).eq(expected, actual)
+ self.trace(expected, actual).eq(define_opaque_types, expected, actual)
}
- pub fn relate<T>(self, expected: T, variance: ty::Variance, actual: T) -> InferResult<'tcx, ()>
+ pub fn relate<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ variance: ty::Variance,
+ actual: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
match variance {
- ty::Variance::Covariant => self.sub(expected, actual),
- ty::Variance::Invariant => self.eq(expected, actual),
- ty::Variance::Contravariant => self.sup(expected, actual),
+ ty::Variance::Covariant => self.sub(define_opaque_types, expected, actual),
+ ty::Variance::Invariant => self.eq(define_opaque_types, expected, actual),
+ ty::Variance::Contravariant => self.sup(define_opaque_types, expected, actual),
// We could make this make sense but it's not readily
// exposed and I don't feel like dealing with it. Note
@@ -195,11 +216,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
///
/// See [`At::trace`] and [`Trace::lub`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T>
+ pub fn lub<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ actual: T,
+ ) -> InferResult<'tcx, T>
where
T: ToTrace<'tcx>,
{
- self.trace(expected, actual).lub(expected, actual)
+ self.trace(expected, actual).lub(define_opaque_types, expected, actual)
}
/// Computes the greatest-lower-bound, or mutual subtype, of two
@@ -208,11 +234,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
///
/// See [`At::trace`] and [`Trace::glb`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn glb<T>(self, expected: T, actual: T) -> InferResult<'tcx, T>
+ pub fn glb<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ actual: T,
+ ) -> InferResult<'tcx, T>
where
T: ToTrace<'tcx>,
{
- self.trace(expected, actual).glb(expected, actual)
+ self.trace(expected, actual).glb(define_opaque_types, expected, actual)
}
/// Sets the "trace" values that will be used for
@@ -233,7 +264,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
where
T: ToTrace<'tcx>,
{
- let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b);
+ let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
Trace { at: self, trace, a_is_expected }
}
}
@@ -242,13 +273,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
/// Makes `a <: b` where `a` may or may not be expected (if
/// `a_is_expected` is true, then `a` is expected).
#[instrument(skip(self), level = "debug")]
- pub fn sub<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
+ pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.sub(a_is_expected)
.relate(a, b)
@@ -259,13 +290,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
/// Makes `a == b`; the expectation is set by the call to
/// `trace()`.
#[instrument(skip(self), level = "debug")]
- pub fn eq<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
+ pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.equate(a_is_expected)
.relate(a, b)
@@ -274,13 +305,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
}
#[instrument(skip(self), level = "debug")]
- pub fn lub<T>(self, a: T, b: T) -> InferResult<'tcx, T>
+ pub fn lub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.lub(a_is_expected)
.relate(a, b)
@@ -289,13 +320,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
}
#[instrument(skip(self), level = "debug")]
- pub fn glb<T>(self, a: T, b: T) -> InferResult<'tcx, T>
+ pub fn glb<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.glb(a_is_expected)
.relate(a, b)
@@ -306,7 +337,6 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
fn to_trace(
- tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -314,10 +344,10 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
) -> TypeTrace<'tcx> {
match (a, b) {
(ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
- ToTrace::to_trace(tcx, cause, a_is_expected, trait_ref_a, trait_ref_b)
+ ToTrace::to_trace(cause, a_is_expected, trait_ref_a, trait_ref_b)
}
(ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
- ToTrace::to_trace(tcx, cause, a_is_expected, ty_a, ty_b)
+ ToTrace::to_trace(cause, a_is_expected, ty_a, ty_b)
}
(ImplSubject::Trait(_), ImplSubject::Inherent(_))
| (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
@@ -329,7 +359,6 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -344,7 +373,6 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -356,7 +384,6 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -371,7 +398,6 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -399,7 +425,6 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -411,7 +436,6 @@ impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -426,7 +450,6 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -441,24 +464,17 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
fn to_trace(
- tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
- let a_ty = tcx.mk_projection(a.def_id, a.substs);
- let b_ty = tcx.mk_projection(b.def_id, b.substs);
- TypeTrace {
- cause: cause.clone(),
- values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())),
- }
+ TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) }
}
}
impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 678c4a0be..e808911a3 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -230,9 +230,9 @@ impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
match *r {
- ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic => r,
+ ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic | ty::ReError(_) => r,
ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
- _ => {
+ ty::RePlaceholder(..) | ty::ReLateBound(..) => {
// We only expect region names that the user can type.
bug!("unexpected region in query response: `{:?}`", r)
}
@@ -352,19 +352,17 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
ty::ReVar(vid) => {
- let resolved_vid = self
+ let resolved = self
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
- .opportunistic_resolve_var(vid);
+ .opportunistic_resolve_var(self.tcx, vid);
debug!(
- "canonical: region var found with vid {:?}, \
- opportunistically resolved to {:?}",
- vid, resolved_vid
+ "canonical: region var found with vid {vid:?}, \
+ opportunistically resolved to {resolved:?}",
);
- let r = self.tcx.mk_re_var(resolved_vid);
- self.canonicalize_mode.canonicalize_free_region(self, r)
+ self.canonicalize_mode.canonicalize_free_region(self, resolved)
}
ty::ReStatic
@@ -376,9 +374,18 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
- ty::Infer(ty::TyVar(vid)) => {
+ ty::Infer(ty::TyVar(mut vid)) => {
+ // We need to canonicalize the *root* of our ty var.
+ // This is so that our canonical response correctly reflects
+ // any equated inference vars correctly!
+ let root_vid = self.infcx.root_var(vid);
+ if root_vid != vid {
+ t = self.infcx.tcx.mk_ty_var(root_vid);
+ vid = root_vid;
+ }
+
debug!("canonical: type var found with vid {:?}", vid);
match self.infcx.probe_ty_var(vid) {
// `t` could be a float / int variable; canonicalize that instead.
@@ -404,15 +411,28 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
}
- ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(
- CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
- t,
- ),
-
- ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(
- CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
- t,
- ),
+ ty::Infer(ty::IntVar(vid)) => {
+ let nt = self.infcx.opportunistic_resolve_int_var(vid);
+ if nt != t {
+ return self.fold_ty(nt);
+ } else {
+ self.canonicalize_ty_var(
+ CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
+ t,
+ )
+ }
+ }
+ ty::Infer(ty::FloatVar(vid)) => {
+ let nt = self.infcx.opportunistic_resolve_float_var(vid);
+ if nt != t {
+ return self.fold_ty(nt);
+ } else {
+ self.canonicalize_ty_var(
+ CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
+ t,
+ )
+ }
+ }
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("encountered a fresh type during canonicalization")
@@ -469,9 +489,18 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
}
- fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ fn fold_const(&mut self, mut ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
match ct.kind() {
- ty::ConstKind::Infer(InferConst::Var(vid)) => {
+ ty::ConstKind::Infer(InferConst::Var(mut vid)) => {
+ // We need to canonicalize the *root* of our const var.
+ // This is so that our canonical response correctly reflects
+ // any equated inference vars correctly!
+ let root_vid = self.infcx.root_const_var(vid);
+ if root_vid != vid {
+ ct = self.infcx.tcx.mk_const(ty::InferConst::Var(root_vid), ct.ty());
+ vid = root_vid;
+ }
+
debug!("canonical: const var found with vid {:?}", vid);
match self.infcx.probe_const_var(vid) {
Ok(c) => {
@@ -532,6 +561,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
where
V: TypeFoldable<TyCtxt<'tcx>>,
{
+ let _inside_canonical_ctxt_guard = infcx.set_canonicalization_ctxt();
+
let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::NEEDS_INFER |
TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
@@ -741,7 +772,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
let var = self.canonical_var(info, r.into());
- let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32(), None) };
+ let br = ty::BoundRegion { var, kind: ty::BrAnon(None) };
self.interner().mk_re_late_bound(self.binder_index, br)
}
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index ce230afda..fbb2257bf 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -125,9 +125,9 @@ impl<'tcx> InferCtxt<'tcx> {
ty.into()
}
- CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, name }) => {
+ CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound }) => {
let universe_mapped = universe_map(universe);
- let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, name };
+ let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, bound };
self.tcx.mk_placeholder(placeholder_mapped).into()
}
@@ -138,9 +138,9 @@ impl<'tcx> InferCtxt<'tcx> {
)
.into(),
- CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, name }) => {
+ CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, bound }) => {
let universe_mapped = universe_map(universe);
- let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, name };
+ let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, bound };
self.tcx.mk_re_placeholder(placeholder_mapped).into()
}
@@ -152,9 +152,9 @@ impl<'tcx> InferCtxt<'tcx> {
)
.into(),
- CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, name }, ty) => {
+ CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }, ty) => {
let universe_mapped = universe_map(universe);
- let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name };
+ let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound };
self.tcx.mk_const(placeholder_mapped, ty).into()
}
}
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 436d29c24..e98f68ae5 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -14,7 +14,7 @@ use crate::infer::canonical::{
};
use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
-use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
+use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
use crate::traits::query::{Fallible, NoSolution};
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt};
@@ -159,9 +159,7 @@ impl<'tcx> InferCtxt<'tcx> {
.opaque_type_storage
.opaque_types
.iter()
- .map(|&(k, ref v)| {
- (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)
- })
+ .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty))
.collect()
}
@@ -510,7 +508,7 @@ impl<'tcx> InferCtxt<'tcx> {
let b = substitute_value(self.tcx, &result_subst, b);
debug!(?a, ?b, "constrain opaque type");
obligations
- .extend(self.at(cause, param_env).define_opaque_types(true).eq(a, b)?.obligations);
+ .extend(self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, a, b)?.obligations);
}
Ok(InferOk { value: result_subst, obligations })
@@ -603,8 +601,11 @@ impl<'tcx> InferCtxt<'tcx> {
match (value1.unpack(), value2.unpack()) {
(GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
- obligations
- .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
+ obligations.extend(
+ self.at(cause, param_env)
+ .eq(DefineOpaqueTypes::Yes, v1, v2)?
+ .into_obligations(),
+ );
}
(GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
if re1.is_erased() && re2.is_erased() =>
@@ -612,11 +613,14 @@ impl<'tcx> InferCtxt<'tcx> {
// no action needed
}
(GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => {
- obligations
- .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
+ obligations.extend(
+ self.at(cause, param_env)
+ .eq(DefineOpaqueTypes::Yes, v1, v2)?
+ .into_obligations(),
+ );
}
(GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
- let ok = self.at(cause, param_env).eq(v1, v2)?;
+ let ok = self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, v1, v2)?;
obligations.extend(ok.into_obligations());
}
_ => {
@@ -636,11 +640,9 @@ pub fn make_query_region_constraints<'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 } =
- region_constraints;
+ let RegionConstraintData { constraints, verifys, member_constraints } = region_constraints;
assert!(verifys.is_empty());
- assert!(givens.is_empty());
debug!(?constraints);
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 33292e871..fe45b5ebe 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -27,14 +27,13 @@ use super::glb::Glb;
use super::lub::Lub;
use super::sub::Sub;
use super::type_variable::TypeVariableValue;
-use super::{InferCtxt, MiscVariable, TypeTrace};
+use super::{DefineOpaqueTypes, InferCtxt, MiscVariable, TypeTrace};
use crate::traits::{Obligation, PredicateObligations};
use rustc_data_structures::sso::SsoHashMap;
use rustc_hir::def_id::DefId;
use rustc_middle::infer::canonical::OriginalQueryValues;
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
@@ -53,12 +52,7 @@ pub struct CombineFields<'infcx, 'tcx> {
pub cause: Option<ty::relate::Cause>,
pub param_env: ty::ParamEnv<'tcx>,
pub obligations: PredicateObligations<'tcx>,
- /// Whether we should define opaque types
- /// or just treat them opaquely.
- /// Currently only used to prevent predicate
- /// matching from matching anything against opaque
- /// types.
- pub define_opaque_types: bool,
+ pub define_opaque_types: DefineOpaqueTypes,
}
#[derive(Copy, Clone, Debug)]
@@ -119,17 +113,39 @@ impl<'tcx> InferCtxt<'tcx> {
self.unify_float_variable(!a_is_expected, v_id, v)
}
+ // We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
+ (
+ ty::Alias(AliasKind::Projection, _),
+ ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)),
+ )
+ | (
+ ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)),
+ ty::Alias(AliasKind::Projection, _),
+ ) if self.tcx.trait_solver_next() => {
+ bug!()
+ }
+
+ (_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
+ if self.tcx.trait_solver_next() =>
+ {
+ relation.register_type_relate_obligation(a, b);
+ Ok(a)
+ }
+
// All other cases of inference are errors
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b)))
}
- (ty::Alias(AliasKind::Projection, _), _) if self.tcx.trait_solver_next() => {
- relation.register_type_equate_obligation(a, b);
- Ok(b)
- }
- (_, ty::Alias(AliasKind::Projection, _)) if self.tcx.trait_solver_next() => {
- relation.register_type_equate_obligation(b, a);
+ // During coherence, opaque types should be treated as *possibly*
+ // equal to each other, even if their generic params differ, as
+ // they could resolve to the same hidden type, even for different
+ // generic params.
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+ ) if self.intercrate && a_def_id == b_def_id => {
+ relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
Ok(a)
}
@@ -161,9 +177,9 @@ impl<'tcx> InferCtxt<'tcx> {
//
// This probe is probably not strictly necessary but it seems better to be safe and not accidentally find
// ourselves with a check to find bugs being required for code to compile because it made inference progress.
- self.probe(|_| {
+ let compatible_types = self.probe(|_| {
if a.ty() == b.ty() {
- return;
+ return Ok(());
}
// We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the
@@ -173,15 +189,33 @@ impl<'tcx> InferCtxt<'tcx> {
(relation.param_env(), a.ty(), b.ty()),
&mut OriginalQueryValues::default(),
);
-
- if let Err(NoSolution) = self.tcx.check_tys_might_be_eq(canonical) {
+ self.tcx.check_tys_might_be_eq(canonical).map_err(|_| {
self.tcx.sess.delay_span_bug(
DUMMY_SP,
&format!("cannot relate consts of different types (a={:?}, b={:?})", a, b,),
- );
- }
+ )
+ })
});
+ // If the consts have differing types, just bail with a const error with
+ // the expected const's type. Specifically, we don't want const infer vars
+ // to do any type shapeshifting before and after resolution.
+ if let Err(guar) = compatible_types {
+ // HACK: equating both sides with `[const error]` eagerly prevents us
+ // from leaving unconstrained inference vars during things like impl
+ // matching in the solver.
+ let a_error = self.tcx.const_error_with_guaranteed(a.ty(), guar);
+ if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() {
+ return self.unify_const_variable(vid, a_error);
+ }
+ let b_error = self.tcx.const_error_with_guaranteed(b.ty(), guar);
+ if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() {
+ return self.unify_const_variable(vid, b_error);
+ }
+
+ return Ok(if relation.a_is_expected() { a_error } else { b_error });
+ }
+
match (a.kind(), b.kind()) {
(
ty::ConstKind::Infer(InferConst::Var(a_vid)),
@@ -483,10 +517,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, to_pred)
}))
}
-
- pub fn mark_ambiguous(&mut self) {
- self.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
- }
}
struct Generalizer<'cx, 'tcx> {
@@ -559,10 +589,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
self.infcx.tcx
}
- fn intercrate(&self) -> bool {
- self.infcx.intercrate
- }
-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
@@ -575,10 +601,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
true
}
- fn mark_ambiguous(&mut self) {
- span_bug!(self.cause.span, "opaque types are handled in `tys`");
- }
-
fn binders<T>(
&mut self,
a: ty::Binder<'tcx, T>,
@@ -820,23 +842,25 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() {
- ty::PredicateKind::AliasEq(a.into(), b.into())
+ ty::PredicateKind::AliasRelate(a.into(), b.into(), ty::AliasRelationDirection::Equate)
} else {
ty::PredicateKind::ConstEquate(a, b)
})]);
}
- /// Register an obligation that both types must be equal to each other.
- ///
- /// If they aren't equal then the relation doesn't hold.
- fn register_type_equate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
- let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
-
- self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasEq(
+ /// Register an obligation that both types must be related to each other according to
+ /// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`]
+ fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+ self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
a.into(),
b.into(),
+ self.alias_relate_direction(),
))]);
}
+
+ /// Relation direction emitted for `AliasRelate` predicates, corresponding to the direction
+ /// of the relation.
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection;
}
fn int_unification_error<'tcx>(
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 54a62326e..fe4a2dd38 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -1,3 +1,4 @@
+use crate::infer::DefineOpaqueTypes;
use crate::traits::PredicateObligations;
use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir};
@@ -34,10 +35,6 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
self.fields.tcx()
}
- fn intercrate(&self) -> bool {
- self.fields.infcx.intercrate
- }
-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.fields.param_env
}
@@ -46,10 +43,6 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
self.a_is_expected
}
- fn mark_ambiguous(&mut self) {
- self.fields.mark_ambiguous();
- }
-
fn relate_item_substs(
&mut self,
_item_def_id: DefId,
@@ -110,7 +103,8 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
}
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
- if self.fields.define_opaque_types && def_id.is_local() =>
+ if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
+ && def_id.is_local() =>
{
self.fields.obligations.extend(
infcx
@@ -208,4 +202,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.fields.register_obligations(obligations);
}
+
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+ ty::AliasRelationDirection::Equate
+ }
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 8a2b800af..9e5f6d107 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -49,11 +49,10 @@ use super::lexical_region_resolve::RegionResolutionError;
use super::region_constraints::GenericKind;
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
-use crate::errors;
+use crate::errors::{self, ObligationCauseFailureCode, TypeErrorAdditionalDiags};
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,
PredicateObligation,
@@ -75,6 +74,7 @@ use rustc_middle::ty::{
self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt,
};
+use rustc_span::DUMMY_SP;
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
use std::ops::{ControlFlow, Deref};
@@ -90,9 +90,35 @@ pub use need_type_info::TypeAnnotationNeeded;
pub mod nice_region_error;
+/// Makes a valid string literal from a string by escaping special characters (" and \),
+/// unless they are already escaped.
+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
+}
+
/// 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`.
+/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`.
+///
+/// You must only create this if you intend to actually emit an error.
+/// This provides a lot of utility methods which should not be used
+/// during the happy path.
pub struct TypeErrCtxt<'a, 'tcx> {
pub infcx: &'a InferCtxt<'tcx>,
pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
@@ -104,6 +130,19 @@ pub struct TypeErrCtxt<'a, 'tcx> {
Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
}
+impl Drop for TypeErrCtxt<'_, '_> {
+ fn drop(&mut self) {
+ if let Some(_) = self.infcx.tcx.sess.has_errors_or_delayed_span_bugs() {
+ // ok, emitted an error.
+ } else {
+ self.infcx
+ .tcx
+ .sess
+ .delay_span_bug(DUMMY_SP, "used a `TypeErrCtxt` without failing compilation");
+ }
+ }
+}
+
impl TypeErrCtxt<'_, '_> {
/// This is just to avoid a potential footgun of accidentally
/// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
@@ -164,83 +203,73 @@ fn msg_span_from_named_region<'tcx>(
alt_span: Option<Span>,
) -> (String, Option<Span>) {
match *region {
- ty::ReEarlyBound(_) | ty::ReFree(_) => {
- let (msg, span) = msg_span_from_early_bound_and_free_regions(tcx, region);
- (msg, Some(span))
- }
- ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
- ty::RePlaceholder(ty::PlaceholderRegion {
- name: ty::BoundRegionKind::BrNamed(def_id, name),
- ..
- }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))),
- ty::RePlaceholder(ty::PlaceholderRegion {
- name: ty::BoundRegionKind::BrAnon(_, Some(span)),
- ..
- }) => (format!("the anonymous lifetime defined here"), Some(span)),
- ty::RePlaceholder(ty::PlaceholderRegion {
- name: ty::BoundRegionKind::BrAnon(_, None),
- ..
- }) => (format!("an anonymous lifetime"), None),
- _ => bug!("{:?}", region),
- }
-}
-
-fn msg_span_from_early_bound_and_free_regions<'tcx>(
- tcx: TyCtxt<'tcx>,
- region: ty::Region<'tcx>,
-) -> (String, Span) {
- 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) =
+ let scope = region.free_region_binding_scope(tcx).expect_local();
+ let span = if let Some(param) =
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
{
- sp = param.span;
- }
+ param.span
+ } else {
+ tcx.def_span(scope)
+ };
let text = if br.has_name() {
format!("the lifetime `{}` as defined here", br.name)
} else {
"the anonymous lifetime as defined here".to_string()
};
- (text, sp)
+ (text, Some(span))
}
ty::ReFree(ref fr) => {
if !fr.bound_region.is_named()
&& let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
{
- ("the anonymous lifetime defined here".to_string(), ty.span)
+ ("the anonymous lifetime defined here".to_string(), Some(ty.span))
} else {
+ let scope = region.free_region_binding_scope(tcx).expect_local();
match fr.bound_region {
ty::BoundRegionKind::BrNamed(_, name) => {
- let mut sp = tcx.def_span(scope);
- if let Some(param) =
+ let span = if let Some(param) =
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
{
- sp = param.span;
- }
+ param.span
+ } else {
+ tcx.def_span(scope)
+ };
let text = if name == kw::UnderscoreLifetime {
"the anonymous lifetime as defined here".to_string()
} else {
format!("the lifetime `{}` as defined here", name)
};
- (text, sp)
+ (text, Some(span))
}
- ty::BrAnon(idx, span) => (
- format!("the anonymous lifetime #{} defined here", idx + 1),
- match span {
+ ty::BrAnon(span) => (
+ "the anonymous lifetime as defined here".to_string(),
+ Some(match span {
Some(span) => span,
None => tcx.def_span(scope)
- }
+ })
),
_ => (
format!("the lifetime `{}` as defined here", region),
- tcx.def_span(scope),
+ Some(tcx.def_span(scope)),
),
}
}
}
- _ => bug!(),
+ ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
+ ty::RePlaceholder(ty::PlaceholderRegion {
+ bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, name), .. },
+ ..
+ }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))),
+ ty::RePlaceholder(ty::PlaceholderRegion {
+ bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon(Some(span)), .. },
+ ..
+ }) => (format!("the anonymous lifetime defined here"), Some(span)),
+ ty::RePlaceholder(ty::PlaceholderRegion {
+ bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon(None), .. },
+ ..
+ }) => (format!("an anonymous lifetime"), None),
+ _ => bug!("{:?}", region),
}
}
@@ -359,10 +388,12 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
let (def_id, substs) = match *ty.kind() {
ty::Alias(_, ty::AliasTy { def_id, substs, .. })
- if matches!(
- self.tcx.def_kind(def_id),
- DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
- ) =>
+ if matches!(self.tcx.def_kind(def_id), DefKind::OpaqueTy) =>
+ {
+ (def_id, substs)
+ }
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ if self.tcx.is_impl_trait_in_trait(def_id) =>
{
(def_id, substs)
}
@@ -396,7 +427,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&self,
generic_param_scope: LocalDefId,
errors: &[RegionResolutionError<'tcx>],
- ) {
+ ) -> ErrorGuaranteed {
+ if let Some(guaranteed) = self.infcx.tainted_by_errors() {
+ return guaranteed;
+ }
+
debug!("report_region_errors(): {} errors to start", errors.len());
// try to pre-process the errors, which will group some of them
@@ -476,6 +511,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
}
+
+ self.tcx
+ .sess
+ .delay_span_bug(self.tcx.def_span(generic_param_scope), "expected region errors")
}
// This method goes through all the errors and try to group certain types
@@ -613,9 +652,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
let report_path_match = |err: &mut Diagnostic, did1: DefId, did2: DefId| {
- // Only external crates, if either is from a local
- // module we could have false positives
- if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
+ // Only report definitions from different crates. If both definitions
+ // are from a local module we could have false positives, e.g.
+ // let _ = [{struct Foo; Foo}, {struct Foo; Foo}];
+ if did1.krate != did2.krate {
let abs_path =
|def_id| AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]);
@@ -627,10 +667,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
if same_path().unwrap_or(false) {
let crate_name = self.tcx.crate_name(did1.krate);
- err.note(&format!(
- "perhaps two different versions of crate `{}` are being used?",
- crate_name
- ));
+ let msg = if did1.is_local() || did2.is_local() {
+ format!(
+ "the crate `{crate_name}` is compiled multiple times, possibly with different configurations"
+ )
+ } else {
+ format!(
+ "perhaps two different versions of crate `{crate_name}` are being used?"
+ )
+ };
+ err.note(msg);
}
}
};
@@ -969,7 +1015,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let (_, sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS)
.name_all_regions(sig)
.unwrap();
- let lts: Vec<String> = reg.into_iter().map(|(_, kind)| kind.to_string()).collect();
+ let lts: Vec<String> = reg.into_values().map(|kind| kind.to_string()).collect();
(if lts.is_empty() { String::new() } else { format!("for<{}> ", lts.join(", ")) }, sig)
};
@@ -1568,6 +1614,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
(false, Mismatch::Fixed("trait"))
}
+ ValuePairs::Aliases(infer::ExpectedFound { expected, .. }) => {
+ (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id)))
+ }
ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
};
let Some(vals) = self.values_str(values) else {
@@ -1754,8 +1803,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
)
}
(true, ty::Alias(ty::Projection, proj))
- if self.tcx.def_kind(proj.def_id)
- == DefKind::ImplTraitPlaceholder =>
+ if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
{
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
@@ -1797,7 +1845,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// will try to hide in some case such as `async fn`, so
// to make an error more use friendly we will
// avoid to suggest a mismatch type with a
- // type that the user usually are not usign
+ // type that the user usually are not using
// directly such as `impl Future<Output = u8>`.
if !self.tcx.ty_is_opaque_future(found_ty) {
diag.note_expected_found_extra(
@@ -1888,232 +1936,182 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
debug!(?diag);
}
- pub fn report_and_explain_type_error(
+ pub fn type_error_additional_suggestions(
&self,
- trace: TypeTrace<'tcx>,
+ trace: &TypeTrace<'tcx>,
terr: TypeError<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ ) -> Vec<TypeErrorAdditionalDiags> {
use crate::traits::ObligationCauseCode::MatchExpressionArm;
-
- debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
-
+ let mut suggestions = Vec::new();
let span = trace.cause.span();
- let failure_code = trace.cause.as_failure_code(terr);
- let mut diag = match failure_code {
- FailureCode::Error0038(did) => {
- let violations = self.tcx.object_safety_violations(did);
- report_object_safety_error(self.tcx, span, did, violations)
- }
- FailureCode::Error0317(failure_str) => {
- struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
- }
- FailureCode::Error0580(failure_str) => {
- 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),
- };
+ let values = self.resolve_vars_if_possible(trace.values);
+ if let Some((expected, found)) = values.ty() {
+ match (expected.kind(), found.kind()) {
+ (ty::Tuple(_), ty::Tuple(_)) => {}
+ // If a tuple of length one was expected and the found expression has
+ // parentheses around it, perhaps the user meant to write `(expr,)` to
+ // build a tuple (issue #86100)
+ (ty::Tuple(fields), _) => {
+ suggestions.extend(self.suggest_wrap_to_build_a_tuple( span, found, fields))
+ }
+ // If a byte was expected and the found expression is a char literal
+ // containing a single ASCII character, perhaps the user meant to write `b'c'` to
+ // specify a byte literal
+ (ty::Uint(ty::UintTy::U8), ty::Char) => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+ && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+ && !code.starts_with("\\u") // forbid all Unicode escapes
+ && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
+ {
+ suggestions.push(TypeErrorAdditionalDiags::MeantByteLiteral { span, code: escape_literal(code) })
}
- 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()) {
- (ty::Tuple(_), ty::Tuple(_)) => {}
- // If a tuple of length one was expected and the found expression has
- // parentheses around it, perhaps the user meant to write `(expr,)` to
- // build a tuple (issue #86100)
- (ty::Tuple(fields), _) => {
- self.emit_tuple_wrap_err(&mut err, span, found, fields)
- }
- // If a byte was expected and the found expression is a char literal
- // containing a single ASCII character, perhaps the user meant to write `b'c'` to
- // specify a byte literal
- (ty::Uint(ty::UintTy::U8), ty::Char) => {
- if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
- && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
- && !code.starts_with("\\u") // forbid all Unicode escapes
- && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
- {
- err.span_suggestion(
- span,
- "if you meant to write a byte literal, prefix with `b`",
- format!("b'{}'", escape_literal(code)),
- Applicability::MachineApplicable,
- );
- }
- }
- // If a character was expected and the found expression is a string literal
- // containing a single character, perhaps the user meant to write `'c'` to
- // specify a character literal (issue #92479)
- (ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
- if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
- && let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
- && code.chars().count() == 1
- {
- err.span_suggestion(
- span,
- "if you meant to write a `char` literal, use single quotes",
- format!("'{}'", escape_literal(code)),
- Applicability::MachineApplicable,
- );
- }
- }
- // If a string was expected and the found expression is a character literal,
- // perhaps the user meant to write `"s"` to specify a string literal.
- (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
- if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
- if let Some(code) =
- code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
- {
- err.span_suggestion(
- span,
- "if you meant to write a `str` literal, use double quotes",
- format!("\"{}\"", escape_literal(code)),
- Applicability::MachineApplicable,
- );
- }
- }
- }
- // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
- // we try to suggest to add the missing `let` for `if let Some(..) = expr`
- (ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
- self.suggest_let_for_letchains(&mut err, &trace.cause, span);
- }
- (ty::Array(_, _), ty::Array(_, _)) => 'block: {
- let hir = self.tcx.hir();
- let TypeError::FixedArraySize(sz) = terr else {
- break 'block;
- };
- let tykind = match hir.find_by_def_id(trace.cause.body_id) {
- Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(_, _, body_id),
- ..
- })) => {
- let body = hir.body(*body_id);
- struct LetVisitor<'v> {
- span: Span,
- result: Option<&'v hir::Ty<'v>>,
- }
- impl<'v> Visitor<'v> for LetVisitor<'v> {
- fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
- if self.result.is_some() {
- return;
- }
- // Find a local statement where the initializer has
- // the same span as the error and the type is specified.
- if let hir::Stmt {
- kind: hir::StmtKind::Local(hir::Local {
- init: Some(hir::Expr {
- span: init_span,
- ..
- }),
- ty: Some(array_ty),
- ..
- }),
- ..
- } = s
- && init_span == &self.span {
- self.result = Some(*array_ty);
- }
- }
- }
- let mut visitor = LetVisitor {span, result: None};
- visitor.visit_body(body);
- visitor.result.map(|r| &r.peel_refs().kind)
- }
- Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Const(ty, _),
- ..
- })) => {
- Some(&ty.peel_refs().kind)
- }
- _ => None
- };
-
- if let Some(tykind) = tykind
- && let hir::TyKind::Array(_, length) = tykind
- && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
- && let Some(span) = self.tcx.hir().opt_span(*hir_id)
- {
- err.span_suggestion(
- span,
- "consider specifying the actual array length",
- sz.found,
- Applicability::MaybeIncorrect,
- );
- }
+ // If a character was expected and the found expression is a string literal
+ // containing a single character, perhaps the user meant to write `'c'` to
+ // specify a character literal (issue #92479)
+ (ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+ && let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
+ && code.chars().count() == 1
+ {
+ suggestions.push(TypeErrorAdditionalDiags::MeantCharLiteral { span, code: escape_literal(code) })
+ }
+ }
+ // If a string was expected and the found expression is a character literal,
+ // perhaps the user meant to write `"s"` to specify a string literal.
+ (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
+ if let Some(code) =
+ code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+ {
+ suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { span, code: escape_literal(code) })
}
- _ => {}
}
}
- let code = trace.cause.code();
- if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
+ // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
+ // we try to suggest to add the missing `let` for `if let Some(..) = expr`
+ (ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
+ suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
+ }
+ (ty::Array(_, _), ty::Array(_, _)) => suggestions.extend(self.suggest_specify_actual_length(terr, trace, span)),
+ _ => {}
+ }
+ }
+ let code = trace.cause.code();
+ if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
&& let hir::MatchSource::TryDesugar = source
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
{
- err.note(&format!(
- "`?` operator cannot convert from `{}` to `{}`",
- found_ty.content(),
- expected_ty.content(),
- ));
+ suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert { found: found_ty.content(), expected: expected_ty.content() });
}
- err
+ suggestions
+ }
+
+ fn suggest_specify_actual_length(
+ &self,
+ terr: TypeError<'_>,
+ trace: &TypeTrace<'_>,
+ span: Span,
+ ) -> Option<TypeErrorAdditionalDiags> {
+ let hir = self.tcx.hir();
+ let TypeError::FixedArraySize(sz) = terr else {
+ return None;
+ };
+ let tykind = match hir.find_by_def_id(trace.cause.body_id) {
+ Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => {
+ let body = hir.body(*body_id);
+ struct LetVisitor<'v> {
+ span: Span,
+ result: Option<&'v hir::Ty<'v>>,
+ }
+ impl<'v> Visitor<'v> for LetVisitor<'v> {
+ fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
+ if self.result.is_some() {
+ return;
+ }
+ // Find a local statement where the initializer has
+ // the same span as the error and the type is specified.
+ if let hir::Stmt {
+ kind: hir::StmtKind::Local(hir::Local {
+ init: Some(hir::Expr {
+ span: init_span,
+ ..
+ }),
+ ty: Some(array_ty),
+ ..
+ }),
+ ..
+ } = s
+ && init_span == &self.span {
+ self.result = Some(*array_ty);
+ }
+ }
+ }
+ let mut visitor = LetVisitor { span, result: None };
+ visitor.visit_body(body);
+ visitor.result.map(|r| &r.peel_refs().kind)
}
- FailureCode::Error0644(failure_str) => {
- struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
+ Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. })) => {
+ Some(&ty.peel_refs().kind)
}
+ _ => None,
};
+ if let Some(tykind) = tykind
+ && let hir::TyKind::Array(_, length) = tykind
+ && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
+ && let Some(span) = self.tcx.hir().opt_span(*hir_id)
+ {
+ Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found })
+ } else {
+ None
+ }
+ }
+
+ pub fn report_and_explain_type_error(
+ &self,
+ trace: TypeTrace<'tcx>,
+ terr: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
+
+ let span = trace.cause.span();
+ let failure_code = trace.cause.as_failure_code_diag(
+ terr,
+ span,
+ self.type_error_additional_suggestions(&trace, terr),
+ );
+ let mut diag = self.tcx.sess.create_err(failure_code);
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false);
diag
}
- fn emit_tuple_wrap_err(
+ fn suggest_wrap_to_build_a_tuple(
&self,
- err: &mut Diagnostic,
span: Span,
found: Ty<'tcx>,
expected_fields: &List<Ty<'tcx>>,
- ) {
- let [expected_tup_elem] = expected_fields[..] else { return };
+ ) -> Option<TypeErrorAdditionalDiags> {
+ let [expected_tup_elem] = expected_fields[..] else { return None};
if !self.same_type_modulo_infer(expected_tup_elem, found) {
- return;
+ return None;
}
let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
- else { return };
+ else { return None };
- let msg = "use a trailing comma to create a tuple with one element";
- if code.starts_with('(') && code.ends_with(')') {
+ let sugg = if code.starts_with('(') && code.ends_with(')') {
let before_close = span.hi() - BytePos::from_u32(1);
- err.span_suggestion(
- span.with_hi(before_close).shrink_to_hi(),
- msg,
- ",",
- Applicability::MachineApplicable,
- );
+ TypeErrorAdditionalDiags::TupleOnlyComma {
+ span: span.with_hi(before_close).shrink_to_hi(),
+ }
} else {
- err.multipart_suggestion(
- msg,
- vec![(span.shrink_to_lo(), "(".into()), (span.shrink_to_hi(), ",)".into())],
- Applicability::MachineApplicable,
- );
- }
+ TypeErrorAdditionalDiags::TupleAlsoParentheses {
+ span_low: span.shrink_to_lo(),
+ span_high: span.shrink_to_hi(),
+ }
+ };
+ Some(sugg)
}
fn values_str(
@@ -2124,6 +2122,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
match values {
infer::Regions(exp_found) => self.expected_found_str(exp_found),
infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
+ infer::Aliases(exp_found) => self.expected_found_str(exp_found),
infer::TraitRefs(exp_found) => {
let pretty_exp_found = ty::error::ExpectedFound {
expected: exp_found.expected.print_only_trait_path(),
@@ -2386,10 +2385,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let suggestion =
if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) };
let mut suggestions = vec![(sp, suggestion)];
- for add_lt_sugg in add_lt_suggs {
- if let Some(add_lt_sugg) = add_lt_sugg {
- suggestions.push(add_lt_sugg);
- }
+ for add_lt_sugg in add_lt_suggs.into_iter().flatten() {
+ suggestions.push(add_lt_sugg);
}
err.multipart_suggestion_verbose(
format!("{msg}..."),
@@ -2413,11 +2410,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
let mut sugg =
vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))];
- for add_lt_sugg in add_lt_suggs.clone() {
- if let Some(lt) = add_lt_sugg {
- sugg.push(lt);
- sugg.rotate_right(1);
- }
+ for lt in add_lt_suggs.clone().into_iter().flatten() {
+ sugg.push(lt);
+ sugg.rotate_right(1);
}
// `MaybeIncorrect` due to issue #41966.
err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
@@ -2688,11 +2683,6 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
self.0.tcx
}
- fn intercrate(&self) -> bool {
- assert!(!self.0.intercrate);
- false
- }
-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
// Unused, only for consts which we treat as always equal
ty::ParamEnv::empty()
@@ -2706,10 +2696,6 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
true
}
- fn mark_ambiguous(&mut self) {
- bug!()
- }
-
fn relate_with_variance<T: relate::Relate<'tcx>>(
&mut self,
_variance: ty::Variance,
@@ -2828,15 +2814,21 @@ impl<'tcx> InferCtxt<'tcx> {
}
pub enum FailureCode {
- Error0038(DefId),
- Error0317(&'static str),
- Error0580(&'static str),
- Error0308(&'static str),
- Error0644(&'static str),
+ Error0317,
+ Error0580,
+ Error0308,
+ Error0644,
}
pub trait ObligationCauseExt<'tcx> {
fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode;
+
+ fn as_failure_code_diag(
+ &self,
+ terr: TypeError<'tcx>,
+ span: Span,
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ ) -> ObligationCauseFailureCode;
fn as_requirement_str(&self) -> &'static str;
}
@@ -2845,40 +2837,68 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
use self::FailureCode::*;
use crate::traits::ObligationCauseCode::*;
match self.code() {
+ IfExpressionWithNoElse => Error0317,
+ MainFunctionType => Error0580,
+ CompareImplItemObligation { .. }
+ | MatchExpressionArm(_)
+ | IfExpression { .. }
+ | LetElse
+ | StartFunctionType
+ | IntrinsicType
+ | MethodReceiver => Error0308,
+
+ // In the case where we have no more specific thing to
+ // say, also take a look at the error code, maybe we can
+ // tailor to that.
+ _ => match terr {
+ TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => Error0644,
+ TypeError::IntrinsicCast => Error0308,
+ _ => Error0308,
+ },
+ }
+ }
+ fn as_failure_code_diag(
+ &self,
+ terr: TypeError<'tcx>,
+ span: Span,
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ ) -> ObligationCauseFailureCode {
+ use crate::traits::ObligationCauseCode::*;
+ match self.code() {
CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
- Error0308("method not compatible with trait")
+ ObligationCauseFailureCode::MethodCompat { span, subdiags }
}
CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
- Error0308("type not compatible with trait")
+ ObligationCauseFailureCode::TypeCompat { span, subdiags }
}
CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
- Error0308("const not compatible with trait")
- }
- MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => {
- Error0308(match source {
- hir::MatchSource::TryDesugar => "`?` operator has incompatible types",
- _ => "`match` arms have incompatible types",
- })
- }
- IfExpression { .. } => Error0308("`if` and `else` have incompatible types"),
- IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"),
- LetElse => Error0308("`else` clause of `let...else` does not diverge"),
- MainFunctionType => Error0580("`main` function has wrong type"),
- StartFunctionType => Error0308("`#[start]` function has wrong type"),
- IntrinsicType => Error0308("intrinsic has wrong type"),
- MethodReceiver => Error0308("mismatched `self` parameter type"),
+ ObligationCauseFailureCode::ConstCompat { span, subdiags }
+ }
+ MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
+ hir::MatchSource::TryDesugar => {
+ ObligationCauseFailureCode::TryCompat { span, subdiags }
+ }
+ _ => ObligationCauseFailureCode::MatchCompat { span, subdiags },
+ },
+ IfExpression { .. } => ObligationCauseFailureCode::IfElseDifferent { span, subdiags },
+ IfExpressionWithNoElse => ObligationCauseFailureCode::NoElse { span },
+ LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags },
+ MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span },
+ StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags },
+ IntrinsicType => ObligationCauseFailureCode::IntristicCorrectType { span, subdiags },
+ MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags },
// In the case where we have no more specific thing to
// say, also take a look at the error code, maybe we can
// tailor to that.
_ => match terr {
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => {
- Error0644("closure/generator type that references itself")
+ ObligationCauseFailureCode::ClosureSelfref { span }
}
TypeError::IntrinsicCast => {
- Error0308("cannot coerce intrinsics to function pointers")
+ ObligationCauseFailureCode::CantCoerce { span, subdiags }
}
- _ => Error0308("mismatched types"),
+ _ => ObligationCauseFailureCode::Generic { span, subdiags },
},
}
}
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 e242900fd..75cc4e257 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,5 +1,5 @@
use crate::errors::{
- AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
+ AmbigousReturn, AmbiguousImpl, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
SourceKindMultiSuggestion, SourceKindSubdiag,
};
use crate::infer::error_reporting::TypeErrCtxt;
@@ -10,14 +10,14 @@ use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
use rustc_middle::hir::nested_filter;
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
-use rustc_middle::ty::{self, DefIdTree, InferConst};
+use rustc_middle::ty::{self, InferConst};
use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
use rustc_span::symbol::{kw, sym, Ident};
@@ -358,7 +358,7 @@ impl<'tcx> InferCtxt<'tcx> {
bad_label,
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
- TypeAnnotationNeeded::E0283 => AmbigousImpl {
+ TypeAnnotationNeeded::E0283 => AmbiguousImpl {
span,
source_kind,
source_name,
@@ -386,7 +386,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self, error_code))]
pub fn emit_inference_failure_err(
&self,
- body_id: Option<hir::BodyId>,
+ body_def_id: LocalDefId,
failure_span: Span,
arg: GenericArg<'tcx>,
error_code: TypeAnnotationNeeded,
@@ -403,8 +403,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg);
- if let Some(body_id) = body_id {
- let expr = self.tcx.hir().expect_expr(body_id.hir_id);
+ if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(
+ self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(),
+ ) {
+ let expr = self.tcx.hir().body(body_id).value;
local_visitor.visit_expr(expr);
}
@@ -561,7 +563,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
bad_label: None,
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
- TypeAnnotationNeeded::E0283 => AmbigousImpl {
+ TypeAnnotationNeeded::E0283 => AmbiguousImpl {
span,
source_kind,
source_name: &name,
@@ -1189,11 +1191,14 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
have_turbofish,
} = args;
let generics = tcx.generics_of(generics_def_id);
- if let Some(argument_index) = generics
+ if let Some(mut argument_index) = generics
.own_substs(substs)
.iter()
.position(|&arg| self.generic_arg_contains_target(arg))
{
+ if generics.parent.is_none() && generics.has_self {
+ argument_index += 1;
+ }
let substs = self.infcx.resolve_vars_if_possible(substs);
let generic_args = &generics.own_substs_no_defaults(tcx, substs)
[generics.own_counts().lifetimes..];
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
index e8d94f0c0..8a78a1956 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
@@ -16,22 +16,34 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
match &self.error {
Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::RelateRegionParamBound(span),
- Region(Interned(RePlaceholder(ty::Placeholder { name: sub_name, .. }), _)),
- Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)),
+ Region(Interned(
+ RePlaceholder(ty::Placeholder {
+ bound: ty::BoundRegion { kind: sub_name, .. },
+ ..
+ }),
+ _,
+ )),
+ Region(Interned(
+ RePlaceholder(ty::Placeholder {
+ bound: ty::BoundRegion { kind: sup_name, .. },
+ ..
+ }),
+ _,
+ )),
)) => {
let span = *span;
let (sub_span, sub_symbol) = match sub_name {
ty::BrNamed(def_id, symbol) => {
(Some(self.tcx().def_span(def_id)), Some(symbol))
}
- ty::BrAnon(_, span) => (*span, None),
+ ty::BrAnon(span) => (*span, None),
ty::BrEnv => (None, None),
};
let (sup_span, sup_symbol) = match sup_name {
ty::BrNamed(def_id, symbol) => {
(Some(self.tcx().def_span(def_id)), Some(symbol))
}
- ty::BrAnon(_, span) => (*span, None),
+ ty::BrAnon(span) => (*span, None),
ty::BrEnv => (None, None),
};
let diag = match (sub_span, sup_span, sub_symbol, sup_symbol) {
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 b06ff10d8..22c1e3871 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
@@ -104,7 +104,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let (mention_influencer, influencer_point) =
if sup_origin.span().overlaps(param.param_ty_span) {
// Account for `async fn` like in `async-await/issues/issue-62097.rs`.
- // The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same
+ // The desugaring of `async fn`s causes `sup_origin` and `param` to point at the same
// place (but with different `ctxt`, hence `overlaps` instead of `==` above).
//
// This avoids the following:
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 db4b8af46..c5ef48fe3 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
@@ -5,7 +5,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::TyCtxt;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeVisitable};
+use rustc_middle::ty::{self, Binder, Region, Ty, TypeVisitable};
use rustc_span::Span;
/// Information about the anonymous region we are searching for.
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 7ffe1fd20..07a9eff2d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -1,5 +1,5 @@
use crate::errors::{
- note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
+ note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
};
use crate::fluent_generated as fluent;
@@ -176,7 +176,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let note = note_and_explain::RegionExplanation::new(
self.tcx, sub, opt_span, prefix, suffix,
);
- FullfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note }
+ FulfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note }
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
}
infer::RelateRegionParamBound(span) => {
@@ -306,9 +306,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// Replace the explicit self type with `Self` for better suggestion rendering
.with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
.substs;
- let trait_item_substs =
- ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id())
- .rebase_onto(self.tcx, impl_def_id, trait_substs);
+ let trait_item_substs = ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id)
+ .rebase_onto(self.tcx, impl_def_id, trait_substs);
let Ok(trait_predicates) = self
.tcx
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index b33729d0b..b38bbdfe7 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -1,7 +1,7 @@
use super::TypeErrCtxt;
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
-use rustc_hir::{self as hir, def::DefKind};
+use rustc_hir as hir;
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::Printer;
@@ -75,7 +75,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
diag.note("an associated type was expected, but a different one was found");
}
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
- if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
+ if !tcx.is_impl_trait_in_trait(proj.def_id) =>
{
let p_def_id = tcx
.generics_of(body_owner_def_id)
@@ -222,7 +222,7 @@ impl<T> Trait<T> for X {
diag.span_label(p_span, "this type parameter");
}
}
- (ty::Alias(ty::Projection, proj_ty), _) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
+ (ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
self.expected_projection(
diag,
proj_ty,
@@ -231,7 +231,7 @@ impl<T> Trait<T> for X {
cause.code(),
);
}
- (_, ty::Alias(ty::Projection, proj_ty)) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
+ (_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
let msg = format!(
"consider constraining the associated type `{}` to `{}`",
values.found, values.expected,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 55dcfd05e..b5aeca12a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -1,7 +1,7 @@
use hir::def::CtorKind;
use hir::intravisit::{walk_expr, walk_stmt, Visitor};
use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{Applicability, Diagnostic};
+use rustc_errors::Diagnostic;
use rustc_hir as hir;
use rustc_middle::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -10,13 +10,23 @@ use rustc_middle::traits::{
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitableExt};
use rustc_span::{sym, BytePos, Span};
+use rustc_target::abi::FieldIdx;
use crate::errors::{
- ConsiderAddingAwait, SuggAddLetForLetChains, SuggestRemoveSemiOrReturnBinding,
+ ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
+ FunctionPointerSuggestion, SuggestAccessingField, SuggestAsRefWhereAppropriate,
+ SuggestBoxingForReturnImplTrait, SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany,
+ SuggestTuplePatternOne, TypeErrorAdditionalDiags,
};
use super::TypeErrCtxt;
+#[derive(Clone, Copy)]
+pub enum SuggestAsRefKind {
+ Option,
+ Result,
+}
+
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pub(super) fn suggest_remove_semi_or_return_binding(
&self,
@@ -71,25 +81,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
return_sp: Span,
arm_spans: impl Iterator<Item = Span>,
) {
- err.multipart_suggestion(
- "you could change the return type to be a boxed trait object",
- vec![
- (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
- (return_sp.shrink_to_hi(), ">".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- let sugg = arm_spans
- .flat_map(|sp| {
- [(sp.shrink_to_lo(), "Box::new(".to_string()), (sp.shrink_to_hi(), ")".to_string())]
- .into_iter()
- })
- .collect::<Vec<_>>();
- err.multipart_suggestion(
- "if you change the return type to expect trait objects, box the returned expressions",
- sugg,
- Applicability::MaybeIncorrect,
- );
+ let sugg = SuggestBoxingForReturnImplTrait::ChangeReturnType {
+ start_sp: return_sp.with_hi(return_sp.lo() + BytePos(4)),
+ end_sp: return_sp.shrink_to_hi(),
+ };
+ err.subdiagnostic(sugg);
+
+ let mut starts = Vec::new();
+ let mut ends = Vec::new();
+ for span in arm_spans {
+ starts.push(span.shrink_to_lo());
+ ends.push(span.shrink_to_hi());
+ }
+ let sugg = SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends };
+ err.subdiagnostic(sugg);
}
pub(super) fn suggest_tuple_pattern(
@@ -109,7 +114,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn)
})
.filter_map(|variant| {
- let sole_field = &variant.fields[0];
+ let sole_field = &variant.fields[FieldIdx::from_u32(0)];
let sole_field_ty = sole_field.ty(self.tcx, substs);
if self.same_type_modulo_infer(sole_field_ty, exp_found.found) {
let variant_path =
@@ -129,30 +134,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
match &compatible_variants[..] {
[] => {}
[variant] => {
- diag.multipart_suggestion_verbose(
- &format!("try wrapping the pattern in `{}`", variant),
- vec![
- (cause.span.shrink_to_lo(), format!("{}(", variant)),
- (cause.span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
+ let sugg = SuggestTuplePatternOne {
+ variant: variant.to_owned(),
+ span_low: cause.span.shrink_to_lo(),
+ span_high: cause.span.shrink_to_hi(),
+ };
+ diag.subdiagnostic(sugg);
}
_ => {
// More than one matching variant.
- diag.multipart_suggestions(
- &format!(
- "try wrapping the pattern in a variant of `{}`",
- self.tcx.def_path_str(expected_adt.did())
- ),
- compatible_variants.into_iter().map(|variant| {
- vec![
- (cause.span.shrink_to_lo(), format!("{}(", variant)),
- (cause.span.shrink_to_hi(), ")".to_string()),
- ]
- }),
- Applicability::MaybeIncorrect,
- );
+ let sugg = SuggestTuplePatternMany {
+ path: self.tcx.def_path_str(expected_adt.did()),
+ cause_span: cause.span,
+ compatible_variants,
+ };
+ diag.subdiagnostic(sugg);
}
}
}
@@ -255,15 +251,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
- pub fn suggest_await_on_future(&self, diag: &mut Diagnostic, sp: Span) {
- diag.span_suggestion_verbose(
- sp.shrink_to_hi(),
- "consider `await`ing on the `Future`",
- ".await",
- Applicability::MaybeIncorrect,
- );
- }
-
pub(super) fn suggest_accessing_field_where_appropriate(
&self,
cause: &ObligationCause<'tcx>,
@@ -290,21 +277,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
let suggestion = if expected_def.is_struct() {
- format!("{}.{}", snippet, name)
+ SuggestAccessingField::Safe { span, snippet, name, ty }
} else if expected_def.is_union() {
- format!("unsafe {{ {}.{} }}", snippet, name)
+ SuggestAccessingField::Unsafe { span, snippet, name, ty }
} else {
return;
};
- diag.span_suggestion(
- span,
- &format!(
- "you might have meant to use field `{}` whose type is `{}`",
- name, ty
- ),
- suggestion,
- Applicability::MaybeIncorrect,
- );
+ diag.subdiagnostic(suggestion);
}
}
}
@@ -320,15 +299,15 @@ impl<'tcx> TypeErrCtxt<'_, '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)
+ && let Some(msg) = self.should_suggest_as_ref_kind(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,
- );
+ // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
+ let snippet = snippet.trim_start_matches('&');
+ let subdiag = match msg {
+ SuggestAsRefKind::Option => SuggestAsRefWhereAppropriate::Option { span, snippet },
+ SuggestAsRefKind::Result => SuggestAsRefWhereAppropriate::Result { span, snippet },
+ };
+ diag.subdiagnostic(subdiag);
}
}
@@ -356,36 +335,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
if !self.same_type_modulo_infer(*found_sig, *expected_sig)
|| !sig.is_suggestable(self.tcx, true)
- || ty::util::is_intrinsic(self.tcx, *did)
+ || self.tcx.is_intrinsic(*did)
{
return;
}
- let (msg, sug) = match (expected.is_ref(), found.is_ref()) {
- (true, false) => {
- let msg = "consider using a reference";
- let sug = format!("&{fn_name}");
- (msg, sug)
- }
- (false, true) => {
- let msg = "consider removing the reference";
- let sug = format!("{fn_name}");
- (msg, sug)
- }
+ let sugg = match (expected.is_ref(), found.is_ref()) {
+ (true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
+ (false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name },
(true, true) => {
- diag.note("fn items are distinct from fn pointers");
- let msg = "consider casting to a fn pointer";
- let sug = format!("&({fn_name} as {sig})");
- (msg, sug)
+ diag.subdiagnostic(FnItemsAreDistinct);
+ FunctionPointerSuggestion::CastRef { span, fn_name, sig: *sig }
}
(false, false) => {
- diag.note("fn items are distinct from fn pointers");
- let msg = "consider casting to a fn pointer";
- let sug = format!("{fn_name} as {sig}");
- (msg, sug)
+ diag.subdiagnostic(FnItemsAreDistinct);
+ FunctionPointerSuggestion::Cast { span, fn_name, sig: *sig }
}
};
- diag.span_suggestion_verbose(span, msg, sug, Applicability::MaybeIncorrect);
+ diag.subdiagnostic(sugg);
}
(ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
let expected_sig =
@@ -394,30 +361,36 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&(self.normalize_fn_sig)(self.tcx.fn_sig(*did2).subst(self.tcx, substs2));
if self.same_type_modulo_infer(*expected_sig, *found_sig) {
- diag.note("different fn items have unique types, even if their signatures are the same");
+ diag.subdiagnostic(FnUniqTypes);
}
if !self.same_type_modulo_infer(*found_sig, *expected_sig)
|| !found_sig.is_suggestable(self.tcx, true)
|| !expected_sig.is_suggestable(self.tcx, true)
- || ty::util::is_intrinsic(self.tcx, *did1)
- || ty::util::is_intrinsic(self.tcx, *did2)
+ || self.tcx.is_intrinsic(*did1)
+ || self.tcx.is_intrinsic(*did2)
{
return;
}
let fn_name = self.tcx.def_path_str_with_substs(*did2, substs2);
let sug = if found.is_ref() {
- format!("&({fn_name} as {found_sig})")
+ FunctionPointerSuggestion::CastBothRef {
+ span,
+ fn_name,
+ found_sig: *found_sig,
+ expected_sig: *expected_sig,
+ }
} else {
- format!("{fn_name} as {found_sig}")
+ FunctionPointerSuggestion::CastBoth {
+ span,
+ fn_name,
+ found_sig: *found_sig,
+ expected_sig: *expected_sig,
+ }
};
- let msg = format!(
- "consider casting both fn items to fn pointers using `as {expected_sig}`"
- );
-
- diag.span_suggestion_hidden(span, msg, sug, Applicability::MaybeIncorrect);
+ diag.subdiagnostic(sug);
}
(ty::FnDef(did, substs), ty::FnPtr(sig)) => {
let expected_sig =
@@ -436,7 +409,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
format!("{fn_name} as {found_sig}")
};
- diag.help(&format!("consider casting the fn item to a fn pointer: `{}`", casting));
+ diag.subdiagnostic(FnConsiderCasting { casting });
}
_ => {
return;
@@ -444,23 +417,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
}
- pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
+ pub fn should_suggest_as_ref_kind(
+ &self,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ ) -> Option<SuggestAsRefKind> {
if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) =
(expected.kind(), found.kind())
{
if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
if exp_def == &found_def {
let have_as_ref = &[
- (
- 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()`",
- ),
+ (sym::Option, SuggestAsRefKind::Option),
+ (sym::Result, SuggestAsRefKind::Result),
];
if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| {
self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg)
@@ -494,15 +463,28 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
None
}
+ // FIXME: Remove once `rustc_hir_typeck` is migrated to diagnostic structs
+ pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
+ match self.should_suggest_as_ref_kind(expected, found) {
+ Some(SuggestAsRefKind::Option) => Some(
+ "you can convert from `&Option<T>` to `Option<&T>` using \
+ `.as_ref()`",
+ ),
+ Some(SuggestAsRefKind::Result) => Some(
+ "you can convert from `&Result<T, E>` to \
+ `Result<&T, &E>` using `.as_ref()`",
+ ),
+ None => None,
+ }
+ }
/// Try to find code with pattern `if Some(..) = expr`
/// use a `visitor` to mark the `if` which its span contains given error span,
/// and then try to find a assignment in the `cond` part, which span is equal with error span
pub(super) fn suggest_let_for_letchains(
&self,
- err: &mut Diagnostic,
cause: &ObligationCause<'_>,
span: Span,
- ) {
+ ) -> Option<TypeErrorAdditionalDiags> {
let hir = self.tcx.hir();
if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) &&
let hir::Node::Item(hir::Item {
@@ -549,9 +531,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut visitor = IfVisitor { err_span: span, found_if: false, result: false };
visitor.visit_body(&body);
if visitor.result {
- err.subdiagnostic(SuggAddLetForLetChains{span: span.shrink_to_lo()});
+ return Some(TypeErrorAdditionalDiags::AddLetForLetChains{span: span.shrink_to_lo()});
}
}
+ None
}
}
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index f09f93abf..d89f63e5c 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -43,18 +43,16 @@ pub struct TypeFreshener<'a, 'tcx> {
const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
- keep_static: bool,
}
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> TypeFreshener<'a, 'tcx> {
TypeFreshener {
infcx,
ty_freshen_count: 0,
const_freshen_count: 0,
ty_freshen_map: Default::default(),
const_freshen_map: Default::default(),
- keep_static,
}
}
@@ -121,18 +119,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
| ty::ReFree(_)
| ty::ReVar(_)
| ty::RePlaceholder(..)
+ | ty::ReStatic
| ty::ReError(_)
- | ty::ReErased => {
- // replace all free regions with 'erased
- self.interner().lifetimes.re_erased
- }
- ty::ReStatic => {
- if self.keep_static {
- r
- } else {
- self.interner().lifetimes.re_erased
- }
- }
+ | ty::ReErased => self.interner().lifetimes.re_erased,
}
}
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 49df393d8..2f659d9a6 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -2,8 +2,8 @@
use super::combine::{CombineFields, ObligationEmittingRelation};
use super::lattice::{self, LatticeDir};
-use super::InferCtxt;
use super::Subtype;
+use super::{DefineOpaqueTypes, InferCtxt};
use crate::traits::{ObligationCause, PredicateObligations};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
@@ -29,11 +29,6 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
"Glb"
}
- fn intercrate(&self) -> bool {
- assert!(!self.fields.infcx.intercrate);
- false
- }
-
fn tcx(&self) -> TyCtxt<'tcx> {
self.fields.tcx()
}
@@ -46,10 +41,6 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
self.a_is_expected
}
- fn mark_ambiguous(&mut self) {
- bug!("mark_ambiguous used outside of coherence");
- }
-
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
@@ -142,7 +133,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
Ok(())
}
- fn define_opaque_types(&self) -> bool {
+ fn define_opaque_types(&self) -> DefineOpaqueTypes {
self.fields.define_opaque_types
}
}
@@ -155,4 +146,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.fields.register_obligations(obligations);
}
+
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+ // FIXME(deferred_projection_equality): This isn't right, I think?
+ ty::AliasRelationDirection::Equate
+ }
}
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index d1897cf24..a63cfbc91 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -82,20 +82,20 @@ impl<'tcx> InferCtxt<'tcx> {
let delegate = FnMutDelegate {
regions: &mut |br: ty::BoundRegion| {
- self.tcx.mk_re_placeholder(ty::PlaceholderRegion {
- universe: next_universe,
- name: br.kind,
- })
+ self.tcx
+ .mk_re_placeholder(ty::PlaceholderRegion { universe: next_universe, bound: br })
},
types: &mut |bound_ty: ty::BoundTy| {
self.tcx.mk_placeholder(ty::PlaceholderType {
universe: next_universe,
- name: bound_ty.kind,
+ bound: bound_ty,
})
},
consts: &mut |bound_var: ty::BoundVar, ty| {
- self.tcx
- .mk_const(ty::PlaceholderConst { universe: next_universe, name: bound_var }, ty)
+ self.tcx.mk_const(
+ ty::PlaceholderConst { universe: next_universe, bound: bound_var },
+ ty,
+ )
},
};
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index f377ac1d1..7f4c141b9 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -19,7 +19,7 @@
use super::combine::ObligationEmittingRelation;
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use super::InferCtxt;
+use super::{DefineOpaqueTypes, InferCtxt};
use crate::traits::ObligationCause;
use rustc_middle::ty::relate::RelateResult;
@@ -36,7 +36,7 @@ pub trait LatticeDir<'f, 'tcx>: ObligationEmittingRelation<'tcx> {
fn cause(&self) -> &ObligationCause<'tcx>;
- fn define_opaque_types(&self) -> bool;
+ fn define_opaque_types(&self) -> DefineOpaqueTypes;
// Relates the type `v` to `a` and `b` such that `v` represents
// the LUB/GLB of `a` and `b` as appropriate.
@@ -110,7 +110,7 @@ where
) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
- if this.define_opaque_types() && def_id.is_local() =>
+ if this.define_opaque_types() == DefineOpaqueTypes::Yes && def_id.is_local() =>
{
this.register_obligations(
infcx
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 2c4803550..f298b95ca 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -13,7 +13,7 @@ use rustc_data_structures::graph::implementation::{
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
};
use rustc_data_structures::intern::Interned;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::vec::{IndexSlice, IndexVec};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::PlaceholderRegion;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -132,7 +132,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
let graph = self.construct_graph();
- self.expand_givens(&graph);
self.expansion(&mut var_data);
self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors);
@@ -164,38 +163,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}
- fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
- // Givens are a kind of horrible hack to account for
- // constraints like 'c <= '0 that are known to hold due to
- // closure signatures (see the comment above on the `givens`
- // field). They should go away. But until they do, the role
- // of this fn is to account for the transitive nature:
- //
- // Given 'c <= '0
- // and '0 <= '1
- // then 'c <= '1
-
- let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
- for (r, vid) in seeds {
- // While all things transitively reachable in the graph
- // from the variable (`'0` in the example above).
- let seed_index = NodeIndex(vid.index() as usize);
- for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
- let succ_index = succ_index.0;
-
- // The first N nodes correspond to the region
- // variables. Other nodes correspond to constant
- // regions.
- if succ_index < self.num_vars() {
- let succ_vid = RegionVid::new(succ_index);
-
- // Add `'c <= '1`.
- self.data.givens.insert((r, succ_vid));
- }
- }
- }
- }
-
/// 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 {
@@ -236,7 +203,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// 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());
+ let mut constraints = IndexVec::from_elem(Vec::new(), &var_values.values);
// Tracks the changed region vids.
let mut changes = Vec::new();
for constraint in self.data.constraints.keys() {
@@ -362,18 +329,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
) -> bool {
debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
- match *a_region {
- // Check if this relationship is implied by a given.
- ty::ReEarlyBound(_) | ty::ReFree(_) => {
- if self.data.givens.contains(&(a_region, b_vid)) {
- debug!("given");
- return false;
- }
- }
-
- _ => {}
- }
-
match *b_data {
VarValue::Empty(empty_ui) => {
let lub = match self.lub_empty(a_region) {
@@ -768,7 +723,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
fn collect_error_for_expanding_node(
&self,
graph: &RegionGraph<'tcx>,
- dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>,
+ dup_vec: &mut IndexSlice<RegionVid, Option<RegionVid>>,
node_idx: RegionVid,
errors: &mut Vec<RegionResolutionError<'tcx>>,
) {
@@ -891,7 +846,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
graph: &RegionGraph<'tcx>,
orig_node_idx: RegionVid,
dir: Direction,
- mut dup_vec: Option<&mut IndexVec<RegionVid, Option<RegionVid>>>,
+ mut dup_vec: Option<&mut IndexSlice<RegionVid, Option<RegionVid>>>,
) -> (Vec<RegionAndOrigin<'tcx>>, FxHashSet<RegionVid>, bool) {
struct WalkState<'tcx> {
set: FxHashSet<RegionVid>,
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index c871ccb21..e41ec7e6c 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -2,8 +2,8 @@
use super::combine::{CombineFields, ObligationEmittingRelation};
use super::lattice::{self, LatticeDir};
-use super::InferCtxt;
use super::Subtype;
+use super::{DefineOpaqueTypes, InferCtxt};
use crate::traits::{ObligationCause, PredicateObligations};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
@@ -29,11 +29,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
"Lub"
}
- fn intercrate(&self) -> bool {
- assert!(!self.fields.infcx.intercrate);
- false
- }
-
fn tcx(&self) -> TyCtxt<'tcx> {
self.fields.tcx()
}
@@ -46,10 +41,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
self.a_is_expected
}
- fn mark_ambiguous(&mut self) {
- bug!("mark_ambiguous used outside of coherence");
- }
-
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
@@ -142,7 +133,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
Ok(())
}
- fn define_opaque_types(&self) -> bool {
+ fn define_opaque_types(&self) -> DefineOpaqueTypes {
self.fields.define_opaque_types
}
}
@@ -155,4 +146,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.fields.register_obligations(obligations)
}
+
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+ // FIXME(deferred_projection_equality): This isn't right, I think?
+ ty::AliasRelationDirection::Equate
+ }
}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index bd1f96635..66f51328b 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1,3 +1,4 @@
+pub use self::at::DefineOpaqueTypes;
pub use self::freshen::TypeFreshener;
pub use self::lexical_region_resolve::RegionResolutionError;
pub use self::LateBoundRegionConversionTime::*;
@@ -38,13 +39,13 @@ use rustc_span::Span;
use std::cell::{Cell, RefCell};
use std::fmt;
+use std::ops::Drop;
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;
-use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
+use self::region_constraints::{GenericKind, VarInfos, VerifyBound};
use self::region_constraints::{
RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
};
@@ -94,10 +95,10 @@ pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
/// call to `start_snapshot` and `rollback_to`.
#[derive(Clone)]
pub struct InferCtxtInner<'tcx> {
- /// Cache for projections. This cache is snapshotted along with the infcx.
+ /// Cache for projections.
///
- /// Public so that `traits::project` can use it.
- pub projection_cache: traits::ProjectionCacheStorage<'tcx>,
+ /// This cache is snapshotted along with the infcx.
+ projection_cache: traits::ProjectionCacheStorage<'tcx>,
/// We instantiate `UnificationTable` with `bounds<Ty>` because the types
/// that might instantiate a general type variable have an order,
@@ -114,24 +115,26 @@ pub struct InferCtxtInner<'tcx> {
float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
/// Tracks the set of region variables and the constraints between them.
+ ///
/// This is initially `Some(_)` but when
/// `resolve_regions_and_report_errors` is invoked, this gets set to `None`
/// -- further attempts to perform unification, etc., may fail if new
/// region constraints would've been added.
region_constraint_storage: Option<RegionConstraintStorage<'tcx>>,
- /// A set of constraints that regionck must validate. Each
- /// constraint has the form `T:'a`, meaning "some type `T` must
+ /// A set of constraints that regionck must validate.
+ ///
+ /// Each constraint has the form `T:'a`, meaning "some type `T` must
/// outlive the lifetime 'a". These constraints derive from
/// instantiated type parameters. So if you had a struct defined
- /// like
+ /// like the following:
/// ```ignore (illustrative)
- /// struct Foo<T:'static> { ... }
+ /// struct Foo<T: 'static> { ... }
/// ```
- /// then in some expression `let x = Foo { ... }` it will
+ /// In some expression `let x = Foo { ... }`, it will
/// instantiate the type parameter `T` with a fresh type `$0`. At
/// the same time, it will record a region obligation of
- /// `$0:'static`. This will get checked later by regionck. (We
+ /// `$0: 'static`. This will get checked later by regionck. (We
/// can't generally check these things right away because we have
/// to wait until types are resolved.)
///
@@ -185,6 +188,16 @@ impl<'tcx> InferCtxtInner<'tcx> {
}
#[inline]
+ fn try_type_variables_probe_ref(
+ &self,
+ vid: ty::TyVid,
+ ) -> Option<&type_variable::TypeVariableValue<'tcx>> {
+ // Uses a read-only view of the unification table, this way we don't
+ // need an undo log.
+ self.type_variable_storage.eq_relations_ref().try_probe_value(vid)
+ }
+
+ #[inline]
fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> {
self.type_variable_storage.with_log(&mut self.undo_log)
}
@@ -268,7 +281,7 @@ pub struct InferCtxt<'tcx> {
/// Caches the results of trait evaluation.
pub evaluation_cache: select::EvaluationCache<'tcx>,
- /// the set of predicates on which errors have been reported, to
+ /// The set of predicates on which errors have been reported, to
/// avoid reporting the same error twice.
pub reported_trait_errors: RefCell<FxIndexMap<Span, Vec<ty::Predicate<'tcx>>>>,
@@ -291,7 +304,7 @@ pub struct InferCtxt<'tcx> {
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
+ /// If the number of errors increases, that's also a sign (like
/// `tainted_by_errors`) to avoid reporting certain kinds of errors.
// FIXME(matthewjasper) Merge into `tainted_by_errors`
err_count_on_creation: usize,
@@ -313,7 +326,7 @@ pub struct InferCtxt<'tcx> {
/// During coherence we have to assume that other crates may add
/// additional impls which we currently don't know about.
///
- /// To deal with this evaluation should be conservative
+ /// To deal with this evaluation, we should be conservative
/// and consider the possibility of impls from outside this crate.
/// This comes up primarily when resolving ambiguity. Imagine
/// there is some trait reference `$0: Bar` where `$0` is an
@@ -323,12 +336,17 @@ pub struct InferCtxt<'tcx> {
/// bound to some type that in a downstream crate that implements
/// `Bar`.
///
- /// Outside of coherence we set this to false because we are only
+ /// Outside of coherence, we set this to false because we are only
/// interested in types that the user could actually have written.
/// In other words, we consider `$0: Bar` to be unimplemented if
/// there is no type that the user could *actually name* that
/// would satisfy it. This avoids crippling inference, basically.
pub intercrate: bool,
+
+ /// Flag that is set when we enter canonicalization. Used for debugging to ensure
+ /// that we only collect region information for `BorrowckInferCtxt::reg_var_to_origin`
+ /// inside non-canonicalization contexts.
+ inside_canonicalization_ctxt: Cell<bool>,
}
/// See the `error_reporting` module for more details.
@@ -336,6 +354,7 @@ pub struct InferCtxt<'tcx> {
pub enum ValuePairs<'tcx> {
Regions(ExpectedFound<ty::Region<'tcx>>),
Terms(ExpectedFound<ty::Term<'tcx>>),
+ Aliases(ExpectedFound<ty::AliasTy<'tcx>>),
TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
Sigs(ExpectedFound<ty::FnSig<'tcx>>),
@@ -373,7 +392,7 @@ pub enum SubregionOrigin<'tcx> {
Subtype(Box<TypeTrace<'tcx>>),
/// When casting `&'a T` to an `&'b Trait` object,
- /// relating `'a` to `'b`
+ /// relating `'a` to `'b`.
RelateObjectBound(Span),
/// Some type parameter was instantiated with the given type,
@@ -384,7 +403,7 @@ pub enum SubregionOrigin<'tcx> {
/// that must outlive some other region.
RelateRegionParamBound(Span),
- /// Creating a pointer `b` to contents of another reference
+ /// Creating a pointer `b` to contents of another reference.
Reborrow(Span),
/// (&'a &'b T) where a >= b
@@ -398,7 +417,7 @@ pub enum SubregionOrigin<'tcx> {
trait_item_def_id: DefId,
},
- /// Checking that the bounds of a trait's associated type hold for a given impl
+ /// Checking that the bounds of a trait's associated type hold for a given impl.
CheckAssociatedTypeBounds {
parent: Box<SubregionOrigin<'tcx>>,
impl_item_def_id: LocalDefId,
@@ -435,32 +454,33 @@ pub enum LateBoundRegionConversionTime {
AssocTypeProjection(DefId),
}
-/// Reasons to create a region inference variable
+/// Reasons to create a region inference variable.
///
-/// See `error_reporting` module for more details
+/// See `error_reporting` module for more details.
#[derive(Copy, Clone, Debug)]
pub enum RegionVariableOrigin {
- /// Region variables created for ill-categorized reasons,
- /// mostly indicates places in need of refactoring
+ /// Region variables created for ill-categorized reasons.
+ ///
+ /// They mostly indicate places in need of refactoring.
MiscVariable(Span),
- /// Regions created by a `&P` or `[...]` pattern
+ /// Regions created by a `&P` or `[...]` pattern.
PatternRegion(Span),
- /// Regions created by `&` operator
+ /// Regions created by `&` operator.
+ ///
AddrOfRegion(Span),
-
- /// Regions created as part of an autoref of a method receiver
+ /// Regions created as part of an autoref of a method receiver.
Autoref(Span),
- /// Regions created as part of an automatic coercion
+ /// Regions created as part of an automatic coercion.
Coercion(Span),
- /// Region variables created as the values for early-bound regions
+ /// Region variables created as the values for early-bound regions.
EarlyBoundRegion(Span, Symbol),
/// Region variables created for bound regions
- /// in a function or method that is called
+ /// in a function or method that is called.
LateBoundRegion(Span, ty::BoundRegionKind, LateBoundRegionConversionTime),
UpvarRegion(ty::UpvarId, Span),
@@ -534,7 +554,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
}
}
-/// Used to configure inference contexts before their creation
+/// Used to configure inference contexts before their creation.
pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
defining_use_anchor: DefiningAnchor,
@@ -570,8 +590,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
self
}
- pub fn intercrate(mut self) -> Self {
- self.intercrate = true;
+ pub fn intercrate(mut self, intercrate: bool) -> Self {
+ self.intercrate = intercrate;
self
}
@@ -618,6 +638,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
skip_leak_check: Cell::new(false),
universe: Cell::new(ty::UniverseIndex::ROOT),
intercrate,
+ inside_canonicalization_ctxt: Cell::new(false),
}
}
}
@@ -691,12 +712,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
- freshen::TypeFreshener::new(self, false)
- }
-
- /// Like `freshener`, but does not replace `'static` regions.
- pub fn freshener_keep_static<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
- freshen::TypeFreshener::new(self, true)
+ freshen::TypeFreshener::new(self)
}
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
@@ -726,7 +742,7 @@ impl<'tcx> InferCtxt<'tcx> {
&'a self,
trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- define_opaque_types: bool,
+ define_opaque_types: DefineOpaqueTypes,
) -> CombineFields<'a, 'tcx> {
CombineFields {
infcx: self,
@@ -835,9 +851,9 @@ impl<'tcx> InferCtxt<'tcx> {
/// Scan the constraints produced since `snapshot` began and returns:
///
- /// - `None` -- if none of them involve "region outlives" constraints
- /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder
- /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders
+ /// - `None` -- if none of them involves "region outlives" constraints.
+ /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder.
+ /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders.
pub fn region_constraints_added_in_snapshot(
&self,
snapshot: &CombinedSnapshot<'tcx>,
@@ -852,16 +868,12 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
}
- pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
- self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
- }
-
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
where
T: at::ToTrace<'tcx>,
{
let origin = &ObligationCause::dummy();
- self.probe(|_| self.at(origin, param_env).sub(a, b).is_ok())
+ self.probe(|_| self.at(origin, param_env).sub(DefineOpaqueTypes::No, a, b).is_ok())
}
pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
@@ -869,7 +881,7 @@ impl<'tcx> InferCtxt<'tcx> {
T: at::ToTrace<'tcx>,
{
let origin = &ObligationCause::dummy();
- self.probe(|_| self.at(origin, param_env).eq(a, b).is_ok())
+ self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::No, a, b).is_ok())
}
#[instrument(skip(self), level = "debug")]
@@ -964,7 +976,8 @@ impl<'tcx> InferCtxt<'tcx> {
let ty::SubtypePredicate { a_is_expected, a, b } =
self.instantiate_binder_with_placeholders(predicate);
- let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
+ let ok =
+ self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)?;
Ok(ok.unit())
}))
@@ -1199,95 +1212,6 @@ impl<'tcx> InferCtxt<'tcx> {
self.tainted_by_errors.set(Some(e));
}
- pub fn skip_region_resolution(&self) {
- let (var_infos, _) = {
- let mut inner = self.inner.borrow_mut();
- let inner = &mut *inner;
- // Note: `inner.region_obligations` may not be empty, because we
- // didn't necessarily call `process_registered_region_obligations`.
- // This is okay, because that doesn't introduce new vars.
- inner
- .region_constraint_storage
- .take()
- .expect("regions already resolved")
- .with_log(&mut inner.undo_log)
- .into_infos_and_data()
- };
-
- let lexical_region_resolutions = LexicalRegionResolutions {
- values: rustc_index::vec::IndexVec::from_elem_n(
- crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
- var_infos.len(),
- ),
- };
-
- let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
- assert!(old_value.is_none());
- }
-
- /// 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`.
- pub fn resolve_regions(
- &self,
- outlives_env: &OutlivesEnvironment<'tcx>,
- ) -> Vec<RegionResolutionError<'tcx>> {
- let (var_infos, data) = {
- let mut inner = self.inner.borrow_mut();
- let inner = &mut *inner;
- assert!(
- self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(),
- "region_obligations not empty: {:#?}",
- inner.region_obligations
- );
- inner
- .region_constraint_storage
- .take()
- .expect("regions already resolved")
- .with_log(&mut inner.undo_log)
- .into_infos_and_data()
- };
-
- let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
-
- let (lexical_region_resolutions, errors) =
- lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
-
- let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
- assert!(old_value.is_none());
-
- errors
- }
- /// Obtains (and clears) the current set of region
- /// constraints. The inference context is still usable: further
- /// unifications will simply add new constraints.
- ///
- /// This method is not meant to be used with normal lexical region
- /// resolution. Rather, it is used in the NLL mode as a kind of
- /// interim hack: basically we run normal type-check and generate
- /// region constraints as normal, but then we take them and
- /// translate them into the form that the NLL solver
- /// understands. See the NLL module for mode details.
- pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
- assert!(
- self.inner.borrow().region_obligations.is_empty(),
- "region_obligations not empty: {:#?}",
- self.inner.borrow().region_obligations
- );
-
- self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data()
- }
-
- /// Gives temporary access to the region constraint data.
- pub fn with_region_constraints<R>(
- &self,
- op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
- ) -> R {
- let mut inner = self.inner.borrow_mut();
- op(inner.unwrap_region_constraints().data())
- }
-
pub fn region_var_origin(&self, vid: ty::RegionVid) -> RegionVariableOrigin {
let mut inner = self.inner.borrow_mut();
let inner = &mut *inner;
@@ -1356,6 +1280,32 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().type_variables().root_var(var)
}
+ pub fn root_const_var(&self, var: ty::ConstVid<'tcx>) -> ty::ConstVid<'tcx> {
+ self.inner.borrow_mut().const_unification_table().find(var)
+ }
+
+ /// Resolves an int var to a rigid int type, if it was constrained to one,
+ /// or else the root int var in the unification table.
+ pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
+ let mut inner = self.inner.borrow_mut();
+ if let Some(value) = inner.int_unification_table().probe_value(vid) {
+ value.to_type(self.tcx)
+ } else {
+ self.tcx.mk_int_var(inner.int_unification_table().find(vid))
+ }
+ }
+
+ /// Resolves a float var to a rigid int type, if it was constrained to one,
+ /// or else the root float var in the unification table.
+ pub fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> {
+ let mut inner = self.inner.borrow_mut();
+ if let Some(value) = inner.float_unification_table().probe_value(vid) {
+ value.to_type(self.tcx)
+ } else {
+ self.tcx.mk_float_var(inner.float_unification_table().find(vid))
+ }
+ }
+
/// Where possible, replaces type/const variables in
/// `value` with their final value. Note that region variables
/// are unaffected. If a type/const variable has not been unified, it
@@ -1614,6 +1564,28 @@ impl<'tcx> InferCtxt<'tcx> {
tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
}
+ /// The returned function is used in a fast path. If it returns `true` the variable is
+ /// unchanged, `false` indicates that the status is unknown.
+ #[inline]
+ pub fn is_ty_infer_var_definitely_unchanged<'a>(
+ &'a self,
+ ) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) {
+ // This hoists the borrow/release out of the loop body.
+ let inner = self.inner.try_borrow();
+
+ return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) {
+ (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => {
+ use self::type_variable::TypeVariableValue;
+
+ match inner.try_type_variables_probe_ref(ty_var) {
+ Some(TypeVariableValue::Unknown { .. }) => true,
+ _ => false,
+ }
+ }
+ _ => false,
+ };
+ }
+
/// `ty_or_const_infer_var_changed` is equivalent to one of these two:
/// * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`)
/// * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`)
@@ -1664,59 +1636,34 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
}
-}
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
- /// Processes registered region obliations and resolves regions, reporting
- /// any errors if any were raised. Prefer using this function over manually
- /// calling `resolve_regions_and_report_errors`.
- pub fn check_region_obligations_and_report_errors(
- &self,
- generic_param_scope: LocalDefId,
- outlives_env: &OutlivesEnvironment<'tcx>,
- ) -> Result<(), ErrorGuaranteed> {
- self.process_registered_region_obligations(
- outlives_env.region_bound_pairs(),
- outlives_env.param_env,
- );
+ pub fn inside_canonicalization_ctxt(&self) -> bool {
+ self.inside_canonicalization_ctxt.get()
+ }
- self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
+ pub fn set_canonicalization_ctxt(&self) -> CanonicalizationCtxtGuard<'_, 'tcx> {
+ let prev_ctxt = self.inside_canonicalization_ctxt();
+ self.inside_canonicalization_ctxt.set(true);
+ CanonicalizationCtxtGuard { prev_ctxt, infcx: self }
}
- /// 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 [`TypeErrCtxt::check_region_obligations_and_report_errors`]
- /// to do both of these operations together.
- pub fn resolve_regions_and_report_errors(
- &self,
- generic_param_scope: LocalDefId,
- outlives_env: &OutlivesEnvironment<'tcx>,
- ) -> Result<(), ErrorGuaranteed> {
- let errors = self.resolve_regions(outlives_env);
-
- if let None = self.tainted_by_errors() {
- // As a heuristic, just skip reporting region errors
- // altogether if other errors have been reported while
- // this infcx was in use. This is totally hokey but
- // otherwise we have a hard time separating legit region
- // errors from silly ones.
- self.report_region_errors(generic_param_scope, &errors);
- }
+ fn set_canonicalization_ctxt_to(&self, ctxt: bool) {
+ self.inside_canonicalization_ctxt.set(ctxt);
+ }
+}
- if errors.is_empty() {
- Ok(())
- } else {
- Err(self
- .tcx
- .sess
- .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"))
- }
+pub struct CanonicalizationCtxtGuard<'cx, 'tcx> {
+ prev_ctxt: bool,
+ infcx: &'cx InferCtxt<'tcx>,
+}
+
+impl<'cx, 'tcx> Drop for CanonicalizationCtxtGuard<'cx, 'tcx> {
+ fn drop(&mut self) {
+ self.infcx.set_canonicalization_ctxt_to(self.prev_ctxt)
}
+}
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// [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),
@@ -1770,7 +1717,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
-/// Helper for `ty_or_const_infer_var_changed` (see comment on that), currently
+/// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently
/// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
#[derive(Copy, Clone, Debug)]
pub enum TyOrConstInferVar<'tcx> {
@@ -2043,13 +1990,17 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Infer(_) = t.kind() {
+ let idx = {
+ let idx = self.idx;
+ self.idx += 1;
+ idx
+ };
self.tcx.mk_placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::ROOT,
- name: ty::BoundTyKind::Anon({
- let idx = self.idx;
- self.idx += 1;
- idx
- }),
+ bound: ty::BoundTy {
+ var: ty::BoundVar::from_u32(idx),
+ kind: ty::BoundTyKind::Anon,
+ },
})
} else {
t.super_fold_with(self)
@@ -2066,7 +2017,7 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
self.tcx.mk_const(
ty::PlaceholderConst {
universe: ty::UniverseIndex::ROOT,
- name: ty::BoundVar::from_u32({
+ bound: ty::BoundVar::from_u32({
let idx = self.idx;
self.idx += 1;
idx
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 573cd91a2..9f7b26b87 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -28,6 +28,7 @@ use crate::traits::{Obligation, PredicateObligations};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
@@ -55,21 +56,6 @@ where
ambient_variance: ty::Variance,
ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
-
- /// When we pass through a set of binders (e.g., when looking into
- /// a `fn` type), we push a new bound region scope onto here. This
- /// will contain the instantiated region for each region in those
- /// binders. When we then encounter a `ReLateBound(d, br)`, we can
- /// use the De Bruijn index `d` to find the right scope, and then
- /// bound region name `br` to find the specific instantiation from
- /// within that scope. See `replace_bound_region`.
- ///
- /// This field stores the instantiations for late-bound regions in
- /// the `a` type.
- a_scopes: Vec<BoundRegionScope<'tcx>>,
-
- /// Same as `a_scopes`, but for the `b` type.
- b_scopes: Vec<BoundRegionScope<'tcx>>,
}
pub trait TypeRelatingDelegate<'tcx> {
@@ -147,8 +133,6 @@ where
delegate,
ambient_variance,
ambient_variance_info: ty::VarianceDiagInfo::default(),
- a_scopes: vec![],
- b_scopes: vec![],
}
}
@@ -166,88 +150,6 @@ where
}
}
- fn create_scope(
- &mut self,
- value: ty::Binder<'tcx, impl Relate<'tcx>>,
- universally_quantified: UniversallyQuantified,
- ) -> BoundRegionScope<'tcx> {
- let mut scope = BoundRegionScope::default();
-
- // Create a callback that creates (via the delegate) either an
- // existential or placeholder region as needed.
- let mut next_region = {
- let delegate = &mut self.delegate;
- let mut lazy_universe = None;
- move |br: ty::BoundRegion| {
- if universally_quantified.0 {
- // The first time this closure is called, create a
- // new universe for the placeholders we will make
- // from here out.
- let universe = lazy_universe.unwrap_or_else(|| {
- let universe = delegate.create_next_universe();
- lazy_universe = Some(universe);
- universe
- });
-
- let placeholder = ty::PlaceholderRegion { universe, name: br.kind };
- delegate.next_placeholder_region(placeholder)
- } else {
- delegate.next_existential_region_var(true, br.kind.get_name())
- }
- }
- };
-
- value.skip_binder().visit_with(&mut ScopeInstantiator {
- next_region: &mut next_region,
- target_index: ty::INNERMOST,
- bound_region_scope: &mut scope,
- });
-
- scope
- }
-
- /// When we encounter binders during the type traversal, we record
- /// the value to substitute for each of the things contained in
- /// that binder. (This will be either a universal placeholder or
- /// an existential inference variable.) Given the De Bruijn index
- /// `debruijn` (and name `br`) of some binder we have now
- /// encountered, this routine finds the value that we instantiated
- /// the region with; to do so, it indexes backwards into the list
- /// of ambient scopes `scopes`.
- fn lookup_bound_region(
- debruijn: ty::DebruijnIndex,
- br: &ty::BoundRegion,
- first_free_index: ty::DebruijnIndex,
- scopes: &[BoundRegionScope<'tcx>],
- ) -> ty::Region<'tcx> {
- // The debruijn index is a "reverse index" into the
- // scopes listing. So when we have INNERMOST (0), we
- // want the *last* scope pushed, and so forth.
- let debruijn_index = debruijn.index() - first_free_index.index();
- let scope = &scopes[scopes.len() - debruijn_index - 1];
-
- // Find this bound region in that scope to map to a
- // particular region.
- scope.map[br]
- }
-
- /// If `r` is a bound region, find the scope in which it is bound
- /// (from `scopes`) and return the value that we instantiated it
- /// with. Otherwise just return `r`.
- fn replace_bound_region(
- &self,
- r: ty::Region<'tcx>,
- first_free_index: ty::DebruijnIndex,
- scopes: &[BoundRegionScope<'tcx>],
- ) -> ty::Region<'tcx> {
- debug!("replace_bound_regions(scopes={:?})", scopes);
- if let ty::ReLateBound(debruijn, br) = *r {
- Self::lookup_bound_region(debruijn, &br, first_free_index, scopes)
- } else {
- r
- }
- }
-
/// Push a new outlives requirement into our output set of
/// constraints.
fn push_outlives(
@@ -314,18 +216,9 @@ where
self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty);
- // The generalized values we extract from `canonical_var_values` have
- // been fully instantiated and hence the set of scopes we have
- // doesn't matter -- just to be sure, put an empty vector
- // in there.
- let old_a_scopes = std::mem::take(pair.vid_scopes(self));
-
// Relate the generalized kind to the original one.
let result = pair.relate_generalized_ty(self, generalized_ty);
- // Restore the old scopes now.
- *pair.vid_scopes(self) = old_a_scopes;
-
debug!("relate_ty_var: complete, result = {:?}", result);
result
}
@@ -379,6 +272,97 @@ where
trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
Ok(a)
}
+
+ #[instrument(skip(self), level = "debug")]
+ fn instantiate_binder_with_placeholders<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
+ where
+ T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
+ {
+ if let Some(inner) = binder.no_bound_vars() {
+ return inner;
+ }
+
+ let mut next_region = {
+ let nll_delegate = &mut self.delegate;
+ let mut lazy_universe = None;
+
+ move |br: ty::BoundRegion| {
+ // The first time this closure is called, create a
+ // new universe for the placeholders we will make
+ // from here out.
+ let universe = lazy_universe.unwrap_or_else(|| {
+ let universe = nll_delegate.create_next_universe();
+ lazy_universe = Some(universe);
+ universe
+ });
+
+ let placeholder = ty::PlaceholderRegion { universe, bound: br };
+ debug!(?placeholder);
+ let placeholder_reg = nll_delegate.next_placeholder_region(placeholder);
+ debug!(?placeholder_reg);
+
+ placeholder_reg
+ }
+ };
+
+ let delegate = FnMutDelegate {
+ regions: &mut next_region,
+ types: &mut |_bound_ty: ty::BoundTy| {
+ unreachable!("we only replace regions in nll_relate, not types")
+ },
+ consts: &mut |_bound_var: ty::BoundVar, _ty| {
+ unreachable!("we only replace regions in nll_relate, not consts")
+ },
+ };
+
+ let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
+ debug!(?replaced);
+
+ replaced
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
+ where
+ T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
+ {
+ if let Some(inner) = binder.no_bound_vars() {
+ return inner;
+ }
+
+ let mut next_region = {
+ let nll_delegate = &mut self.delegate;
+ let mut reg_map = FxHashMap::default();
+
+ move |br: ty::BoundRegion| {
+ if let Some(ex_reg_var) = reg_map.get(&br) {
+ return *ex_reg_var;
+ } else {
+ let ex_reg_var =
+ nll_delegate.next_existential_region_var(true, br.kind.get_name());
+ debug!(?ex_reg_var);
+ reg_map.insert(br, ex_reg_var);
+
+ ex_reg_var
+ }
+ }
+ };
+
+ let delegate = FnMutDelegate {
+ regions: &mut next_region,
+ types: &mut |_bound_ty: ty::BoundTy| {
+ unreachable!("we only replace regions in nll_relate, not types")
+ },
+ consts: &mut |_bound_var: ty::BoundVar, _ty| {
+ unreachable!("we only replace regions in nll_relate, not consts")
+ },
+ };
+
+ let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
+ debug!(?replaced);
+
+ replaced
+ }
}
/// When we instantiate an inference variable with a value in
@@ -396,14 +380,6 @@ trait VidValuePair<'tcx>: Debug {
/// opposite part of the tuple from the vid).
fn value_ty(&self) -> Ty<'tcx>;
- /// Extract the scopes that apply to whichever side of the tuple
- /// the vid was found on. See the comment where this is called
- /// for more details on why we want them.
- fn vid_scopes<'r, D: TypeRelatingDelegate<'tcx>>(
- &self,
- relate: &'r mut TypeRelating<'_, 'tcx, D>,
- ) -> &'r mut Vec<BoundRegionScope<'tcx>>;
-
/// Given a generalized type G that should replace the vid, relate
/// G to the value, putting G on whichever side the vid would have
/// appeared.
@@ -425,16 +401,6 @@ impl<'tcx> VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) {
self.1
}
- fn vid_scopes<'r, D>(
- &self,
- relate: &'r mut TypeRelating<'_, 'tcx, D>,
- ) -> &'r mut Vec<BoundRegionScope<'tcx>>
- where
- D: TypeRelatingDelegate<'tcx>,
- {
- &mut relate.a_scopes
- }
-
fn relate_generalized_ty<D>(
&self,
relate: &mut TypeRelating<'_, 'tcx, D>,
@@ -457,16 +423,6 @@ impl<'tcx> VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) {
self.0
}
- fn vid_scopes<'r, D>(
- &self,
- relate: &'r mut TypeRelating<'_, 'tcx, D>,
- ) -> &'r mut Vec<BoundRegionScope<'tcx>>
- where
- D: TypeRelatingDelegate<'tcx>,
- {
- &mut relate.b_scopes
- }
-
fn relate_generalized_ty<D>(
&self,
relate: &mut TypeRelating<'_, 'tcx, D>,
@@ -487,10 +443,6 @@ where
self.infcx.tcx
}
- fn intercrate(&self) -> bool {
- self.infcx.intercrate
- }
-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.delegate.param_env()
}
@@ -503,17 +455,6 @@ where
true
}
- fn mark_ambiguous(&mut self) {
- let cause = ObligationCause::dummy_with_span(self.delegate.span());
- let param_env = self.delegate.param_env();
- self.delegate.register_obligations(vec![Obligation::new(
- self.tcx(),
- cause,
- param_env,
- ty::Binder::dummy(ty::PredicateKind::Ambiguous),
- )]);
- }
-
#[instrument(skip(self, info), level = "trace", ret)]
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
@@ -602,20 +543,14 @@ where
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!(?self.ambient_variance);
- let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
- let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
-
- debug!(?v_a);
- debug!(?v_b);
-
if self.ambient_covariance() {
// Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
- self.push_outlives(v_a, v_b, self.ambient_variance_info);
+ self.push_outlives(a, b, self.ambient_variance_info);
}
if self.ambient_contravariance() {
// Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
- self.push_outlives(v_b, v_a, self.ambient_variance_info);
+ self.push_outlives(b, a, self.ambient_variance_info);
}
Ok(a)
@@ -689,15 +624,6 @@ where
// instantiation of B (i.e., B instantiated with
// universals).
- let b_scope = self.create_scope(b, UniversallyQuantified(true));
- let a_scope = self.create_scope(a, UniversallyQuantified(false));
-
- debug!(?a_scope, "(existential)");
- debug!(?b_scope, "(universal)");
-
- self.b_scopes.push(b_scope);
- self.a_scopes.push(a_scope);
-
// Reset the ambient variance to covariant. This is needed
// to correctly handle cases like
//
@@ -718,12 +644,14 @@ where
// subtyping (i.e., `&'b u32 <: &{P} u32`).
let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
- self.relate(a.skip_binder(), b.skip_binder())?;
+ // Note: the order here is important. Create the placeholders first, otherwise
+ // we assign the wrong universe to the existential!
+ let b_replaced = self.instantiate_binder_with_placeholders(b);
+ let a_replaced = self.instantiate_binder_with_existentials(a);
- self.ambient_variance = variance;
+ self.relate(a_replaced, b_replaced)?;
- self.b_scopes.pop().unwrap();
- self.a_scopes.pop().unwrap();
+ self.ambient_variance = variance;
}
if self.ambient_contravariance() {
@@ -733,26 +661,17 @@ where
// instantiation of B (i.e., B instantiated with
// existentials). Opposite of above.
- let a_scope = self.create_scope(a, UniversallyQuantified(true));
- let b_scope = self.create_scope(b, UniversallyQuantified(false));
-
- debug!(?a_scope, "(universal)");
- debug!(?b_scope, "(existential)");
-
- self.a_scopes.push(a_scope);
- self.b_scopes.push(b_scope);
-
// Reset ambient variance to contravariance. See the
// covariant case above for an explanation.
let variance =
std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
- self.relate(a.skip_binder(), b.skip_binder())?;
+ let a_replaced = self.instantiate_binder_with_placeholders(a);
+ let b_replaced = self.instantiate_binder_with_existentials(b);
- self.ambient_variance = variance;
+ self.relate(a_replaced, b_replaced)?;
- self.b_scopes.pop().unwrap();
- self.a_scopes.pop().unwrap();
+ self.ambient_variance = variance;
}
Ok(a)
@@ -777,6 +696,34 @@ where
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.delegate.register_obligations(obligations);
}
+
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+ unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance")
+ }
+
+ fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+ self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
+ ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
+ a.into(),
+ b.into(),
+ ty::AliasRelationDirection::Subtype,
+ ),
+ // a :> b is b <: a
+ ty::Variance::Contravariant => ty::PredicateKind::AliasRelate(
+ b.into(),
+ a.into(),
+ ty::AliasRelationDirection::Subtype,
+ ),
+ ty::Variance::Invariant => ty::PredicateKind::AliasRelate(
+ a.into(),
+ b.into(),
+ ty::AliasRelationDirection::Equate,
+ ),
+ // FIXME(deferred_projection_equality): Implement this when we trigger it.
+ // Probably just need to do nothing here.
+ ty::Variance::Bivariant => unreachable!(),
+ })]);
+ }
}
/// When we encounter a binder like `for<..> fn(..)`, we actually have
@@ -872,11 +819,6 @@ where
self.infcx.tcx
}
- fn intercrate(&self) -> bool {
- assert!(!self.infcx.intercrate);
- false
- }
-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.delegate.param_env()
}
@@ -889,10 +831,6 @@ where
true
}
- fn mark_ambiguous(&mut self) {
- bug!()
- }
-
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index d5c824d4c..3a0a0494a 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,11 +1,12 @@
+use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use super::{DefineOpaqueTypes, InferResult};
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::OpaqueTyOrigin;
+use rustc_data_structures::fx::FxIndexMap;
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};
@@ -16,18 +17,13 @@ use rustc_middle::ty::{
TypeVisitable, TypeVisitableExt, TypeVisitor,
};
use rustc_span::Span;
-
use std::ops::ControlFlow;
-pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
-
mod table;
+pub type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
-use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use super::InferResult;
-
/// Information about the opaque types whose values we
/// are inferring in this function (these are the `impl Trait` that
/// appear in the return type).
@@ -481,9 +477,7 @@ where
}
}
- ty::Alias(ty::Projection, proj)
- if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder =>
- {
+ ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => {
// Skip lifetime parameters that are not captures.
let variances = self.tcx.variances_of(proj.def_id);
@@ -547,8 +541,7 @@ impl<'tcx> InferCtxt<'tcx> {
if let Some(prev) = prev {
obligations = self
.at(&cause, param_env)
- .define_opaque_types(true)
- .eq_exp(a_is_expected, prev, hidden_ty)?
+ .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
.obligations;
}
@@ -563,8 +556,7 @@ impl<'tcx> InferCtxt<'tcx> {
// FIXME(RPITIT): Don't replace RPITITs with inference vars.
ty::Alias(ty::Projection, projection_ty)
if !projection_ty.has_escaping_bound_vars()
- && tcx.def_kind(projection_ty.def_id)
- != DefKind::ImplTraitPlaceholder =>
+ && !tcx.is_impl_trait_in_trait(projection_ty.def_id) =>
{
self.infer_projection(
param_env,
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 24e3c34dd..47e3dd762 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -1,9 +1,9 @@
use crate::infer::free_regions::FreeRegionMap;
-use crate::infer::{GenericKind, InferCtxt};
+use crate::infer::GenericKind;
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 rustc_middle::ty::{self, Region};
use super::explicit_outlives_bounds;
@@ -75,7 +75,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
region_bound_pairs: Default::default(),
};
- builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
+ builder.add_outlives_bounds(explicit_outlives_bounds(param_env));
builder
}
@@ -89,11 +89,10 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
/// 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.add_outlives_bounds(extra_bounds);
builder.build()
}
@@ -120,12 +119,7 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
}
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
- ///
- /// The `infcx` parameter is optional; if the implied bounds may
- /// contain inference variables, it must be supplied, in which
- /// case we will register "givens" on the inference context. (See
- /// `RegionConstraintData`.)
- fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I)
+ fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
where
I: IntoIterator<Item = OutlivesBound<'tcx>>,
{
@@ -142,27 +136,17 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
}
- OutlivesBound::RegionSubRegion(r_a, r_b) => {
- if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
- infcx
- .expect("no infcx provided but region vars found")
- .add_given(r_a, vid_b);
- } else {
- // In principle, we could record (and take
- // advantage of) every relationship here, but
- // we are also free not to -- it simply means
- // strictly less that we can successfully type
- // check. Right now we only look for things
- // relationships between free regions. (It may
- // also be that we should revise our inference
- // system to be more general and to make use
- // of *every* relationship that arises here,
- // but presently we do not.)
- if r_a.is_free_or_static() && r_b.is_free() {
- self.region_relation.add(r_a, r_b)
- }
- }
- }
+ OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) {
+ (
+ ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
+ ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
+ ) => self.region_relation.add(r_a, r_b),
+ (ty::ReError(_), _) | (_, ty::ReError(_)) => {}
+ // FIXME(#109628): We shouldn't have existential variables in implied bounds.
+ // Panic here once the linked issue is resolved!
+ (ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
+ _ => bug!("add_outlives_bounds: unexpected regions: ({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 83f3d5a74..9a9a1696b 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -1,4 +1,11 @@
//! Various code related to computing outlives relations.
+use self::env::OutlivesEnvironment;
+use super::region_constraints::RegionConstraintData;
+use super::{InferCtxt, RegionResolutionError};
+use crate::infer::free_regions::RegionRelations;
+use crate::infer::lexical_region_resolve::{self, LexicalRegionResolutions};
+use rustc_middle::traits::query::OutlivesBound;
+use rustc_middle::ty;
pub mod components;
pub mod env;
@@ -6,9 +13,6 @@ pub mod obligations;
pub mod test_type_match;
pub mod verify;
-use rustc_middle::traits::query::OutlivesBound;
-use rustc_middle::ty;
-
#[instrument(level = "debug", skip(param_env), ret)]
pub fn explicit_outlives_bounds<'tcx>(
param_env: ty::ParamEnv<'tcx>,
@@ -22,7 +26,7 @@ pub fn explicit_outlives_bounds<'tcx>(
ty::PredicateKind::Clause(ty::Clause::Projection(..))
| ty::PredicateKind::Clause(ty::Clause::Trait(..))
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
- | ty::PredicateKind::AliasEq(..)
+ | ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::WellFormed(..)
@@ -39,3 +43,98 @@ pub fn explicit_outlives_bounds<'tcx>(
))) => Some(OutlivesBound::RegionSubRegion(r_b, r_a)),
})
}
+
+impl<'tcx> InferCtxt<'tcx> {
+ pub fn skip_region_resolution(&self) {
+ let (var_infos, _) = {
+ let mut inner = self.inner.borrow_mut();
+ let inner = &mut *inner;
+ // Note: `inner.region_obligations` may not be empty, because we
+ // didn't necessarily call `process_registered_region_obligations`.
+ // This is okay, because that doesn't introduce new vars.
+ inner
+ .region_constraint_storage
+ .take()
+ .expect("regions already resolved")
+ .with_log(&mut inner.undo_log)
+ .into_infos_and_data()
+ };
+
+ let lexical_region_resolutions = LexicalRegionResolutions {
+ values: rustc_index::vec::IndexVec::from_elem_n(
+ crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
+ var_infos.len(),
+ ),
+ };
+
+ let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
+ assert!(old_value.is_none());
+ }
+
+ /// 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`.
+ #[must_use]
+ pub fn resolve_regions(
+ &self,
+ outlives_env: &OutlivesEnvironment<'tcx>,
+ ) -> Vec<RegionResolutionError<'tcx>> {
+ self.process_registered_region_obligations(outlives_env);
+
+ let (var_infos, data) = {
+ let mut inner = self.inner.borrow_mut();
+ let inner = &mut *inner;
+ assert!(
+ self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(),
+ "region_obligations not empty: {:#?}",
+ inner.region_obligations
+ );
+ inner
+ .region_constraint_storage
+ .take()
+ .expect("regions already resolved")
+ .with_log(&mut inner.undo_log)
+ .into_infos_and_data()
+ };
+
+ let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
+
+ let (lexical_region_resolutions, errors) =
+ lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
+
+ let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
+ assert!(old_value.is_none());
+
+ errors
+ }
+
+ /// Obtains (and clears) the current set of region
+ /// constraints. The inference context is still usable: further
+ /// unifications will simply add new constraints.
+ ///
+ /// This method is not meant to be used with normal lexical region
+ /// resolution. Rather, it is used in the NLL mode as a kind of
+ /// interim hack: basically we run normal type-check and generate
+ /// region constraints as normal, but then we take them and
+ /// translate them into the form that the NLL solver
+ /// understands. See the NLL module for mode details.
+ pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
+ assert!(
+ self.inner.borrow().region_obligations.is_empty(),
+ "region_obligations not empty: {:#?}",
+ self.inner.borrow().region_obligations
+ );
+
+ self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data()
+ }
+
+ /// Gives temporary access to the region constraint data.
+ pub fn with_region_constraints<R>(
+ &self,
+ op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
+ ) -> R {
+ let mut inner = self.inner.borrow_mut();
+ op(inner.unwrap_region_constraints().data())
+ }
+}
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index bbe7d4c63..ccf11c61b 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -72,6 +72,8 @@ use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitableExt};
use smallvec::smallvec;
+use super::env::OutlivesEnvironment;
+
impl<'tcx> InferCtxt<'tcx> {
/// Registers that the given region obligation must be resolved
/// from within the scope of `body_id`. These regions are enqueued
@@ -112,39 +114,17 @@ impl<'tcx> InferCtxt<'tcx> {
std::mem::take(&mut self.inner.borrow_mut().region_obligations)
}
- /// NOTE: Prefer using `TypeErrCtxt::check_region_obligations_and_report_errors`
- /// instead of calling this directly.
- ///
/// Process the region obligations that must be proven (during
/// `regionck`) for the given `body_id`, given information about
- /// the region bounds in scope and so forth. This function must be
- /// invoked for all relevant body-ids before region inference is
- /// done (or else an assert will fire).
+ /// the region bounds in scope and so forth.
///
/// See the `region_obligations` field of `InferCtxt` for some
/// comments about how this function fits into the overall expected
/// flow of the inferencer. The key point is that it is
/// invoked after all type-inference variables have been bound --
- /// towards the end of regionck. This also ensures that the
- /// region-bound-pairs are available (see comments above regarding
- /// closures).
- ///
- /// # Parameters
- ///
- /// - `region_bound_pairs_map`: the set of region bounds implied by
- /// the parameters and where-clauses. In particular, each pair
- /// `('a, K)` in this list tells us that the bounds in scope
- /// indicate that `K: 'a`, where `K` is either a generic
- /// parameter like `T` or a projection like `T::Item`.
- /// - `param_env` is the parameter environment for the enclosing function.
- /// - `body_id` is the body-id whose region obligations are being
- /// processed.
- #[instrument(level = "debug", skip(self, region_bound_pairs))]
- pub fn process_registered_region_obligations(
- &self,
- region_bound_pairs: &RegionBoundPairs<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ) {
+ /// right before lexical region resolution.
+ #[instrument(level = "debug", skip(self, outlives_env))]
+ pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) {
assert!(
!self.in_snapshot.get(),
"cannot process registered region obligations in a snapshot"
@@ -153,15 +133,16 @@ impl<'tcx> InferCtxt<'tcx> {
let my_region_obligations = self.take_registered_region_obligations();
for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
- debug!(
- "process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}",
- sup_type, sub_region, origin
- );
-
+ debug!(?sup_type, ?sub_region, ?origin);
let sup_type = self.resolve_vars_if_possible(sup_type);
- let outlives =
- &mut TypeOutlives::new(self, self.tcx, &region_bound_pairs, None, param_env);
+ let outlives = &mut TypeOutlives::new(
+ self,
+ self.tcx,
+ &outlives_env.region_bound_pairs(),
+ None,
+ outlives_env.param_env,
+ );
let category = origin.to_constraint_category();
outlives.type_must_outlive(origin, sup_type, sub_region, category);
}
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 3c6cc2b90..01f900f05 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -137,10 +137,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
"Match"
}
- fn intercrate(&self) -> bool {
- false
- }
-
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@@ -151,10 +147,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
true
} // irrelevant
- fn mark_ambiguous(&mut self) {
- bug!()
- }
-
#[instrument(level = "trace", skip(self))]
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index f79504770..fa6529dfa 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -26,7 +26,7 @@ impl<'tcx> InferCtxt<'tcx> {
// completely change the normalization routine with the new solver.
//
// The new solver correctly handles projection equality so this hack
- // is not necessary. if re-enabled it should emit `PredicateKind::AliasEq`
+ // is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate`
// not `PredicateKind::Clause(Clause::Projection(..))` as in the new solver
// `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`.
return projection_ty.to_ty(self.tcx);
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 e413b2bb5..b8ba98fc0 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -290,9 +290,9 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
) -> TypeError<'tcx> {
debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region);
if self.overly_polymorphic {
- TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region)
+ TypeError::RegionsOverlyPolymorphic(placeholder.bound.kind, other_region)
} else {
- TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region)
+ TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound.kind, other_region)
}
}
}
@@ -424,9 +424,6 @@ impl<'tcx> MiniGraph<'tcx> {
&AddConstraint(Constraint::RegSubReg(a, b)) => {
each_edge(a, b);
}
- &AddGiven(a, b) => {
- each_edge(a, tcx.mk_re_var(b));
- }
&AddVerify(i) => span_bug!(
verifys[i].origin.span(),
"we never add verifications while doing higher-ranked things",
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 872f61747..7b272dfd2 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -7,7 +7,7 @@ use super::{
InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
};
-use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
@@ -104,26 +104,6 @@ pub struct RegionConstraintData<'tcx> {
/// An example is a `A <= B` where neither `A` nor `B` are
/// inference variables.
pub verifys: Vec<Verify<'tcx>>,
-
- /// A "given" is a relationship that is known to hold. In
- /// particular, we often know from closure fn signatures that a
- /// particular free region must be a subregion of a region
- /// variable:
- ///
- /// foo.iter().filter(<'a> |x: &'a &'b T| ...)
- ///
- /// In situations like this, `'b` is in fact a region variable
- /// introduced by the call to `iter()`, and `'a` is a bound region
- /// on the closure (as indicated by the `<'a>` prefix). If we are
- /// naive, we wind up inferring that `'b` must be `'static`,
- /// because we require that it be greater than `'a` and we do not
- /// know what `'a` is precisely.
- ///
- /// This hashmap is used to avoid that naive scenario. Basically
- /// we record the fact that `'a <= 'b` is implied by the fn
- /// signature, and then ignore the constraint when solving
- /// equations. This is a bit of a hack but seems to work.
- pub givens: FxIndexSet<(Region<'tcx>, ty::RegionVid)>,
}
/// Represents a constraint that influences the inference process.
@@ -297,9 +277,6 @@ pub(crate) enum UndoLog<'tcx> {
/// We added the given `verify`.
AddVerify(usize),
- /// We added the given `given`.
- AddGiven(Region<'tcx>, ty::RegionVid),
-
/// We added a GLB/LUB "combination variable".
AddCombination(CombineMapType, TwoRegions<'tcx>),
}
@@ -348,9 +325,6 @@ impl<'tcx> RegionConstraintStorage<'tcx> {
self.data.verifys.pop();
assert_eq!(self.data.verifys.len(), index);
}
- AddGiven(sub, sup) => {
- self.data.givens.remove(&(sub, sup));
- }
AddCombination(Glb, ref regions) => {
self.glbs.remove(regions);
}
@@ -420,7 +394,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
// `RegionConstraintData` contains the relationship here.
if *any_unifications {
*any_unifications = false;
- self.unification_table().reset_unifications(|_| UnifiedRegion(None));
+ self.unification_table_mut().reset_unifications(|_| UnifiedRegion::new(None));
}
data
@@ -447,7 +421,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
) -> RegionVid {
let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
- let u_vid = self.unification_table().new_key(UnifiedRegion(None));
+ let u_vid = self.unification_table_mut().new_key(UnifiedRegion::new(None));
assert_eq!(vid, u_vid.vid);
self.undo_log.push(AddVar(vid));
debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin);
@@ -492,15 +466,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
self.undo_log.push(AddVerify(index));
}
- 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);
-
- self.undo_log.push(AddGiven(sub, sup));
- }
- }
-
pub(super) fn make_eqregion(
&mut self,
origin: SubregionOrigin<'tcx>,
@@ -516,13 +481,13 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
match (sub, sup) {
(Region(Interned(ReVar(sub), _)), Region(Interned(ReVar(sup), _))) => {
debug!("make_eqregion: unifying {:?} with {:?}", sub, sup);
- self.unification_table().union(*sub, *sup);
+ self.unification_table_mut().union(*sub, *sup);
self.any_unifications = true;
}
(Region(Interned(ReVar(vid), _)), value)
| (value, Region(Interned(ReVar(vid), _))) => {
debug!("make_eqregion: unifying {:?} with {:?}", vid, value);
- self.unification_table().union_value(*vid, UnifiedRegion(Some(value)));
+ self.unification_table_mut().union_value(*vid, UnifiedRegion::new(Some(value)));
self.any_unifications = true;
}
(_, _) => {}
@@ -633,28 +598,25 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
}
- /// Resolves the passed RegionVid to the root RegionVid in the unification table
- pub(super) fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid {
- self.unification_table().find(rid).vid
- }
-
- /// If the Region is a `ReVar`, then resolves it either to the root value in
- /// the unification table, if it exists, or to the root `ReVar` in the table.
- /// If the Region is not a `ReVar`, just returns the Region itself.
- pub fn opportunistic_resolve_region(
+ /// Resolves a region var to its value in the unification table, if it exists.
+ /// Otherwise, it is resolved to the root `ReVar` in the table.
+ pub fn opportunistic_resolve_var(
&mut self,
tcx: TyCtxt<'tcx>,
- region: ty::Region<'tcx>,
+ vid: ty::RegionVid,
) -> ty::Region<'tcx> {
- match *region {
- ty::ReVar(rid) => {
- let unified_region = self.unification_table().probe_value(rid);
- unified_region.0.unwrap_or_else(|| {
- let root = self.unification_table().find(rid).vid;
- tcx.mk_re_var(root)
- })
- }
- _ => region,
+ let mut ut = self.unification_table_mut(); // FIXME(rust-lang/ena#42): unnecessary mut
+ let root_vid = ut.find(vid).vid;
+ let resolved = ut
+ .probe_value(root_vid)
+ .get_value_ignoring_universes()
+ .unwrap_or_else(|| tcx.mk_re_var(root_vid));
+
+ // Don't resolve a variable to a region that it cannot name.
+ if self.var_universe(vid).can_name(self.universe(resolved)) {
+ resolved
+ } else {
+ tcx.mk_re_var(vid)
}
}
@@ -733,7 +695,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
#[inline]
- fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> {
+ fn unification_table_mut(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> {
ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log)
}
}
@@ -807,11 +769,8 @@ impl<'tcx> RegionConstraintData<'tcx> {
/// Returns `true` if this region constraint data contains no constraints, and `false`
/// otherwise.
pub fn is_empty(&self) -> bool {
- let RegionConstraintData { constraints, member_constraints, verifys, givens } = self;
- constraints.is_empty()
- && member_constraints.is_empty()
- && verifys.is_empty()
- && givens.is_empty()
+ let RegionConstraintData { constraints, member_constraints, verifys } = self;
+ constraints.is_empty() && member_constraints.is_empty() && verifys.is_empty()
}
}
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 5bb358329..4f49f4165 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -85,15 +85,12 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticRegionResolver<'a, 'tcx
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
- ty::ReVar(rid) => {
- let resolved = self
- .infcx
- .inner
- .borrow_mut()
- .unwrap_region_constraints()
- .opportunistic_resolve_var(rid);
- TypeFolder::interner(self).mk_re_var(resolved)
- }
+ ty::ReVar(vid) => self
+ .infcx
+ .inner
+ .borrow_mut()
+ .unwrap_region_constraints()
+ .opportunistic_resolve_var(TypeFolder::interner(self), vid),
_ => r,
}
}
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 3e8c2052d..0dd73a6e9 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -1,5 +1,5 @@
use super::combine::{CombineFields, RelationDir};
-use super::{ObligationEmittingRelation, SubregionOrigin};
+use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin};
use crate::traits::{Obligation, PredicateObligations};
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
@@ -35,10 +35,6 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
"Sub"
}
- fn intercrate(&self) -> bool {
- self.fields.infcx.intercrate
- }
-
fn tcx(&self) -> TyCtxt<'tcx> {
self.fields.infcx.tcx
}
@@ -51,10 +47,6 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
self.a_is_expected
}
- fn mark_ambiguous(&mut self) {
- self.fields.mark_ambiguous()
- }
-
fn with_cause<F, R>(&mut self, cause: Cause, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
@@ -138,7 +130,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
}
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
- if self.fields.define_opaque_types && def_id.is_local() =>
+ if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
+ && def_id.is_local() =>
{
self.fields.obligations.extend(
infcx
@@ -235,4 +228,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.fields.register_obligations(obligations);
}
+
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+ ty::AliasRelationDirection::Subtype
+ }
}
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 263c6a47d..f7ab05b2d 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -190,6 +190,11 @@ impl<'tcx> TypeVariableStorage<'tcx> {
) -> TypeVariableTable<'a, 'tcx> {
TypeVariableTable { storage: self, undo_log }
}
+
+ #[inline]
+ pub(crate) fn eq_relations_ref(&self) -> &ut::UnificationTableStorage<TyVidEqKey<'tcx>> {
+ &self.eq_relations
+ }
}
impl<'tcx> TypeVariableTable<'_, 'tcx> {
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index bdc313c21..738a12376 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -41,4 +41,4 @@ mod errors;
pub mod infer;
pub mod traits;
-fluent_messages! { "../locales/en-US.ftl" }
+fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index f75344f20..b8940e2f0 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -36,9 +36,10 @@ pub trait TraitEngine<'tcx>: 'tcx {
obligation: PredicateObligation<'tcx>,
);
+ #[must_use]
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
- fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>>;
+ fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
@@ -58,6 +59,7 @@ pub trait TraitEngineExt<'tcx> {
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
);
+ #[must_use]
fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
}
@@ -78,6 +80,6 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
return errors;
}
- self.collect_remaining_errors()
+ self.collect_remaining_errors(infcx)
}
}
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 3a8289966..e01b6caf4 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -8,6 +8,8 @@ mod project;
mod structural_impls;
pub mod util;
+use std::cmp;
+
use hir::def_id::LocalDefId;
use rustc_hir as hir;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -53,6 +55,12 @@ pub struct Obligation<'tcx, T> {
pub recursion_depth: usize,
}
+impl<'tcx, P> From<Obligation<'tcx, P>> for solve::Goal<'tcx, P> {
+ fn from(value: Obligation<'tcx, P>) -> Self {
+ solve::Goal { param_env: value.param_env, predicate: value.predicate }
+ }
+}
+
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
@@ -120,7 +128,11 @@ pub enum FulfillmentErrorCode<'tcx> {
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
CodeConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
- CodeAmbiguity,
+ CodeAmbiguity {
+ /// Overflow reported from the new solver `-Ztrait-solver=next`, which will
+ /// be reported as an regular error as opposed to a fatal error.
+ overflow: bool,
+ },
}
impl<'tcx, O> Obligation<'tcx, O> {
@@ -133,6 +145,14 @@ impl<'tcx, O> Obligation<'tcx, O> {
Self::with_depth(tcx, cause, 0, param_env, predicate)
}
+ /// We often create nested obligations without setting the correct depth.
+ ///
+ /// To deal with this evaluate and fulfill explicitly update the depth
+ /// of nested obligations using this function.
+ pub fn set_depth_from_parent(&mut self, parent_depth: usize) {
+ self.recursion_depth = cmp::max(parent_depth + 1, self.recursion_depth);
+ }
+
pub fn with_depth(
tcx: TyCtxt<'tcx>,
cause: ObligationCause<'tcx>,
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 3a5273b03..1563d92af 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -46,7 +46,8 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
super::CodeConstEquateError(ref a, ref b) => {
write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
}
- super::CodeAmbiguity => write!(f, "Ambiguity"),
+ super::CodeAmbiguity { overflow: false } => write!(f, "Ambiguity"),
+ super::CodeAmbiguity { overflow: true } => write!(f, "Overflow"),
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 c07ff5165..ef01d5d51 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -1,7 +1,7 @@
use smallvec::smallvec;
use crate::infer::outlives::components::{push_outlives_components, Component};
-use crate::traits::{self, Obligation, ObligationCause, PredicateObligation};
+use crate::traits::{self, Obligation, PredicateObligation};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_middle::ty::{self, ToPredicate, TyCtxt};
use rustc_span::symbol::Ident;
@@ -66,93 +66,146 @@ impl<'tcx> Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
/// `T: Foo`, then we know that `T: 'static`.
-pub struct Elaborator<'tcx> {
- stack: Vec<PredicateObligation<'tcx>>,
+pub struct Elaborator<'tcx, O> {
+ stack: Vec<O>,
visited: PredicateSet<'tcx>,
+ only_self: bool,
}
-pub fn elaborate_trait_ref<'tcx>(
- tcx: TyCtxt<'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>,
-) -> Elaborator<'tcx> {
- elaborate_predicates(tcx, std::iter::once(trait_ref.without_const().to_predicate(tcx)))
+/// Describes how to elaborate an obligation into a sub-obligation.
+///
+/// For [`Obligation`], a sub-obligation is combined with the current obligation's
+/// param-env and cause code. For [`ty::Predicate`], none of this is needed, since
+/// there is no param-env or cause code to copy over.
+pub trait Elaboratable<'tcx> {
+ fn predicate(&self) -> ty::Predicate<'tcx>;
+
+ // Makes a new `Self` but with a different predicate.
+ fn child(&self, predicate: ty::Predicate<'tcx>) -> Self;
+
+ // Makes a new `Self` but with a different predicate and a different cause
+ // code (if `Self` has one).
+ fn child_with_derived_cause(
+ &self,
+ predicate: ty::Predicate<'tcx>,
+ span: Span,
+ parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+ index: usize,
+ ) -> Self;
}
-pub fn elaborate_trait_refs<'tcx>(
- tcx: TyCtxt<'tcx>,
- trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
-) -> Elaborator<'tcx> {
- let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate(tcx));
- elaborate_predicates(tcx, predicates)
+impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> {
+ fn predicate(&self) -> ty::Predicate<'tcx> {
+ self.predicate
+ }
+
+ fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
+ Obligation {
+ cause: self.cause.clone(),
+ param_env: self.param_env,
+ recursion_depth: 0,
+ predicate,
+ }
+ }
+
+ fn child_with_derived_cause(
+ &self,
+ predicate: ty::Predicate<'tcx>,
+ span: Span,
+ parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+ index: usize,
+ ) -> Self {
+ let cause = self.cause.clone().derived_cause(parent_trait_pred, |derived| {
+ traits::ImplDerivedObligation(Box::new(traits::ImplDerivedObligationCause {
+ derived,
+ impl_or_alias_def_id: parent_trait_pred.def_id(),
+ impl_def_predicate_index: Some(index),
+ span,
+ }))
+ });
+ Obligation { cause, param_env: self.param_env, recursion_depth: 0, predicate }
+ }
}
-pub fn elaborate_predicates<'tcx>(
- tcx: TyCtxt<'tcx>,
- predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
-) -> Elaborator<'tcx> {
- let obligations = predicates
- .map(|predicate| {
- predicate_obligation(predicate, ty::ParamEnv::empty(), ObligationCause::dummy())
- })
- .collect();
- elaborate_obligations(tcx, obligations)
+impl<'tcx> Elaboratable<'tcx> for ty::Predicate<'tcx> {
+ fn predicate(&self) -> ty::Predicate<'tcx> {
+ *self
+ }
+
+ fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
+ predicate
+ }
+
+ fn child_with_derived_cause(
+ &self,
+ predicate: ty::Predicate<'tcx>,
+ _span: Span,
+ _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+ _index: usize,
+ ) -> Self {
+ predicate
+ }
}
-pub fn elaborate_predicates_with_span<'tcx>(
- tcx: TyCtxt<'tcx>,
- predicates: impl Iterator<Item = (ty::Predicate<'tcx>, Span)>,
-) -> Elaborator<'tcx> {
- let obligations = predicates
- .map(|(predicate, span)| {
- predicate_obligation(
- predicate,
- ty::ParamEnv::empty(),
- ObligationCause::dummy_with_span(span),
- )
- })
- .collect();
- elaborate_obligations(tcx, obligations)
+impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) {
+ fn predicate(&self) -> ty::Predicate<'tcx> {
+ self.0
+ }
+
+ fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
+ (predicate, self.1)
+ }
+
+ fn child_with_derived_cause(
+ &self,
+ predicate: ty::Predicate<'tcx>,
+ _span: Span,
+ _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+ _index: usize,
+ ) -> Self {
+ (predicate, self.1)
+ }
}
-pub fn elaborate_obligations<'tcx>(
+pub fn elaborate<'tcx, O: Elaboratable<'tcx>>(
tcx: TyCtxt<'tcx>,
- obligations: Vec<PredicateObligation<'tcx>>,
-) -> Elaborator<'tcx> {
- let mut elaborator = Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx) };
+ obligations: impl IntoIterator<Item = O>,
+) -> Elaborator<'tcx, O> {
+ let mut elaborator =
+ Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), only_self: false };
elaborator.extend_deduped(obligations);
elaborator
}
-fn predicate_obligation<'tcx>(
- predicate: ty::Predicate<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- cause: ObligationCause<'tcx>,
-) -> PredicateObligation<'tcx> {
- Obligation { cause, param_env, recursion_depth: 0, predicate }
-}
-
-impl<'tcx> Elaborator<'tcx> {
- fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>) {
+impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
+ fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = O>) {
// Only keep those bounds that we haven't already seen.
// This is necessary to prevent infinite recursion in some
// cases. One common case is when people define
// `trait Sized: Sized { }` rather than `trait Sized { }`.
// let visited = &mut self.visited;
- self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate)));
+ self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate())));
}
- pub fn filter_to_traits(self) -> FilterToTraits<Self> {
- FilterToTraits::new(self)
+ /// Filter to only the supertraits of trait predicates, i.e. only the predicates
+ /// that have `Self` as their self type, instead of all implied predicates.
+ pub fn filter_only_self(mut self) -> Self {
+ self.only_self = true;
+ self
}
- fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
+ fn elaborate(&mut self, elaboratable: &O) {
let tcx = self.visited.tcx;
- let bound_predicate = obligation.predicate.kind();
+ let bound_predicate = elaboratable.predicate().kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
- // Get predicates declared on the trait.
- let predicates = tcx.super_predicates_of(data.def_id());
+ // Get predicates implied by the trait, or only super predicates if we only care about self predicates.
+ let predicates = if self.only_self {
+ tcx.super_predicates_of(data.def_id())
+ } else {
+ tcx.implied_predicates_of(data.def_id())
+ };
let obligations =
predicates.predicates.iter().enumerate().map(|(index, &(mut pred, span))| {
@@ -160,24 +213,11 @@ impl<'tcx> Elaborator<'tcx> {
if data.constness == ty::BoundConstness::NotConst {
pred = pred.without_const(tcx);
}
-
- let cause = obligation.cause.clone().derived_cause(
- bound_predicate.rebind(data),
- |derived| {
- traits::ImplDerivedObligation(Box::new(
- traits::ImplDerivedObligationCause {
- derived,
- impl_or_alias_def_id: data.def_id(),
- impl_def_predicate_index: Some(index),
- span,
- },
- ))
- },
- );
- predicate_obligation(
+ elaboratable.child_with_derived_cause(
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
- obligation.param_env,
- cause,
+ span,
+ bound_predicate.rebind(data),
+ index,
)
});
debug!(?data, ?obligations, "super_predicates");
@@ -280,20 +320,14 @@ impl<'tcx> Elaborator<'tcx> {
.map(|predicate_kind| {
bound_predicate.rebind(predicate_kind).to_predicate(tcx)
})
- .map(|predicate| {
- predicate_obligation(
- predicate,
- obligation.param_env,
- obligation.cause.clone(),
- )
- }),
+ .map(|predicate| elaboratable.child(predicate)),
);
}
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
// Nothing to elaborate
}
ty::PredicateKind::Ambiguous => {}
- ty::PredicateKind::AliasEq(..) => {
+ ty::PredicateKind::AliasRelate(..) => {
// No
}
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => {
@@ -303,8 +337,8 @@ impl<'tcx> Elaborator<'tcx> {
}
}
-impl<'tcx> Iterator for Elaborator<'tcx> {
- type Item = PredicateObligation<'tcx>;
+impl<'tcx, O: Elaboratable<'tcx>> Iterator for Elaborator<'tcx, O> {
+ type Item = O;
fn size_hint(&self) -> (usize, Option<usize>) {
(self.stack.len(), None)
@@ -325,23 +359,23 @@ impl<'tcx> Iterator for Elaborator<'tcx> {
// Supertrait iterator
///////////////////////////////////////////////////////////////////////////
-pub type Supertraits<'tcx> = FilterToTraits<Elaborator<'tcx>>;
-
pub fn supertraits<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
-) -> Supertraits<'tcx> {
- elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
+) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
+ elaborate(tcx, [trait_ref.to_predicate(tcx)]).filter_only_self().filter_to_traits()
}
pub fn transitive_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
- bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
-) -> Supertraits<'tcx> {
- elaborate_trait_refs(tcx, bounds).filter_to_traits()
+ trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
+) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
+ elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
+ .filter_only_self()
+ .filter_to_traits()
}
-/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may
+/// A specialized variant of `elaborate` that only elaborates trait references that may
/// define the given associated type `assoc_name`. It uses the
/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that
/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or
@@ -358,10 +392,8 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
while let Some(trait_ref) = stack.pop() {
let anon_trait_ref = tcx.anonymize_bound_vars(trait_ref);
if visited.insert(anon_trait_ref) {
- let super_predicates = tcx.super_predicates_that_define_assoc_type((
- trait_ref.def_id(),
- Some(assoc_name),
- ));
+ let super_predicates =
+ tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), assoc_name));
for (super_predicate, _) in super_predicates.predicates {
let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() {
@@ -381,24 +413,24 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
// Other
///////////////////////////////////////////////////////////////////////////
+impl<'tcx> Elaborator<'tcx, ty::Predicate<'tcx>> {
+ fn filter_to_traits(self) -> FilterToTraits<Self> {
+ FilterToTraits { base_iterator: self }
+ }
+}
+
/// A filter around an iterator of predicates that makes it yield up
/// just trait references.
pub struct FilterToTraits<I> {
base_iterator: I,
}
-impl<I> FilterToTraits<I> {
- fn new(base: I) -> FilterToTraits<I> {
- FilterToTraits { base_iterator: base }
- }
-}
-
-impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToTraits<I> {
+impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
type Item = ty::PolyTraitRef<'tcx>;
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
- while let Some(obligation) = self.base_iterator.next() {
- if let Some(data) = obligation.predicate.to_opt_poly_trait_pred() {
+ while let Some(pred) = self.base_iterator.next() {
+ if let Some(data) = pred.to_opt_poly_trait_pred() {
return Some(data.map_bound(|t| t.trait_ref));
}
}