diff options
Diffstat (limited to 'compiler/rustc_infer/src')
42 files changed, 1247 insertions, 1830 deletions
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index aee99063e03..f29ba70be98 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1,7 +1,8 @@ use hir::GenericParamKind; use rustc_errors::{ - AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString, - IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage, + codes::*, AddToDiagnostic, Applicability, DiagnosticBuilder, DiagnosticMessage, + DiagnosticStyledString, EmissionGuarantee, IntoDiagnosticArg, MultiSpan, + SubdiagnosticMessageOp, }; use rustc_hir as hir; use rustc_hir::FnRetTy; @@ -33,7 +34,7 @@ pub struct OpaqueHiddenTypeDiag { } #[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = "E0282")] +#[diag(infer_type_annotations_needed, code = E0282)] pub struct AnnotationRequired<'a> { #[primary_span] pub span: Span, @@ -51,7 +52,7 @@ pub struct AnnotationRequired<'a> { // Copy of `AnnotationRequired` for E0283 #[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = "E0283")] +#[diag(infer_type_annotations_needed, code = E0283)] pub struct AmbiguousImpl<'a> { #[primary_span] pub span: Span, @@ -69,7 +70,7 @@ pub struct AmbiguousImpl<'a> { // Copy of `AnnotationRequired` for E0284 #[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = "E0284")] +#[diag(infer_type_annotations_needed, code = E0284)] pub struct AmbiguousReturn<'a> { #[primary_span] pub span: Span, @@ -225,10 +226,11 @@ pub enum RegionOriginNote<'a> { } impl AddToDiagnostic for RegionOriginNote<'_> { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { let mut label_or_note = |span, msg: DiagnosticMessage| { let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); @@ -289,10 +291,11 @@ pub enum LifetimeMismatchLabels { } impl AddToDiagnostic for LifetimeMismatchLabels { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { match self { LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { diag.span_label(param_span, fluent::infer_declared_different); @@ -336,10 +339,11 @@ pub struct AddLifetimeParamsSuggestion<'a> { } impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { let mut mk_suggestion = || { let ( hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. }, @@ -421,7 +425,7 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> { } #[derive(Diagnostic)] -#[diag(infer_lifetime_mismatch, code = "E0623")] +#[diag(infer_lifetime_mismatch, code = E0623)] pub struct LifetimeMismatch<'a> { #[primary_span] pub span: Span, @@ -437,10 +441,11 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq { } impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { - fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>( + mut self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { self.unmet_requirements .push_span_label(self.binding_span, fluent::infer_msl_introduces_static); diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req); @@ -495,7 +500,7 @@ pub struct MismatchedStaticLifetime<'a> { #[derive(Diagnostic)] pub enum ExplicitLifetimeRequired<'a> { - #[diag(infer_explicit_lifetime_required_with_ident, code = "E0621")] + #[diag(infer_explicit_lifetime_required_with_ident, code = E0621)] WithIdent { #[primary_span] #[label] @@ -511,7 +516,7 @@ pub enum ExplicitLifetimeRequired<'a> { #[skip_arg] new_ty: Ty<'a>, }, - #[diag(infer_explicit_lifetime_required_with_param_type, code = "E0621")] + #[diag(infer_explicit_lifetime_required_with_param_type, code = E0621)] WithParamType { #[primary_span] #[label] @@ -534,7 +539,7 @@ pub enum TyOrSig<'tcx> { } impl IntoDiagnosticArg for TyOrSig<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { match self { TyOrSig::Ty(ty) => ty.into_diagnostic_arg(), TyOrSig::ClosureSig(sig) => sig.into_diagnostic_arg(), @@ -755,10 +760,11 @@ pub struct ConsiderBorrowingParamHelp { } impl AddToDiagnostic for ConsiderBorrowingParamHelp { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { // Seems like we can't call f() here as Into<DiagnosticMessage> is required @@ -799,10 +805,11 @@ pub struct DynTraitConstraintSuggestion { } impl AddToDiagnostic for DynTraitConstraintSuggestion { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { let mut multi_span: MultiSpan = vec![self.span].into(); multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label); multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement); @@ -819,7 +826,7 @@ impl AddToDiagnostic for DynTraitConstraintSuggestion { } #[derive(Diagnostic)] -#[diag(infer_but_calling_introduces, code = "E0772")] +#[diag(infer_but_calling_introduces, code = E0772)] pub struct ButCallingIntroduces { #[label(infer_label1)] pub param_ty_span: Span, @@ -845,10 +852,11 @@ pub struct ReqIntroducedLocations { } impl AddToDiagnostic for ReqIntroducedLocations { - fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>( + mut self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { for sp in self.spans { self.span.push_span_label(sp, fluent::infer_ril_introduced_here); } @@ -867,18 +875,19 @@ pub struct MoreTargeted { } impl AddToDiagnostic for MoreTargeted { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - diag.code(rustc_errors::error_code!(E0772)); + fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { + diag.code(E0772); diag.primary_message(fluent::infer_more_targeted); diag.arg("ident", self.ident); } } #[derive(Diagnostic)] -#[diag(infer_but_needs_to_satisfy, code = "E0759")] +#[diag(infer_but_needs_to_satisfy, code = E0759)] pub struct ButNeedsToSatisfy { #[primary_span] pub sp: Span, @@ -904,7 +913,7 @@ pub struct ButNeedsToSatisfy { } #[derive(Diagnostic)] -#[diag(infer_outlives_content, code = "E0312")] +#[diag(infer_outlives_content, code = E0312)] pub struct OutlivesContent<'a> { #[primary_span] pub span: Span, @@ -913,7 +922,7 @@ pub struct OutlivesContent<'a> { } #[derive(Diagnostic)] -#[diag(infer_outlives_bound, code = "E0476")] +#[diag(infer_outlives_bound, code = E0476)] pub struct OutlivesBound<'a> { #[primary_span] pub span: Span, @@ -922,7 +931,7 @@ pub struct OutlivesBound<'a> { } #[derive(Diagnostic)] -#[diag(infer_fulfill_req_lifetime, code = "E0477")] +#[diag(infer_fulfill_req_lifetime, code = E0477)] pub struct FulfillReqLifetime<'a> { #[primary_span] pub span: Span, @@ -932,7 +941,7 @@ pub struct FulfillReqLifetime<'a> { } #[derive(Diagnostic)] -#[diag(infer_lf_bound_not_satisfied, code = "E0478")] +#[diag(infer_lf_bound_not_satisfied, code = E0478)] pub struct LfBoundNotSatisfied<'a> { #[primary_span] pub span: Span, @@ -941,7 +950,7 @@ pub struct LfBoundNotSatisfied<'a> { } #[derive(Diagnostic)] -#[diag(infer_ref_longer_than_data, code = "E0491")] +#[diag(infer_ref_longer_than_data, code = E0491)] pub struct RefLongerThanData<'a> { #[primary_span] pub span: Span, @@ -1117,7 +1126,7 @@ pub enum PlaceholderRelationLfNotSatisfied { } #[derive(Diagnostic)] -#[diag(infer_opaque_captures_lifetime, code = "E0700")] +#[diag(infer_opaque_captures_lifetime, code = E0700)] pub struct OpaqueCapturesLifetime<'tcx> { #[primary_span] pub span: Span, @@ -1289,10 +1298,11 @@ pub struct SuggestTuplePatternMany { } 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, - { + fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { diag.arg("path", self.path); let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into()); diag.multipart_suggestions( @@ -1378,73 +1388,73 @@ pub enum TypeErrorAdditionalDiags { #[derive(Diagnostic)] pub enum ObligationCauseFailureCode { - #[diag(infer_oc_method_compat, code = "E0308")] + #[diag(infer_oc_method_compat, code = E0308)] MethodCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_type_compat, code = "E0308")] + #[diag(infer_oc_type_compat, code = E0308)] TypeCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_const_compat, code = "E0308")] + #[diag(infer_oc_const_compat, code = E0308)] ConstCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_try_compat, code = "E0308")] + #[diag(infer_oc_try_compat, code = E0308)] TryCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_match_compat, code = "E0308")] + #[diag(infer_oc_match_compat, code = E0308)] MatchCompat { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_if_else_different, code = "E0308")] + #[diag(infer_oc_if_else_different, code = E0308)] IfElseDifferent { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_no_else, code = "E0317")] + #[diag(infer_oc_no_else, code = E0317)] NoElse { #[primary_span] span: Span, }, - #[diag(infer_oc_no_diverge, code = "E0308")] + #[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")] + #[diag(infer_oc_fn_main_correct_type, code = E0580)] FnMainCorrectType { #[primary_span] span: Span, }, - #[diag(infer_oc_fn_start_correct_type, code = "E0308")] + #[diag(infer_oc_fn_start_correct_type, code = E0308)] FnStartCorrectType { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_fn_lang_correct_type, code = "E0308")] + #[diag(infer_oc_fn_lang_correct_type, code = E0308)] FnLangCorrectType { #[primary_span] span: Span, @@ -1452,33 +1462,33 @@ pub enum ObligationCauseFailureCode { subdiags: Vec<TypeErrorAdditionalDiags>, lang_item_name: Symbol, }, - #[diag(infer_oc_intrinsic_correct_type, code = "E0308")] + #[diag(infer_oc_intrinsic_correct_type, code = E0308)] IntrinsicCorrectType { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_method_correct_type, code = "E0308")] + #[diag(infer_oc_method_correct_type, code = E0308)] MethodCorrectType { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_closure_selfref, code = "E0644")] + #[diag(infer_oc_closure_selfref, code = E0644)] ClosureSelfref { #[primary_span] span: Span, }, - #[diag(infer_oc_cant_coerce, code = "E0308")] + #[diag(infer_oc_cant_coerce, code = E0308)] CantCoerce { #[primary_span] span: Span, #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_generic, code = "E0308")] + #[diag(infer_oc_generic, code = E0308)] Generic { #[primary_span] span: Span, diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 8e45cc6d80e..c272aa63b08 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -1,6 +1,9 @@ use crate::fluent_generated as fluent; use crate::infer::error_reporting::nice_region_error::find_anon_type; -use rustc_errors::{AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessage}; +use rustc_errors::{ + AddToDiagnostic, DiagnosticBuilder, EmissionGuarantee, IntoDiagnosticArg, + SubdiagnosticMessageOp, +}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{symbol::kw, Span}; @@ -108,7 +111,7 @@ pub enum SuffixKind { } impl IntoDiagnosticArg for PrefixKind { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { let kind = match self { Self::Empty => "empty", Self::RefValidFor => "ref_valid_for", @@ -130,7 +133,7 @@ impl IntoDiagnosticArg for PrefixKind { } impl IntoDiagnosticArg for SuffixKind { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { let kind = match self { Self::Empty => "empty", Self::Continues => "continues", @@ -160,10 +163,11 @@ impl RegionExplanation<'_> { } impl AddToDiagnostic for RegionExplanation<'_> { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { diag.arg("pref_kind", self.prefix); diag.arg("suff_kind", self.suffix); diag.arg("desc_kind", self.desc.kind); diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index e60e3ffeaa7..05b9479c7b0 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -87,9 +87,11 @@ impl<'tcx> InferCtxt<'tcx> { reported_signature_mismatch: self.reported_signature_mismatch.clone(), tainted_by_errors: self.tainted_by_errors.clone(), err_count_on_creation: self.err_count_on_creation, + stashed_err_count_on_creation: self.stashed_err_count_on_creation, universe: self.universe.clone(), intercrate, next_trait_solver: self.next_trait_solver, + obligation_inspector: self.obligation_inspector.clone(), } } } @@ -283,13 +285,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { 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, define_opaque_types); - fields - .sub(a_is_expected) - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - }) + let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); + fields + .sub(a_is_expected) + .relate(a, b) + .map(move |_| InferOk { value: (), obligations: fields.obligations }) } /// Makes `a == b`; the expectation is set by the call to @@ -300,13 +300,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { 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, define_opaque_types); - fields - .equate(a_is_expected) - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - }) + let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); + fields + .equate(a_is_expected) + .relate(a, b) + .map(move |_| InferOk { value: (), obligations: fields.obligations }) } #[instrument(skip(self), level = "debug")] @@ -315,13 +313,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { 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, define_opaque_types); - fields - .lub(a_is_expected) - .relate(a, b) - .map(move |t| InferOk { value: t, obligations: fields.obligations }) - }) + let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); + fields + .lub(a_is_expected) + .relate(a, b) + .map(move |t| InferOk { value: t, obligations: fields.obligations }) } #[instrument(skip(self), level = "debug")] @@ -330,13 +326,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { 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, define_opaque_types); - fields - .glb(a_is_expected) - .relate(a, b) - .map(move |t| InferOk { value: t, obligations: fields.obligations }) - }) + let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); + fields + .glb(a_is_expected) + .relate(a, b) + .map(move |t| InferOk { value: t, obligations: fields.obligations }) } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index e4b37f05b77..99882a42abc 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -191,7 +191,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { // // rust-lang/rust#57464: `impl Trait` can leak local // scopes (in manner violating typeck). Therefore, use - // `span_delayed_bug` to allow type error over an ICE. + // `delayed_bug` to allow type error over an ICE. canonicalizer .tcx .dcx() @@ -414,6 +414,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { } ty::Closure(..) + | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Bool @@ -480,7 +481,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { } ty::ConstKind::Infer(InferConst::EffectVar(vid)) => { match self.infcx.unwrap().probe_effect_var(vid) { - Some(value) => return self.fold_const(value.as_const(self.tcx)), + Some(value) => return self.fold_const(value), None => { return self.canonicalize_const_var( CanonicalVarInfo { kind: CanonicalVarKind::Effect }, diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index e0b97bb160c..c8adbf7f57a 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -1,4 +1,4 @@ -//! This module contains code to substitute new values into a +//! This module contains code to instantiate new values into a //! `Canonical<'tcx, T>`. //! //! For an overview of what canonicalization is and how it fits into @@ -13,38 +13,24 @@ use rustc_middle::ty::{self, TyCtxt}; /// FIXME(-Znext-solver): This or public because it is shared with the /// new trait solver implementation. We should deduplicate canonicalization. -pub trait CanonicalExt<'tcx, V> { +#[extension(pub trait CanonicalExt<'tcx, V>)] +impl<'tcx, V> Canonical<'tcx, V> { /// Instantiate the wrapped value, replacing each canonical value /// with the value given in `var_values`. - fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V + fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V where - V: TypeFoldable<TyCtxt<'tcx>>; + V: TypeFoldable<TyCtxt<'tcx>>, + { + self.instantiate_projected(tcx, var_values, |value| value.clone()) + } - /// Allows one to apply a substitute to some subset of + /// Allows one to apply a instantiation to some subset of /// `self.value`. Invoke `projection_fn` with `self.value` to get /// a value V that is expressed in terms of the same canonical /// variables bound in `self` (usually this extracts from subset - /// of `self`). Apply the substitution `var_values` to this value + /// of `self`). Apply the instantiation `var_values` to this value /// V, replacing each of the canonical variables. - fn substitute_projected<T>( - &self, - tcx: TyCtxt<'tcx>, - var_values: &CanonicalVarValues<'tcx>, - projection_fn: impl FnOnce(&V) -> T, - ) -> T - where - T: TypeFoldable<TyCtxt<'tcx>>; -} - -impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { - fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V - where - V: TypeFoldable<TyCtxt<'tcx>>, - { - self.substitute_projected(tcx, var_values, |value| value.clone()) - } - - fn substitute_projected<T>( + fn instantiate_projected<T>( &self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, @@ -55,14 +41,14 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { { assert_eq!(self.variables.len(), var_values.len()); let value = projection_fn(&self.value); - substitute_value(tcx, var_values, value) + instantiate_value(tcx, var_values, value) } } -/// Substitute the values from `var_values` into `value`. `var_values` +/// Instantiate the values from `var_values` into `value`. `var_values` /// must be values for the set of canonical variables that appear in /// `value`. -pub(super) fn substitute_value<'tcx, T>( +pub(super) fn instantiate_value<'tcx, T>( tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, value: T, diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 386fdb09ba5..1d203a29b14 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -24,29 +24,30 @@ use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind}; use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind}; use rustc_index::IndexVec; +use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::GenericArg; use rustc_middle::ty::{self, List, Ty, TyCtxt}; use rustc_span::Span; +pub use instantiate::CanonicalExt; pub use rustc_middle::infer::canonical::*; -pub use substitute::CanonicalExt; mod canonicalizer; +mod instantiate; pub mod query_response; -mod substitute; impl<'tcx> InferCtxt<'tcx> { - /// Creates a substitution S for the canonical value with fresh + /// Creates an instantiation S for the canonical value with fresh /// inference variables and applies it to the canonical value. - /// Returns both the instantiated result *and* the substitution S. + /// Returns both the instantiated result *and* the instantiation S. /// /// This can be invoked as part of constructing an /// inference context at the start of a query (see /// `InferCtxtBuilder::build_with_canonical`). It basically /// brings the canonical value "into scope" within your new infcx. /// - /// At the end of processing, the substitution S (once + /// At the end of processing, the instantiation S (once /// canonicalized) then represents the values that you computed /// for each of the canonical inputs to your query. pub fn instantiate_canonical_with_fresh_inference_vars<T>( @@ -72,14 +73,14 @@ impl<'tcx> InferCtxt<'tcx> { let canonical_inference_vars = self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]); - let result = canonical.substitute(self.tcx, &canonical_inference_vars); + let result = canonical.instantiate(self.tcx, &canonical_inference_vars); (result, canonical_inference_vars) } /// Given the "infos" about the canonical variables from some /// canonical, creates fresh variables with the same /// characteristics (see `instantiate_canonical_var` for - /// details). You can then use `substitute` to instantiate the + /// details). You can then use `instantiate` to instantiate the /// canonical variable with these inference variables. fn instantiate_canonical_vars( &self, @@ -152,7 +153,12 @@ impl<'tcx> InferCtxt<'tcx> { ) .into(), CanonicalVarKind::Effect => { - let vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid; + let vid = self + .inner + .borrow_mut() + .effect_unification_table() + .new_key(EffectVarValue::Unknown) + .vid; ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool) .into() } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 1f071a9ff0b..9d2e065afa3 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -7,27 +7,24 @@ //! //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html -use crate::infer::canonical::substitute::{substitute_value, CanonicalExt}; +use crate::infer::canonical::instantiate::{instantiate_value, CanonicalExt}; use crate::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues, QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse, }; -use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, NllRegionVariableOrigin}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult}; use crate::traits::query::NoSolution; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt}; +use crate::traits::{TraitEngine, TraitEngineExt}; use rustc_data_structures::captures::Captures; use rustc_index::Idx; use rustc_index::IndexVec; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::{self, BoundVar, ToPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; -use rustc_span::{Span, Symbol}; use std::fmt::Debug; use std::iter; @@ -189,18 +186,18 @@ impl<'tcx> InferCtxt<'tcx> { where R: Debug + TypeFoldable<TyCtxt<'tcx>>, { - let InferOk { value: result_subst, mut obligations } = - self.query_response_substitution(cause, param_env, original_values, query_response)?; + let InferOk { value: result_args, mut obligations } = + self.query_response_instantiation(cause, param_env, original_values, query_response)?; obligations.extend(self.query_outlives_constraints_into_obligations( cause, param_env, &query_response.value.region_constraints.outlives, - &result_subst, + &result_args, )); let user_result: R = - query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone()); + query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); Ok(InferOk { value: user_result, obligations }) } @@ -225,11 +222,11 @@ impl<'tcx> InferCtxt<'tcx> { /// basic operations as `instantiate_query_response_and_region_obligations` but /// it returns its result differently: /// - /// - It creates a substitution `S` that maps from the original + /// - It creates an instantiation `S` that maps from the original /// query variables to the values computed in the query /// result. If any errors arise, they are propagated back as an /// `Err` result. - /// - In the case of a successful substitution, we will append + /// - In the case of a successful instantiation, we will append /// `QueryOutlivesConstraint` values onto the /// `output_query_region_constraints` vector for the solver to /// use (if an error arises, some values may also be pushed, but @@ -239,7 +236,7 @@ impl<'tcx> InferCtxt<'tcx> { /// that must be processed. In this case, those subobligations /// are propagated back in the return value. /// - Finally, the query result (of type `R`) is propagated back, - /// after applying the substitution `S`. + /// after applying the instantiation `S`. pub fn instantiate_nll_query_response_and_region_obligations<R>( &self, cause: &ObligationCause<'tcx>, @@ -251,8 +248,13 @@ impl<'tcx> InferCtxt<'tcx> { where R: Debug + TypeFoldable<TyCtxt<'tcx>>, { - let InferOk { value: result_subst, mut obligations } = self - .query_response_substitution_guess(cause, param_env, original_values, query_response)?; + let InferOk { value: result_args, mut obligations } = self + .query_response_instantiation_guess( + cause, + param_env, + original_values, + query_response, + )?; // Compute `QueryOutlivesConstraint` values that unify each of // the original values `v_o` that was canonicalized into a @@ -262,7 +264,7 @@ impl<'tcx> InferCtxt<'tcx> { for (index, original_value) in original_values.var_values.iter().enumerate() { // ...with the value `v_r` of that variable from the query. - let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| { + let result_value = query_response.instantiate_projected(self.tcx, &result_args, |v| { v.var_values[BoundVar::new(index)] }); match (original_value.unpack(), result_value.unpack()) { @@ -285,31 +287,19 @@ impl<'tcx> InferCtxt<'tcx> { } (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { - TypeRelating::new( - self, - QueryTypeRelatingDelegate { - infcx: self, - param_env, - cause, - obligations: &mut obligations, - }, - ty::Variance::Invariant, - ) - .relate(v1, v2)?; + obligations.extend( + self.at(&cause, param_env) + .eq(DefineOpaqueTypes::Yes, v1, v2)? + .into_obligations(), + ); } (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { - TypeRelating::new( - self, - QueryTypeRelatingDelegate { - infcx: self, - param_env, - cause, - obligations: &mut obligations, - }, - ty::Variance::Invariant, - ) - .relate(v1, v2)?; + obligations.extend( + self.at(&cause, param_env) + .eq(DefineOpaqueTypes::Yes, v1, v2)? + .into_obligations(), + ); } _ => { @@ -321,7 +311,7 @@ impl<'tcx> InferCtxt<'tcx> { // ...also include the other query region constraints from the query. output_query_region_constraints.outlives.extend( query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| { - let r_c = substitute_value(self.tcx, &result_subst, r_c); + let r_c = instantiate_value(self.tcx, &result_args, r_c); // Screen out `'a: 'a` cases. let ty::OutlivesPredicate(k1, r2) = r_c.0; @@ -336,26 +326,26 @@ impl<'tcx> InferCtxt<'tcx> { .region_constraints .member_constraints .iter() - .map(|p_c| substitute_value(self.tcx, &result_subst, p_c.clone())), + .map(|p_c| instantiate_value(self.tcx, &result_args, p_c.clone())), ); let user_result: R = - query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone()); + query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); Ok(InferOk { value: user_result, obligations }) } /// Given the original values and the (canonicalized) result from - /// computing a query, returns a substitution that can be applied + /// computing a query, returns an instantiation that can be applied /// to the query result to convert the result back into the /// original namespace. /// - /// The substitution also comes accompanied with subobligations + /// The instantiation also comes accompanied with subobligations /// that arose from unification; these might occur if (for /// example) we are doing lazy normalization and the value /// assigned to a type variable is unified with an unnormalized /// projection. - fn query_response_substitution<R>( + fn query_response_instantiation<R>( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -366,11 +356,11 @@ impl<'tcx> InferCtxt<'tcx> { R: Debug + TypeFoldable<TyCtxt<'tcx>>, { debug!( - "query_response_substitution(original_values={:#?}, query_response={:#?})", + "query_response_instantiation(original_values={:#?}, query_response={:#?})", original_values, query_response, ); - let mut value = self.query_response_substitution_guess( + let mut value = self.query_response_instantiation_guess( cause, param_env, original_values, @@ -378,7 +368,7 @@ impl<'tcx> InferCtxt<'tcx> { )?; value.obligations.extend( - self.unify_query_response_substitution_guess( + self.unify_query_response_instantiation_guess( cause, param_env, original_values, @@ -392,7 +382,7 @@ impl<'tcx> InferCtxt<'tcx> { } /// Given the original values and the (canonicalized) result from - /// computing a query, returns a **guess** at a substitution that + /// computing a query, returns a **guess** at an instantiation that /// can be applied to the query result to convert the result back /// into the original namespace. This is called a **guess** /// because it uses a quick heuristic to find the values for each @@ -400,8 +390,8 @@ impl<'tcx> InferCtxt<'tcx> { /// will instantiate fresh inference variables for each canonical /// variable instead. Therefore, the result of this method must be /// properly unified - #[instrument(level = "debug", skip(self, cause, param_env))] - fn query_response_substitution_guess<R>( + #[instrument(level = "debug", skip(self, param_env))] + fn query_response_instantiation_guess<R>( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -450,7 +440,7 @@ impl<'tcx> InferCtxt<'tcx> { if let ty::Bound(debruijn, b) = *result_value.kind() { // ...in which case we would set `canonical_vars[0]` to `Some(?U)`. - // We only allow a `ty::INNERMOST` index in substitutions. + // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); opt_values[b.var] = Some(*original_value); } @@ -460,7 +450,7 @@ impl<'tcx> InferCtxt<'tcx> { if let ty::ReBound(debruijn, br) = *result_value { // ... in which case we would set `canonical_vars[0]` to `Some('static)`. - // We only allow a `ty::INNERMOST` index in substitutions. + // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); opt_values[br.var] = Some(*original_value); } @@ -469,7 +459,7 @@ impl<'tcx> InferCtxt<'tcx> { if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() { // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. - // We only allow a `ty::INNERMOST` index in substitutions. + // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); opt_values[b] = Some(*original_value); } @@ -477,10 +467,10 @@ impl<'tcx> InferCtxt<'tcx> { } } - // Create a result substitution: if we found a value for a + // Create result arguments: if we found a value for a // given variable in the loop above, use that. Otherwise, use // a fresh inference variable. - let result_subst = CanonicalVarValues { + let result_args = CanonicalVarValues { var_values: self.tcx.mk_args_from_iter( query_response.variables.iter().enumerate().map(|(index, info)| { if info.universe() != ty::UniverseIndex::ROOT { @@ -511,8 +501,8 @@ impl<'tcx> InferCtxt<'tcx> { // Carry all newly resolved opaque types to the caller's scope for &(a, b) in &query_response.value.opaque_types { - let a = substitute_value(self.tcx, &result_subst, a); - let b = substitute_value(self.tcx, &result_subst, b); + let a = instantiate_value(self.tcx, &result_args, a); + let b = instantiate_value(self.tcx, &result_args, b); debug!(?a, ?b, "constrain opaque type"); // We use equate here instead of, for example, just registering the // opaque type's hidden value directly, because we may be instantiating @@ -532,7 +522,7 @@ impl<'tcx> InferCtxt<'tcx> { ); } - Ok(InferOk { value: result_subst, obligations }) + Ok(InferOk { value: result_args, obligations }) } /// Given a "guess" at the values for the canonical variables in @@ -540,13 +530,13 @@ impl<'tcx> InferCtxt<'tcx> { /// query result. Often, but not always, this is a no-op, because /// we already found the mapping in the "guessing" step. /// - /// See also: `query_response_substitution_guess` - fn unify_query_response_substitution_guess<R>( + /// See also: [`Self::query_response_instantiation_guess`] + fn unify_query_response_instantiation_guess<R>( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, original_values: &OriginalQueryValues<'tcx>, - result_subst: &CanonicalVarValues<'tcx>, + result_args: &CanonicalVarValues<'tcx>, query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, ) -> InferResult<'tcx, ()> where @@ -554,15 +544,15 @@ impl<'tcx> InferCtxt<'tcx> { { // A closure that yields the result value for the given // canonical variable; this is taken from - // `query_response.var_values` after applying the substitution - // `result_subst`. - let substituted_query_response = |index: BoundVar| -> GenericArg<'tcx> { - query_response.substitute_projected(self.tcx, result_subst, |v| v.var_values[index]) + // `query_response.var_values` after applying the instantiation + // by `result_args`. + let instantiated_query_response = |index: BoundVar| -> GenericArg<'tcx> { + query_response.instantiate_projected(self.tcx, result_args, |v| v.var_values[index]) }; // Unify the original value for each variable with the value - // taken from `query_response` (after applying `result_subst`). - self.unify_canonical_vars(cause, param_env, original_values, substituted_query_response) + // taken from `query_response` (after applying `result_args`). + self.unify_canonical_vars(cause, param_env, original_values, instantiated_query_response) } /// Converts the region constraints resulting from a query into an @@ -571,11 +561,11 @@ impl<'tcx> InferCtxt<'tcx> { &'a self, cause: &'a ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - unsubstituted_region_constraints: &'a [QueryOutlivesConstraint<'tcx>], - result_subst: &'a CanonicalVarValues<'tcx>, + uninstantiated_region_constraints: &'a [QueryOutlivesConstraint<'tcx>], + result_args: &'a CanonicalVarValues<'tcx>, ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> { - unsubstituted_region_constraints.iter().map(move |&constraint| { - let predicate = substitute_value(self.tcx, result_subst, constraint); + uninstantiated_region_constraints.iter().map(move |&constraint| { + let predicate = instantiate_value(self.tcx, result_args, constraint); self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env) }) } @@ -615,42 +605,40 @@ impl<'tcx> InferCtxt<'tcx> { variables1: &OriginalQueryValues<'tcx>, variables2: impl Fn(BoundVar) -> GenericArg<'tcx>, ) -> InferResult<'tcx, ()> { - self.commit_if_ok(|_| { - let mut obligations = vec![]; - for (index, value1) in variables1.var_values.iter().enumerate() { - let value2 = variables2(BoundVar::new(index)); - - match (value1.unpack(), value2.unpack()) { - (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { - 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() => - { - // no action needed - } - (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => { - 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(DefineOpaqueTypes::Yes, v1, v2)?; - obligations.extend(ok.into_obligations()); - } - _ => { - bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); - } + let mut obligations = vec![]; + for (index, value1) in variables1.var_values.iter().enumerate() { + let value2 = variables2(BoundVar::new(index)); + + match (value1.unpack(), value2.unpack()) { + (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { + 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() => + { + // no action needed + } + (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => { + 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(DefineOpaqueTypes::Yes, v1, v2)?; + obligations.extend(ok.into_obligations()); + } + _ => { + bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); } } - Ok(InferOk { value: (), obligations }) - }) + } + Ok(InferOk { value: (), obligations }) } } @@ -694,67 +682,3 @@ pub fn make_query_region_constraints<'tcx>( QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() } } - -struct QueryTypeRelatingDelegate<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, - obligations: &'a mut Vec<PredicateObligation<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - cause: &'a ObligationCause<'tcx>, -} - -impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { - fn span(&self) -> Span { - self.cause.span - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn create_next_universe(&mut self) -> ty::UniverseIndex { - self.infcx.create_next_universe() - } - - fn next_existential_region_var( - &mut self, - from_forall: bool, - _name: Option<Symbol>, - ) -> ty::Region<'tcx> { - let origin = NllRegionVariableOrigin::Existential { from_forall }; - self.infcx.next_nll_region_var(origin) - } - - fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { - ty::Region::new_placeholder(self.infcx.tcx, placeholder) - } - - fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - self.infcx.next_nll_region_var_in_universe( - NllRegionVariableOrigin::Existential { from_forall: false }, - universe, - ) - } - - fn push_outlives( - &mut self, - sup: ty::Region<'tcx>, - sub: ty::Region<'tcx>, - _info: ty::VarianceDiagInfo<'tcx>, - ) { - self.obligations.push(Obligation { - cause: self.cause.clone(), - param_env: self.param_env, - predicate: ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(sup, sub)) - .to_predicate(self.infcx.tcx), - recursion_depth: 0, - }); - } - - fn forbid_inference_vars() -> bool { - true - } - - fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { - self.obligations.extend(obligations); - } -} diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 875e94fcd9f..505d56cf491 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -60,8 +60,8 @@ use crate::traits::{ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ - error_code, pluralize, struct_span_code_err, Applicability, DiagCtxt, Diagnostic, - DiagnosticBuilder, DiagnosticStyledString, ErrorGuaranteed, IntoDiagnosticArg, + codes::*, pluralize, struct_span_code_err, Applicability, DiagCtxt, DiagnosticBuilder, + DiagnosticStyledString, ErrorGuaranteed, IntoDiagnosticArg, }; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -71,6 +71,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError}; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; +use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{ self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -117,9 +118,9 @@ fn escape_literal(s: &str) -> String { /// field is only populated during an in-progress typeck. /// 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. +/// You must only create this if you intend to actually emit an error (or +/// perhaps a warning, though preferably not.) It 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>>>, @@ -131,19 +132,6 @@ 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.dcx().has_errors_or_span_delayed_bugs() { - // ok, emitted an error. - } else { - self.infcx - .tcx - .sess - .good_path_delayed_bug("used a `TypeErrCtxt` without raising an error or lint"); - } - } -} - impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub fn dcx(&self) -> &'tcx DiagCtxt { self.infcx.tcx.dcx() @@ -167,7 +155,7 @@ impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> { pub(super) fn note_and_explain_region<'tcx>( tcx: TyCtxt<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, prefix: &str, region: ty::Region<'tcx>, suffix: &str, @@ -192,7 +180,7 @@ pub(super) fn note_and_explain_region<'tcx>( fn explain_free_region<'tcx>( tcx: TyCtxt<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, prefix: &str, region: ty::Region<'tcx>, suffix: &str, @@ -274,7 +262,7 @@ fn msg_span_from_named_region<'tcx>( } fn emit_msg_span( - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, prefix: &str, description: String, span: Option<Span>, @@ -290,7 +278,7 @@ fn emit_msg_span( } fn label_msg_span( - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, prefix: &str, description: String, span: Option<Span>, @@ -517,6 +505,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); } + + RegionResolutionError::CannotNormalize(clause, origin) => { + let clause: ty::Clause<'tcx> = + clause.map_bound(ty::ClauseKind::TypeOutlives).to_predicate(self.tcx); + self.tcx + .dcx() + .struct_span_err(origin.span(), format!("cannot normalize `{clause}`")) + .emit(); + } } } } @@ -558,7 +555,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { RegionResolutionError::GenericBoundFailure(..) => true, RegionResolutionError::ConcreteFailure(..) | RegionResolutionError::SubSupConflict(..) - | RegionResolutionError::UpperBoundUniverseConflict(..) => false, + | RegionResolutionError::UpperBoundUniverseConflict(..) + | RegionResolutionError::CannotNormalize(..) => false, }; let mut errors = if errors.iter().all(|e| is_bound_failure(e)) { @@ -573,12 +571,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(), RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(), + RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(), }); errors } /// Adds a note if the types come from similarly named crates - fn check_and_note_conflicting_crates(&self, err: &mut Diagnostic, terr: TypeError<'tcx>) { + fn check_and_note_conflicting_crates( + &self, + err: &mut DiagnosticBuilder<'_>, + terr: TypeError<'tcx>, + ) { use hir::def_id::CrateNum; use rustc_hir::definitions::DisambiguatedDefPathData; use ty::print::Printer; @@ -652,7 +655,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - let report_path_match = |err: &mut Diagnostic, did1: DefId, did2: DefId| { + let report_path_match = |err: &mut DiagnosticBuilder<'_>, did1: DefId, did2: DefId| { // 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}]; @@ -702,7 +705,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn note_error_origin( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, cause: &ObligationCause<'tcx>, exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>, terr: TypeError<'tcx>, @@ -778,10 +781,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { prior_arm_span, prior_arm_ty, source, - ref prior_arms, + ref prior_non_diverging_arms, opt_suggest_box_span, scrut_span, - scrut_hir_id, .. }) => match source { hir::MatchSource::TryDesugar(scrut_hir_id) => { @@ -818,12 +820,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }); let source_map = self.tcx.sess.source_map(); let mut any_multiline_arm = source_map.is_multiline(arm_span); - if prior_arms.len() <= 4 { - for sp in prior_arms { + if prior_non_diverging_arms.len() <= 4 { + for sp in prior_non_diverging_arms { any_multiline_arm |= source_map.is_multiline(*sp); err.span_label(*sp, format!("this is found to be of type `{t}`")); } - } else if let Some(sp) = prior_arms.last() { + } else if let Some(sp) = prior_non_diverging_arms.last() { any_multiline_arm |= source_map.is_multiline(*sp); err.span_label( *sp, @@ -847,26 +849,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { arm_ty, arm_span, ) { - err.subdiagnostic(subdiag); - } - if let Some(hir::Node::Expr(m)) = self.tcx.hir().find_parent(scrut_hir_id) - && let Some(hir::Node::Stmt(stmt)) = self.tcx.hir().find_parent(m.hir_id) - && let hir::StmtKind::Expr(_) = stmt.kind - { - err.span_suggestion_verbose( - stmt.span.shrink_to_hi(), - "consider using a semicolon here, but this will discard any values \ - in the match arms", - ";", - Applicability::MaybeIncorrect, - ); + err.subdiagnostic(self.dcx(), subdiag); } if let Some(ret_sp) = opt_suggest_box_span { // Get return type span and point to it. self.suggest_boxing_for_return_impl_trait( err, ret_sp, - prior_arms.iter().chain(std::iter::once(&arm_span)).copied(), + prior_non_diverging_arms + .iter() + .chain(std::iter::once(&arm_span)) + .copied(), ); } } @@ -893,7 +886,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { else_ty, else_span, ) { - err.subdiagnostic(subdiag); + err.subdiagnostic(self.dcx(), subdiag); } // don't suggest wrapping either blocks in `if .. {} else {}` let is_empty_arm = |id| { @@ -1546,7 +1539,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { )] pub fn note_type_err( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, cause: &ObligationCause<'tcx>, secondary_span: Option<(Span, Cow<'static, str>)>, mut values: Option<ValuePairs<'tcx>>, @@ -1593,14 +1586,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { types_visitor } - fn report(&self, err: &mut Diagnostic) { + fn report(&self, err: &mut DiagnosticBuilder<'_>) { self.add_labels_for_types(err, "expected", &self.expected); self.add_labels_for_types(err, "found", &self.found); } fn add_labels_for_types( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, target: &str, types: &FxIndexMap<TyCategory, FxIndexSet<Span>>, ) { @@ -1814,7 +1807,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { |prim: Ty<'tcx>, shadow: Ty<'tcx>, defid: DefId, - diagnostic: &mut Diagnostic| { + diagnostic: &mut DiagnosticBuilder<'_>| { let name = shadow.sort_string(self.tcx); diagnostic.note(format!( "{prim} and {name} have similar names, but are actually distinct types" @@ -1834,7 +1827,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let diagnose_adts = |expected_adt: ty::AdtDef<'tcx>, found_adt: ty::AdtDef<'tcx>, - diagnostic: &mut Diagnostic| { + diagnostic: &mut DiagnosticBuilder<'_>| { let found_name = values.found.sort_string(self.tcx); let expected_name = values.expected.sort_string(self.tcx); @@ -1942,6 +1935,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { "the full type name has been written to '{}'", path.display(), )); + diag.note(format!("consider using `--verbose` to print the full type name to the console")); } } } @@ -2169,8 +2163,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { 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) { + let span = self.tcx.hir().span(*hir_id); Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found }) } else { None @@ -2361,9 +2355,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .dcx() .struct_span_err(span, format!("{labeled_user_string} may not live long enough")); err.code(match sub.kind() { - ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => error_code!(E0309), - ty::ReStatic => error_code!(E0310), - _ => error_code!(E0311), + ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => E0309, + ty::ReStatic => E0310, + _ => E0311, }); '_explain: { @@ -2545,7 +2539,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { add_lt_suggs, new_lt: &new_lt, }; - match self.tcx.hir().expect_owner(lifetime_scope) { + match self.tcx.expect_hir_owner_node(lifetime_scope) { hir::OwnerNode::Item(i) => visitor.visit_item(i), hir::OwnerNode::ForeignItem(i) => visitor.visit_foreign_item(i), hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i), @@ -2797,19 +2791,8 @@ pub enum FailureCode { 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; -} - -impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { +#[extension(pub trait ObligationCauseExt<'tcx>)] +impl<'tcx> ObligationCause<'tcx> { fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode { use self::FailureCode::*; use crate::traits::ObligationCauseCode::*; @@ -2829,7 +2812,11 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { // say, also take a look at the error code, maybe we can // tailor to that. _ => match terr { - TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() => Error0644, + TypeError::CyclicTy(ty) + if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() => + { + Error0644 + } TypeError::IntrinsicCast => Error0308, _ => Error0308, }, @@ -2876,7 +2863,9 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { // say, also take a look at the error code, maybe we can // tailor to that. _ => match terr { - TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() => { + TypeError::CyclicTy(ty) + if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() => + { ObligationCauseFailureCode::ClosureSelfref { span } } TypeError::IntrinsicCast => { @@ -2913,7 +2902,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>); impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { use crate::traits::ObligationCauseCode::*; let kind = match self.0.code() { CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat", 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 03c8e08aa01..af722b20626 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 @@ -5,7 +5,7 @@ use crate::errors::{ use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; -use rustc_errors::{DiagnosticBuilder, IntoDiagnosticArg}; +use rustc_errors::{codes::*, DiagnosticBuilder, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; @@ -43,12 +43,12 @@ pub enum TypeAnnotationNeeded { E0284, } -impl Into<String> for TypeAnnotationNeeded { - fn into(self) -> String { +impl Into<ErrCode> for TypeAnnotationNeeded { + fn into(self) -> ErrCode { match self { - Self::E0282 => rustc_errors::error_code!(E0282), - Self::E0283 => rustc_errors::error_code!(E0283), - Self::E0284 => rustc_errors::error_code!(E0284), + Self::E0282 => E0282, + Self::E0283 => E0283, + Self::E0284 => E0284, } } } @@ -134,7 +134,7 @@ impl InferenceDiagnosticsParentData { } impl IntoDiagnosticArg for UnderspecifiedArgKind { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { let kind = match self { Self::Type { .. } => "type", Self::Const { is_parameter: true } => "const_with_param", @@ -883,7 +883,10 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { GenericArgKind::Type(ty) => { if matches!( ty.kind(), - ty::Alias(ty::Opaque, ..) | ty::Closure(..) | ty::Coroutine(..) + ty::Alias(ty::Opaque, ..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) ) { // Opaque types can't be named by the user right now. // diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index adb3267d5be..cf8ac544106 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -12,7 +12,7 @@ use crate::infer::SubregionOrigin; use crate::infer::TyCtxt; use rustc_errors::AddToDiagnostic; -use rustc_errors::{Diagnostic, ErrorGuaranteed}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir::Ty; use rustc_middle::ty::Region; @@ -142,7 +142,7 @@ pub fn suggest_adding_lifetime_params<'tcx>( sub: Region<'tcx>, ty_sup: &'tcx Ty<'_>, ty_sub: &'tcx Ty<'_>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) { let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false }; suggestion.add_to_diagnostic(err); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index e1a83c86318..b3b83c8ab95 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -30,7 +30,7 @@ impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T> where T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>>, { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue { rustc_errors::DiagnosticArgValue::Str(self.to_string().into()) } } 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 a7d1c2ca666..83e0b763d24 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 @@ -9,7 +9,7 @@ use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{AddToDiagnostic, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{ @@ -261,7 +261,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { pub fn suggest_new_region_bound( tcx: TyCtxt<'_>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, fn_returns: Vec<&rustc_hir::Ty<'_>>, lifetime_name: String, arg: Option<String>, @@ -443,7 +443,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if let hir::OwnerNode::Item(Item { kind: ItemKind::Impl(hir::Impl { self_ty, .. }), .. - }) = tcx.hir().owner(impl_did) + }) = tcx.hir_owner_node(impl_did) { Some((impl_item.ident, self_ty)) } else { @@ -488,7 +488,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// `'static` obligation. Suggest relaxing that implicit bound. fn find_impl_on_dyn_trait( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, ctxt: &UnifyReceiverContext<'tcx>, ) -> bool { @@ -521,7 +521,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { fn suggest_constrain_dyn_trait_in_impl( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, found_dids: &FxIndexSet<DefId>, ident: Ident, self_ty: &hir::Ty<'_>, 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 bfff00b948e..f1f8314661f 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, Region, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Binder, Region, Ty, TypeFoldable}; use rustc_span::Span; /// Information about the anonymous region we are searching for. @@ -142,10 +142,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { fn includes_region( &self, - ty: Binder<'tcx, impl TypeVisitable<TyCtxt<'tcx>>>, + ty: Binder<'tcx, impl TypeFoldable<TyCtxt<'tcx>>>, region: ty::BoundRegionKind, ) -> bool { - let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty); + let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(ty); // We are only checking is any region meets the condition so order doesn't matter #[allow(rustc::potential_query_instability)] late_bound_regions.iter().any(|r| *r == region) diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 02200d6a4aa..0878505e85e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -5,7 +5,7 @@ use crate::errors::{ use crate::fluent_generated as fluent; use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::{self, SubregionOrigin}; -use rustc_errors::{AddToDiagnostic, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{AddToDiagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; @@ -15,7 +15,11 @@ use rustc_span::symbol::kw; use super::ObligationCauseAsDiagArg; impl<'tcx> TypeErrCtxt<'_, 'tcx> { - pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) { + pub(super) fn note_region_origin( + &self, + err: &mut DiagnosticBuilder<'_>, + origin: &SubregionOrigin<'tcx>, + ) { match *origin { infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { span: trace.cause.span, @@ -290,7 +294,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, trait_item_def_id: DefId, impl_item_def_id: LocalDefId, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) { // FIXME(compiler-errors): Right now this is only being used for region // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches, @@ -342,7 +346,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { trait_predicates: trait_predicates.join(", "), } }; - err.subdiagnostic(suggestion); + err.subdiagnostic(self.dcx(), suggestion); } pub(super) fn report_placeholder_failure( 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 afb3c5c1e56..9df2f929501 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,6 +1,6 @@ use super::TypeErrCtxt; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; -use rustc_errors::{pluralize, Diagnostic, MultiSpan}; +use rustc_errors::{pluralize, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::traits::ObligationCauseCode; @@ -15,7 +15,7 @@ use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol}; impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub fn note_and_explain_type_err( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, err: TypeError<'tcx>, cause: &ObligationCause<'tcx>, sp: Span, @@ -106,7 +106,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } p_def_id.as_local().and_then(|id| { let local_id = tcx.local_def_id_to_hir_id(id); - let generics = tcx.hir().find_parent(local_id)?.generics()?; + let generics = tcx.parent_hir_node(local_id).generics()?; Some((id, generics)) }) }); @@ -195,7 +195,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } diag.help("type parameters must be constrained to match other types"); - if tcx.sess.teach(&diag.get_code().unwrap()) { + if tcx.sess.teach(diag.code.unwrap()) { diag.help( "given a type parameter `T` and a method `foo`: ``` @@ -228,7 +228,10 @@ impl<T> Trait<T> for X { #traits-as-parameters", ); } - (ty::Param(p), ty::Closure(..) | ty::Coroutine(..)) => { + ( + ty::Param(p), + ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..), + ) => { let generics = tcx.generics_of(body_owner_def_id); if let Some(param) = generics.opt_type_param(p, tcx) { let p_span = tcx.def_span(param.def_id); @@ -294,8 +297,78 @@ impl<T> Trait<T> for X { ); } } - (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) - if alias.def_id.is_local() + (ty::Dynamic(t, _, ty::DynKind::Dyn), ty::Alias(ty::Opaque, alias)) + if let Some(def_id) = t.principal_def_id() + && tcx.explicit_item_bounds(alias.def_id).skip_binder().iter().any( + |(pred, _span)| match pred.kind().skip_binder() { + ty::ClauseKind::Trait(trait_predicate) + if trait_predicate.polarity + == ty::ImplPolarity::Positive => + { + trait_predicate.def_id() == def_id + } + _ => false, + }, + ) => + { + diag.help(format!( + "you can box the `{}` to coerce it to `Box<{}>`, but you'll have to \ + change the expected type as well", + values.found, values.expected, + )); + } + (ty::Dynamic(t, _, ty::DynKind::Dyn), _) + if let Some(def_id) = t.principal_def_id() => + { + let mut impl_def_ids = vec![]; + tcx.for_each_relevant_impl(def_id, values.found, |did| { + impl_def_ids.push(did) + }); + if let [_] = &impl_def_ids[..] { + let trait_name = tcx.item_name(def_id); + diag.help(format!( + "`{}` implements `{trait_name}` so you could box the found value \ + and coerce it to the trait object `Box<dyn {trait_name}>`, you \ + will have to change the expected type as well", + values.found, + )); + } + } + (_, ty::Dynamic(t, _, ty::DynKind::Dyn)) + if let Some(def_id) = t.principal_def_id() => + { + let mut impl_def_ids = vec![]; + tcx.for_each_relevant_impl(def_id, values.expected, |did| { + impl_def_ids.push(did) + }); + if let [_] = &impl_def_ids[..] { + let trait_name = tcx.item_name(def_id); + diag.help(format!( + "`{}` implements `{trait_name}` so you could change the expected \ + type to `Box<dyn {trait_name}>`", + values.expected, + )); + } + } + (ty::Dynamic(t, _, ty::DynKind::DynStar), _) + if let Some(def_id) = t.principal_def_id() => + { + let mut impl_def_ids = vec![]; + tcx.for_each_relevant_impl(def_id, values.found, |did| { + impl_def_ids.push(did) + }); + if let [_] = &impl_def_ids[..] { + let trait_name = tcx.item_name(def_id); + diag.help(format!( + "`{}` implements `{trait_name}`, `#[feature(dyn_star)]` is likely \ + not enabled; that feature it is currently incomplete", + values.found, + )); + } + } + (_, ty::Alias(ty::Opaque, opaque_ty)) + | (ty::Alias(ty::Opaque, opaque_ty), _) => { + if opaque_ty.def_id.is_local() && matches!( tcx.def_kind(body_owner_def_id), DefKind::Fn @@ -303,21 +376,74 @@ impl<T> Trait<T> for X { | DefKind::Const | DefKind::AssocFn | DefKind::AssocConst - ) => - { - if tcx.is_type_alias_impl_trait(alias.def_id) { - if !tcx + ) + && tcx.is_type_alias_impl_trait(opaque_ty.def_id) + && !tcx .opaque_types_defined_by(body_owner_def_id.expect_local()) - .contains(&alias.def_id.expect_local()) - { - let sp = tcx - .def_ident_span(body_owner_def_id) - .unwrap_or_else(|| tcx.def_span(body_owner_def_id)); - diag.span_note( - sp, - "\ - this item must have the opaque type in its signature \ - in order to be able to register hidden types", + .contains(&opaque_ty.def_id.expect_local()) + { + let sp = tcx + .def_ident_span(body_owner_def_id) + .unwrap_or_else(|| tcx.def_span(body_owner_def_id)); + diag.span_note( + sp, + "this item must have the opaque type in its signature in order to \ + be able to register hidden types", + ); + } + // If two if arms can be coerced to a trait object, provide a structured + // suggestion. + let ObligationCauseCode::IfExpression(cause) = cause.code() else { + return; + }; + let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id) else { + return; + }; + let Some(then) = blk.expr else { + return; + }; + let hir::Node::Block(blk) = self.tcx.hir_node(cause.else_id) else { + return; + }; + let Some(else_) = blk.expr else { + return; + }; + let expected = match values.found.kind() { + ty::Alias(..) => values.expected, + _ => values.found, + }; + let preds = tcx.explicit_item_bounds(opaque_ty.def_id); + for (pred, _span) in preds.skip_binder() { + let ty::ClauseKind::Trait(trait_predicate) = pred.kind().skip_binder() + else { + continue; + }; + if trait_predicate.polarity != ty::ImplPolarity::Positive { + continue; + } + let def_id = trait_predicate.def_id(); + let mut impl_def_ids = vec![]; + tcx.for_each_relevant_impl(def_id, expected, |did| { + impl_def_ids.push(did) + }); + if let [_] = &impl_def_ids[..] { + let trait_name = tcx.item_name(def_id); + diag.multipart_suggestion( + format!( + "`{expected}` implements `{trait_name}` so you can box \ + both arms and coerce to the trait object \ + `Box<dyn {trait_name}>`", + ), + vec![ + (then.span.shrink_to_lo(), "Box::new(".to_string()), + ( + then.span.shrink_to_hi(), + format!(") as Box<dyn {}>", tcx.def_path_str(def_id)), + ), + (else_.span.shrink_to_lo(), "Box::new(".to_string()), + (else_.span.shrink_to_hi(), ")".to_string()), + ], + MachineApplicable, ); } } @@ -330,6 +456,38 @@ impl<T> Trait<T> for X { ); } } + (ty::Adt(_, _), ty::Adt(def, args)) + if let ObligationCauseCode::IfExpression(cause) = cause.code() + && let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id) + && let Some(then) = blk.expr + && def.is_box() + && let boxed_ty = args.type_at(0) + && let ty::Dynamic(t, _, _) = boxed_ty.kind() + && let Some(def_id) = t.principal_def_id() + && let mut impl_def_ids = vec![] + && let _ = + tcx.for_each_relevant_impl(def_id, values.expected, |did| { + impl_def_ids.push(did) + }) + && let [_] = &impl_def_ids[..] => + { + // We have divergent if/else arms where the expected value is a type that + // implements the trait of the found boxed trait object. + diag.multipart_suggestion( + format!( + "`{}` implements `{}` so you can box it to coerce to the trait \ + object `{}`", + values.expected, + tcx.item_name(def_id), + values.found, + ), + vec![ + (then.span.shrink_to_lo(), "Box::new(".to_string()), + (then.span.shrink_to_hi(), ")".to_string()), + ], + MachineApplicable, + ); + } _ => {} } debug!( @@ -342,7 +500,7 @@ impl<T> Trait<T> for X { } CyclicTy(ty) => { // Watch out for various cases of cyclic types and try to explain. - if ty.is_closure() || ty.is_coroutine() { + if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() { diag.note( "closures cannot capture themselves or take themselves as argument;\n\ this error may be the result of a recent compiler bug-fix,\n\ @@ -364,7 +522,7 @@ impl<T> Trait<T> for X { fn suggest_constraint( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, msg: impl Fn() -> String, body_owner_def_id: DefId, proj_ty: &ty::AliasTy<'tcx>, @@ -437,7 +595,7 @@ impl<T> Trait<T> for X { /// fn that returns the type. fn expected_projection( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, proj_ty: &ty::AliasTy<'tcx>, values: ExpectedFound<Ty<'tcx>>, body_owner_def_id: DefId, @@ -523,7 +681,7 @@ impl<T> Trait<T> for X { https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", ); } - if tcx.sess.teach(&diag.get_code().unwrap()) { + if tcx.sess.teach(diag.code.unwrap()) { diag.help( "given an associated type `T` and a method `foo`: ``` @@ -547,7 +705,7 @@ fn foo(&self) -> Self::T { String::new() } /// a return type. This can occur when dealing with `TryStream` (#71035). fn suggest_constraining_opaque_associated_type( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, msg: impl Fn() -> String, proj_ty: &ty::AliasTy<'tcx>, ty: Ty<'tcx>, @@ -582,7 +740,7 @@ fn foo(&self) -> Self::T { String::new() } fn point_at_methods_that_satisfy_associated_type( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, assoc_container_id: DefId, current_method_ident: Option<Symbol>, proj_ty_item_def_id: DefId, @@ -640,7 +798,7 @@ fn foo(&self) -> Self::T { String::new() } fn point_at_associated_type( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, body_owner_def_id: DefId, found: Ty<'tcx>, ) -> bool { @@ -721,7 +879,7 @@ fn foo(&self) -> Self::T { String::new() } /// type is defined on a supertrait of the one present in the bounds. fn constrain_generic_bound_associated_type_structured_suggestion( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, assoc: ty::AssocItem, @@ -758,7 +916,7 @@ fn foo(&self) -> Self::T { String::new() } /// associated type to a given type `ty`. fn constrain_associated_type_structured_suggestion( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, span: Span, assoc: ty::AssocItem, assoc_args: &[ty::GenericArg<'tcx>], diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index bbe07b8ed72..f7102ab6205 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::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_middle::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, @@ -76,7 +76,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub(super) fn suggest_boxing_for_return_impl_trait( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, return_sp: Span, arm_spans: impl Iterator<Item = Span>, ) { @@ -84,7 +84,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { start_sp: return_sp.with_hi(return_sp.lo() + BytePos(4)), end_sp: return_sp.shrink_to_hi(), }; - err.subdiagnostic(sugg); + err.subdiagnostic(self.dcx(), sugg); let mut starts = Vec::new(); let mut ends = Vec::new(); @@ -93,14 +93,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ends.push(span.shrink_to_hi()); } let sugg = SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends }; - err.subdiagnostic(sugg); + err.subdiagnostic(self.dcx(), sugg); } pub(super) fn suggest_tuple_pattern( &self, cause: &ObligationCause<'tcx>, exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) { // Heavily inspired by `FnCtxt::suggest_compatible_variants`, with // some modifications due to that being in typeck and this being in infer. @@ -138,7 +138,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span_low: cause.span.shrink_to_lo(), span_high: cause.span.shrink_to_hi(), }; - diag.subdiagnostic(sugg); + diag.subdiagnostic(self.dcx(), sugg); } _ => { // More than one matching variant. @@ -147,7 +147,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cause_span: cause.span, compatible_variants, }; - diag.subdiagnostic(sugg); + diag.subdiagnostic(self.dcx(), sugg); } } } @@ -177,7 +177,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cause: &ObligationCause<'tcx>, exp_span: Span, exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) { debug!( "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}", @@ -203,10 +203,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - prior_arms, + prior_non_diverging_arms, .. }) => { - if let [.., arm_span] = &prior_arms[..] { + if let [.., arm_span] = &prior_non_diverging_arms[..] { Some(ConsiderAddingAwait::BothFuturesSugg { first: arm_span.shrink_to_hi(), second: exp_span.shrink_to_hi(), @@ -219,9 +219,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }, (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => { // FIXME: Seems like we can't have a suggestion and a note with different spans in a single subdiagnostic - diag.subdiagnostic(ConsiderAddingAwait::FutureSugg { - span: exp_span.shrink_to_hi(), - }); + diag.subdiagnostic( + self.dcx(), + ConsiderAddingAwait::FutureSugg { span: exp_span.shrink_to_hi() }, + ); Some(ConsiderAddingAwait::FutureSuggNote { span: exp_span }) } (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code() @@ -234,11 +235,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - ref prior_arms, + ref prior_non_diverging_arms, .. }) => Some({ ConsiderAddingAwait::FutureSuggMultiple { - spans: prior_arms.iter().map(|arm| arm.shrink_to_hi()).collect(), + spans: prior_non_diverging_arms + .iter() + .map(|arm| arm.shrink_to_hi()) + .collect(), } }), _ => None, @@ -246,7 +250,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { _ => None, }; if let Some(subdiag) = subdiag { - diag.subdiagnostic(subdiag); + diag.subdiagnostic(self.dcx(), subdiag); } } @@ -254,7 +258,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, cause: &ObligationCause<'tcx>, exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) { debug!( "suggest_accessing_field_where_appropriate(cause={:?}, exp_found={:?})", @@ -282,7 +286,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } else { return; }; - diag.subdiagnostic(suggestion); + diag.subdiagnostic(self.dcx(), suggestion); } } } @@ -294,7 +298,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cause: &ObligationCause<'tcx>, span: Span, exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) { debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found); let ty::error::ExpectedFound { expected, found } = exp_found; @@ -313,7 +317,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if !self.same_type_modulo_infer(*found_sig, *expected_sig) || !sig.is_suggestable(self.tcx, true) - || self.tcx.is_intrinsic(*did) + || self.tcx.intrinsic(*did).is_some() { return; } @@ -322,15 +326,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (true, false) => FunctionPointerSuggestion::UseRef { span, fn_name }, (false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name }, (true, true) => { - diag.subdiagnostic(FnItemsAreDistinct); + diag.subdiagnostic(self.dcx(), FnItemsAreDistinct); FunctionPointerSuggestion::CastRef { span, fn_name, sig: *sig } } (false, false) => { - diag.subdiagnostic(FnItemsAreDistinct); + diag.subdiagnostic(self.dcx(), FnItemsAreDistinct); FunctionPointerSuggestion::Cast { span, fn_name, sig: *sig } } }; - diag.subdiagnostic(sugg); + diag.subdiagnostic(self.dcx(), sugg); } (ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => { let expected_sig = @@ -339,14 +343,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &(self.normalize_fn_sig)(self.tcx.fn_sig(*did2).instantiate(self.tcx, args2)); if self.same_type_modulo_infer(*expected_sig, *found_sig) { - diag.subdiagnostic(FnUniqTypes); + diag.subdiagnostic(self.dcx(), 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) - || self.tcx.is_intrinsic(*did1) - || self.tcx.is_intrinsic(*did2) + || self.tcx.intrinsic(*did1).is_some() + || self.tcx.intrinsic(*did2).is_some() { return; } @@ -368,7 +372,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } }; - diag.subdiagnostic(sug); + diag.subdiagnostic(self.dcx(), sug); } (ty::FnDef(did, args), ty::FnPtr(sig)) => { let expected_sig = @@ -387,7 +391,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!("{fn_name} as {found_sig}") }; - diag.subdiagnostic(FnConsiderCasting { casting }); + diag.subdiagnostic(self.dcx(), FnConsiderCasting { casting }); } _ => { return; @@ -528,7 +532,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span: Span, hir: hir::Node<'_>, exp_found: &ty::error::ExpectedFound<ty::PolyTraitRef<'tcx>>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) { // 0. Extract fn_decl from hir let hir::Node::Expr(hir::Expr { @@ -735,30 +739,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; local.pat.walk(&mut find_compatible_candidates); } - match hir.find_parent(blk.hir_id) { - Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => match hir.find_parent(*hir_id) { - Some(hir::Node::Arm(hir::Arm { pat, .. })) => { + match self.tcx.parent_hir_node(blk.hir_id) { + hir::Node::Expr(hir::Expr { hir_id, .. }) => match self.tcx.parent_hir_node(*hir_id) { + hir::Node::Arm(hir::Arm { pat, .. }) => { pat.walk(&mut find_compatible_candidates); } - Some( - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. }) - | hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(_, body), .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)), - .. - }) - | hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(hir::Closure { body, .. }), - .. - }), - ) => { + + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(_, body), .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)), + .. + }) + | hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(hir::Closure { body, .. }), + .. + }) => { for param in hir.body(*body).params { param.pat.walk(&mut find_compatible_candidates); } } - Some(hir::Node::Expr(hir::Expr { + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If( hir::Expr { kind: hir::ExprKind::Let(let_), .. }, @@ -766,7 +769,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { _, ), .. - })) if then_block.hir_id == *hir_id => { + }) if then_block.hir_id == *hir_id => { let_.pat.walk(&mut find_compatible_candidates); } _ => {} @@ -815,12 +818,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, blk: &'tcx hir::Block<'tcx>, expected_ty: Ty<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) -> bool { let diag = self.consider_returning_binding_diag(blk, expected_ty); match diag { Some(diag) => { - err.subdiagnostic(diag); + err.subdiagnostic(self.dcx(), diag); true } None => false, diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index d256994d8d1..2d5fa1b5c70 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -151,13 +151,8 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty()) } ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => { - let opt_ct = self - .infcx - .inner - .borrow_mut() - .effect_unification_table() - .probe_value(v) - .map(|effect| effect.as_const(self.infcx.tcx)); + let opt_ct = + self.infcx.inner.borrow_mut().effect_unification_table().probe_value(v).known(); self.freshen_const( opt_ct, ty::InferConst::EffectVar(v), 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 0562c6ccfcf..c39d0425f7e 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -98,6 +98,8 @@ pub enum RegionResolutionError<'tcx> { SubregionOrigin<'tcx>, // cause of the constraint Region<'tcx>, // the placeholder `'b` ), + + CannotNormalize(ty::PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>), } impl<'tcx> RegionResolutionError<'tcx> { @@ -106,7 +108,8 @@ impl<'tcx> RegionResolutionError<'tcx> { RegionResolutionError::ConcreteFailure(origin, _, _) | RegionResolutionError::GenericBoundFailure(origin, _, _) | RegionResolutionError::SubSupConflict(_, _, origin, _, _, _, _) - | RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) => origin, + | RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) + | RegionResolutionError::CannotNormalize(_, origin) => origin, } } } @@ -799,14 +802,12 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } // Errors in earlier passes can yield error variables without - // resolution errors here; delay ICE in favor of those errors. - self.tcx().dcx().span_delayed_bug( - self.var_infos[node_idx].origin.span(), - format!( - "collect_error_for_expanding_node() could not find \ - error for var {node_idx:?} in universe {node_universe:?}, lower_bounds={lower_bounds:#?}, \ - upper_bounds={upper_bounds:#?}" - ), + // resolution errors here; ICE if no errors have been emitted yet. + assert!( + self.tcx().dcx().has_errors().is_some(), + "collect_error_for_expanding_node() could not find error for var {node_idx:?} in \ + universe {node_universe:?}, lower_bounds={lower_bounds:#?}, \ + upper_bounds={upper_bounds:#?}", ); } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 002aad19c49..8fc71671b27 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -8,12 +8,15 @@ pub use self::ValuePairs::*; pub use relate::combine::ObligationEmittingRelation; use rustc_data_structures::captures::Captures; use rustc_data_structures::undo_log::UndoLogs; +use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; use self::opaque_types::OpaqueTypeStorage; pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; -use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine, TraitEngineExt}; +use crate::traits::{ + self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, TraitEngineExt, +}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -23,8 +26,8 @@ use rustc_data_structures::unify as ut; use rustc_errors::{DiagCtxt, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; +use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; -use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::{select, DefiningAnchor}; @@ -51,7 +54,6 @@ use self::region_constraints::{ RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, }; pub use self::relate::combine::CombineFields; -pub use self::relate::nll as nll_relate; use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; pub mod at; @@ -276,7 +278,8 @@ pub struct InferCtxt<'tcx> { /// 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>>>>, + pub reported_trait_errors: + RefCell<FxIndexMap<Span, (Vec<ty::Predicate<'tcx>>, ErrorGuaranteed)>>, pub reported_signature_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>, @@ -302,6 +305,12 @@ pub struct InferCtxt<'tcx> { // FIXME(matthewjasper) Merge into `tainted_by_errors` err_count_on_creation: usize, + /// Track how many errors were stashed when this infcx is created. + /// Used for the same purpose as `err_count_on_creation`, even + /// though it's weaker because the count can go up and down. + // FIXME(matthewjasper) Merge into `tainted_by_errors` + stashed_err_count_on_creation: usize, + /// What is the innermost universe we have created? Starts out as /// `UniverseIndex::root()` but grows from there as we enter /// universal quantifiers. @@ -334,6 +343,8 @@ pub struct InferCtxt<'tcx> { pub intercrate: bool, next_trait_solver: bool, + + pub obligation_inspector: Cell<Option<ObligationInspector<'tcx>>>, } impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { @@ -614,11 +625,8 @@ pub struct InferCtxtBuilder<'tcx> { next_trait_solver: bool, } -pub trait TyCtxtInferExt<'tcx> { - fn infer_ctxt(self) -> InferCtxtBuilder<'tcx>; -} - -impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { +#[extension(pub trait TyCtxtInferExt<'tcx>)] +impl<'tcx> TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { InferCtxtBuilder { tcx: self, @@ -667,7 +675,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// inference context that contains each of the bound values /// within instantiated as a fresh variable. The `f` closure is /// invoked with the new infcx, along with the instantiated value - /// `V` and a substitution `S`. This substitution `S` maps from + /// `V` and a instantiation `S`. This instantiation `S` maps from /// the bound values in `C` to their instantiated values in `V` /// (in other words, `S(C) = V`). pub fn build_with_canonical<T>( @@ -679,8 +687,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> { T: TypeFoldable<TyCtxt<'tcx>>, { let infcx = self.build(); - let (value, subst) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); - (infcx, value, subst) + let (value, args) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); + (infcx, value, args) } pub fn build(&mut self) -> InferCtxt<'tcx> { @@ -704,10 +712,12 @@ impl<'tcx> InferCtxtBuilder<'tcx> { reported_trait_errors: Default::default(), reported_signature_mismatch: Default::default(), tainted_by_errors: Cell::new(None), - err_count_on_creation: tcx.dcx().err_count(), + err_count_on_creation: tcx.dcx().err_count_excluding_lint_errs(), + stashed_err_count_on_creation: tcx.dcx().stashed_err_count(), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, next_trait_solver, + obligation_inspector: Cell::new(None), } } } @@ -812,7 +822,7 @@ impl<'tcx> InferCtxt<'tcx> { (0..table.len()) .map(|i| ty::EffectVid::from_usize(i)) - .filter(|&vid| table.probe_value(vid).is_none()) + .filter(|&vid| table.probe_value(vid).is_unknown()) .map(|v| { ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool) }) @@ -856,7 +866,7 @@ impl<'tcx> InferCtxt<'tcx> { } #[instrument(skip(self, snapshot), level = "debug")] - fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'tcx>) { + fn rollback_to(&self, snapshot: CombinedSnapshot<'tcx>) { let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, universe } = snapshot; self.universe.set(universe); @@ -888,7 +898,7 @@ impl<'tcx> InferCtxt<'tcx> { self.commit_from(snapshot); } Err(_) => { - self.rollback_to("commit_if_ok -- error", snapshot); + self.rollback_to(snapshot); } } r @@ -902,7 +912,7 @@ impl<'tcx> InferCtxt<'tcx> { { let snapshot = self.start_snapshot(); let r = f(&snapshot); - self.rollback_to("probe", snapshot); + self.rollback_to(snapshot); r } @@ -1025,10 +1035,9 @@ impl<'tcx> InferCtxt<'tcx> { _ => {} } - let ty::SubtypePredicate { a_is_expected, a, b } = - self.instantiate_binder_with_placeholders(predicate); - - Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)) + self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| { + Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)) + }) } pub fn region_outlives_predicate( @@ -1036,10 +1045,12 @@ impl<'tcx> InferCtxt<'tcx> { cause: &traits::ObligationCause<'tcx>, predicate: ty::PolyRegionOutlivesPredicate<'tcx>, ) { - let ty::OutlivesPredicate(r_a, r_b) = self.instantiate_binder_with_placeholders(predicate); - let origin = - SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span)); - self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` + self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| { + let origin = SubregionOrigin::from_obligation_cause(cause, || { + RelateRegionParamBound(cause.span) + }); + self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` + }) } /// Number of type variables created so far. @@ -1179,13 +1190,13 @@ impl<'tcx> InferCtxt<'tcx> { } GenericParamDefKind::Type { .. } => { // Create a type inference variable for the given - // type parameter definition. The substitutions are + // type parameter definition. The generic parameters are // for actual parameters that may be referred to by // the default of this type parameter, if it exists. // e.g., `struct Foo<A, B, C = (A, B)>(...);` when // used in a path such as `Foo::<T, U>::new()` will // use an inference variable for `C` with `[T, U]` - // as the substitutions for the default, `(T, U)`. + // as the generic parameters for the default, `(T, U)`. let ty_var_id = self.inner.borrow_mut().type_variables().new_var( self.universe(), TypeVariableOrigin { @@ -1230,7 +1241,8 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { - let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid; + let effect_vid = + self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid; let ty = self .tcx .type_of(param.def_id) @@ -1240,7 +1252,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid), ty).into() } - /// Given a set of generics defined on a type or impl, returns a substitution mapping each + /// Given a set of generics defined on a type or impl, returns the generic parameters mapping each /// type/region parameter to a fresh inference variable. pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> { GenericArgs::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param)) @@ -1253,26 +1265,27 @@ impl<'tcx> InferCtxt<'tcx> { /// inference variables, regionck errors). #[must_use = "this method does not have any side effects"] pub fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> { - debug!( - "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ - tainted_by_errors={})", - self.dcx().err_count(), - self.err_count_on_creation, - self.tainted_by_errors.get().is_some() - ); - - if let Some(e) = self.tainted_by_errors.get() { - return Some(e); - } - - if self.dcx().err_count() > self.err_count_on_creation { - // errors reported since this infcx was made - let e = self.dcx().has_errors().unwrap(); - self.set_tainted_by_errors(e); - return Some(e); + if let Some(guar) = self.tainted_by_errors.get() { + Some(guar) + } else if self.dcx().err_count_excluding_lint_errs() > self.err_count_on_creation { + // Errors reported since this infcx was made. Lint errors are + // excluded to avoid some being swallowed in the presence of + // non-lint errors. (It's arguable whether or not this exclusion is + // important.) + let guar = self.dcx().has_errors().unwrap(); + self.set_tainted_by_errors(guar); + Some(guar) + } else if self.dcx().stashed_err_count() > self.stashed_err_count_on_creation { + // Errors stashed since this infcx was made. Not entirely reliable + // because the count of stashed errors can go down. But without + // this case we get a moderate number of uninteresting and + // extraneous "type annotations needed" errors. + let guar = self.dcx().delayed_bug("tainted_by_errors: stashed bug awaiting emission"); + self.set_tainted_by_errors(guar); + Some(guar) + } else { + None } - - None } /// Set the "tainted by errors" flag to true. We call this when we @@ -1311,6 +1324,12 @@ impl<'tcx> InferCtxt<'tcx> { std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) } + #[instrument(level = "debug", skip(self), ret)] + pub fn clone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> { + debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error); + self.inner.borrow().opaque_type_storage.opaque_types.clone() + } + pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { self.resolve_vars_if_possible(t).to_string() } @@ -1397,7 +1416,7 @@ impl<'tcx> InferCtxt<'tcx> { T: TypeFoldable<TyCtxt<'tcx>>, { if !value.has_infer() { - return value; // Avoid duplicated subst-folding. + return value; // Avoid duplicated type-folding. } let mut r = InferenceLiteralEraser { tcx: self.tcx }; value.fold_with(&mut r) @@ -1410,8 +1429,8 @@ impl<'tcx> InferCtxt<'tcx> { } } - pub fn probe_effect_var(&self, vid: EffectVid) -> Option<EffectVarValue<'tcx>> { - self.inner.borrow_mut().effect_unification_table().probe_value(vid) + pub fn probe_effect_var(&self, vid: EffectVid) -> Option<ty::Const<'tcx>> { + self.inner.borrow_mut().effect_unification_table().probe_value(vid).known() } /// Attempts to resolve all type/region/const variables in @@ -1444,10 +1463,10 @@ impl<'tcx> InferCtxt<'tcx> { // Instantiates the bound variables in a given binder with fresh inference // variables in the current universe. // - // Use this method if you'd like to find some substitution of the binder's + // Use this method if you'd like to find some generic parameters of the binder's // variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`] // that corresponds to your use case, consider whether or not you should - // use [`InferCtxt::instantiate_binder_with_placeholders`] instead. + // use [`InferCtxt::enter_forall`] instead. pub fn instantiate_binder_with_fresh_vars<T>( &self, span: Span, @@ -1532,9 +1551,13 @@ impl<'tcx> InferCtxt<'tcx> { /// Obtains the latest type of the given closure; this may be a /// closure in the current function, in which case its /// `ClosureKind` may not yet be known. - pub fn closure_kind(&self, closure_args: GenericArgsRef<'tcx>) -> Option<ty::ClosureKind> { - let closure_kind_ty = closure_args.as_closure().kind_ty(); - let closure_kind_ty = self.shallow_resolve(closure_kind_ty); + pub fn closure_kind(&self, closure_ty: Ty<'tcx>) -> Option<ty::ClosureKind> { + let unresolved_kind_ty = match *closure_ty.kind() { + ty::Closure(_, args) => args.as_closure().kind_ty(), + ty::CoroutineClosure(_, args) => args.as_coroutine_closure().kind_ty(), + _ => bug!("unexpected type {closure_ty}"), + }; + let closure_kind_ty = self.shallow_resolve(unresolved_kind_ty); closure_kind_ty.to_opt_closure_kind() } @@ -1585,10 +1608,10 @@ impl<'tcx> InferCtxt<'tcx> { /// Resolves and evaluates a constant. /// /// The constant can be located on a trait like `<A as B>::C`, in which case the given - /// substitutions and environment are used to resolve the constant. Alternatively if the - /// constant has generic parameters in scope the substitutions are used to evaluate the value of + /// generic parameters and environment are used to resolve the constant. Alternatively if the + /// constant has generic parameters in scope the instantiations are used to evaluate the value of /// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count - /// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still + /// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is still /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is /// returned. /// @@ -1634,7 +1657,7 @@ impl<'tcx> InferCtxt<'tcx> { let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, args: args_erased }; // The return value is the evaluated value which doesn't contain any reference to inference - // variables, thus we don't need to substitute back the original values. + // variables, thus we don't need to instantiate back the original values. tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span) } @@ -1718,6 +1741,15 @@ impl<'tcx> InferCtxt<'tcx> { } } } + + /// Attach a callback to be invoked on each root obligation evaluated in the new trait solver. + pub fn attach_obligation_inspector(&self, inspector: ObligationInspector<'tcx>) { + debug_assert!( + self.obligation_inspector.get().is_none(), + "shouldn't override a set obligation inspector" + ); + self.obligation_inspector.set(Some(inspector)); + } } impl<'tcx> TypeErrCtxt<'_, 'tcx> { @@ -1878,7 +1910,8 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> { .borrow_mut() .effect_unification_table() .probe_value(vid) - .map_or(ct, |val| val.as_const(self.infcx.tcx)), + .known() + .unwrap_or(ct), _ => ct, } } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index db46b39ce25..ec674407e52 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -219,7 +219,7 @@ impl<'tcx> InferCtxt<'tcx> { /// ``` /// /// As indicating in the comments above, each of those references - /// is (in the compiler) basically a substitution (`args`) + /// is (in the compiler) basically generic paramters (`args`) /// applied to the type of a suitable `def_id` (which identifies /// `Foo1` or `Foo2`). /// @@ -327,7 +327,6 @@ impl<'tcx> InferCtxt<'tcx> { #[instrument(level = "debug", skip(self))] pub fn register_member_constraints( &self, - param_env: ty::ParamEnv<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>, concrete_ty: Ty<'tcx>, span: Span, @@ -456,6 +455,17 @@ where args.as_closure().sig_as_fn_ptr_ty().visit_with(self); } + ty::CoroutineClosure(_, args) => { + // Skip lifetime parameters of the enclosing item(s) + + for upvar in args.as_coroutine_closure().upvar_tys() { + upvar.visit_with(self); + } + + // FIXME(async_closures): Is this the right signature to visit here? + args.as_coroutine_closure().signature_parts_ty().visit_with(self); + } + ty::Coroutine(_, args) => { // Skip lifetime parameters of the enclosing item(s) // Also skip the witness type, because that has no free regions. @@ -676,7 +686,7 @@ fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hi let res = hir_id == scope; trace!( "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}", - tcx.opt_hir_node(hir_id), + tcx.hir_node(hir_id), tcx.hir_node(opaque_hir_id), res ); diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index 6a684dba8de..9f49ed00219 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -20,7 +20,8 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { if let Some(idx) = idx { self.opaque_types.get_mut(&key).unwrap().hidden_type = idx; } else { - match self.opaque_types.remove(&key) { + // FIXME(#120456) - is `swap_remove` correct? + match self.opaque_types.swap_remove(&key) { None => bug!("reverted opaque type inference that was never registered: {:?}", key), Some(_) => {} } diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index fc3d8375873..7dd1ec32542 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -103,6 +103,11 @@ fn compute_components<'tcx>( compute_components(tcx, tupled_ty, out, visited); } + ty::CoroutineClosure(_, args) => { + let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty(); + compute_components(tcx, tupled_ty, out, visited); + } + ty::Coroutine(_, args) => { // Same as the closure case let tupled_ty = args.as_coroutine().tupled_upvars_ty(); diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 6379f84aa25..a4f9316b502 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -1,10 +1,10 @@ //! Various code related to computing outlives relations. use self::env::OutlivesEnvironment; use super::region_constraints::RegionConstraintData; -use super::{InferCtxt, RegionResolutionError}; +use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; -use rustc_middle::traits::query::OutlivesBound; +use rustc_middle::traits::query::{NoSolution, OutlivesBound}; use rustc_middle::ty; pub mod components; @@ -41,12 +41,25 @@ impl<'tcx> InferCtxt<'tcx> { /// 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`. + /// + /// If you are in a crate that has access to `rustc_trait_selection`, + /// then it's probably better to use `resolve_regions`, + /// which knows how to normalize registered region obligations. #[must_use] - pub fn resolve_regions( + pub fn resolve_regions_with_normalize( &self, outlives_env: &OutlivesEnvironment<'tcx>, + deeply_normalize_ty: impl Fn( + ty::PolyTypeOutlivesPredicate<'tcx>, + SubregionOrigin<'tcx>, + ) -> Result<ty::PolyTypeOutlivesPredicate<'tcx>, NoSolution>, ) -> Vec<RegionResolutionError<'tcx>> { - self.process_registered_region_obligations(outlives_env); + match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) { + Ok(()) => {} + Err((clause, origin)) => { + return vec![RegionResolutionError::CannotNormalize(clause, origin)]; + } + }; let (var_infos, data) = { let mut inner = self.inner.borrow_mut(); diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index d7a3bfcbc41..c0a99e5cc41 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -68,8 +68,10 @@ use crate::infer::{ use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::GenericArgKind; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate}; +use rustc_span::DUMMY_SP; use smallvec::smallvec; use super::env::OutlivesEnvironment; @@ -123,26 +125,73 @@ impl<'tcx> InferCtxt<'tcx> { /// flow of the inferencer. The key point is that it is /// invoked after all type-inference variables have been bound -- /// right before lexical region resolution. - #[instrument(level = "debug", skip(self, outlives_env))] - pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) { + #[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))] + pub fn process_registered_region_obligations( + &self, + outlives_env: &OutlivesEnvironment<'tcx>, + mut deeply_normalize_ty: impl FnMut( + PolyTypeOutlivesPredicate<'tcx>, + SubregionOrigin<'tcx>, + ) + -> Result<PolyTypeOutlivesPredicate<'tcx>, NoSolution>, + ) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> { assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot"); - let my_region_obligations = self.take_registered_region_obligations(); + let normalized_caller_bounds: Vec<_> = outlives_env + .param_env + .caller_bounds() + .iter() + .filter_map(|clause| { + let outlives = clause.as_type_outlives_clause()?; + Some( + deeply_normalize_ty( + outlives, + SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP), + ) + // FIXME(-Znext-solver): How do we accurately report an error span here :( + .map_err(|NoSolution| { + (outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)) + }), + ) + }) + .try_collect()?; - for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { - debug!(?sup_type, ?sub_region, ?origin); - let sup_type = self.resolve_vars_if_possible(sup_type); + // Must loop since the process of normalizing may itself register region obligations. + for iteration in 0.. { + let my_region_obligations = self.take_registered_region_obligations(); + if my_region_obligations.is_empty() { + break; + } - 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); + if !self.tcx.recursion_limit().value_within_limit(iteration) { + bug!( + "FIXME(-Znext-solver): Overflowed when processing region obligations: {my_region_obligations:#?}" + ); + } + + for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { + let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region)); + let ty::OutlivesPredicate(sup_type, sub_region) = + deeply_normalize_ty(outlives, origin.clone()) + .map_err(|NoSolution| (outlives, origin.clone()))? + .no_bound_vars() + .expect("started with no bound vars, should end with no bound vars"); + + debug!(?sup_type, ?sub_region, ?origin); + + let outlives = &mut TypeOutlives::new( + self, + self.tcx, + outlives_env.region_bound_pairs(), + None, + &normalized_caller_bounds, + ); + let category = origin.to_constraint_category(); + outlives.type_must_outlive(origin, sup_type, sub_region, category); + } } + + Ok(()) } } @@ -190,7 +239,7 @@ where tcx: TyCtxt<'tcx>, region_bound_pairs: &'cx RegionBoundPairs<'tcx>, implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, + caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>], ) -> Self { Self { delegate, @@ -199,7 +248,7 @@ where tcx, region_bound_pairs, implicit_region_bound, - param_env, + caller_bounds, ), } } @@ -251,9 +300,9 @@ where self.components_must_outlive(origin, subcomponents, region, category); } Component::UnresolvedInferenceVariable(v) => { - // ignore this, we presume it will yield an error - // later, since if a type variable is not resolved by - // this point it never will be + // Ignore this, we presume it will yield an error later, + // since if a type variable is not resolved by this point + // it never will be. self.tcx.dcx().span_delayed_bug( origin.span(), format!("unresolved inference variable in outlives: {v:?}"), 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 236dc4ec384..d547f51f381 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -25,7 +25,7 @@ use crate::infer::region_constraints::VerifyIfEq; /// * `None` if `some_type` cannot be made equal to `test_ty`, /// no matter the values of the variables in `exists`. /// * `Some(r)` with a suitable bound (typically the value of `bound_region`, modulo -/// any bound existential variables, which will be substituted) for the +/// any bound existential variables, which will be instantiated) for the /// type under test. /// /// NB: This function uses a simplistic, syntactic version of type equality. @@ -59,7 +59,7 @@ pub fn extract_verify_if_eq<'tcx>( } } else { // The region does not contain any bound variables, so we don't need - // to do any substitution. + // to do any instantiation. // // Example: // diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 7a85268492b..3ef37bf3466 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -23,7 +23,7 @@ pub struct VerifyBoundCx<'cx, 'tcx> { /// Outside of borrowck the only way to prove `T: '?0` is by /// setting `'?0` to `'empty`. implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, + caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>], } impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { @@ -31,9 +31,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { tcx: TyCtxt<'tcx>, region_bound_pairs: &'cx RegionBoundPairs<'tcx>, implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, + caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>], ) -> Self { - Self { tcx, region_bound_pairs, implicit_region_bound, param_env } + Self { tcx, region_bound_pairs, implicit_region_bound, caller_bounds } } #[instrument(level = "debug", skip(self))] @@ -172,13 +172,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { self.bound_from_components(components, visited) } Component::UnresolvedInferenceVariable(v) => { - // ignore this, we presume it will yield an error - // later, since if a type variable is not resolved by - // this point it never will be + // Ignore this, we presume it will yield an error later, since + // if a type variable is not resolved by this point it never + // will be. self.tcx .dcx() .delayed_bug(format!("unresolved inference variable in outlives: {v:?}")); - // add a bound that never holds + // Add a bound that never holds. VerifyBound::AnyBound(vec![]) } } @@ -219,8 +219,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // To start, collect bounds from user environment. Note that // parameter environments are already elaborated, so we don't // have to worry about that. - let c_b = self.param_env.caller_bounds(); - let param_bounds = self.collect_outlives_from_clause_list(erased_ty, c_b.into_iter()); + let param_bounds = self.caller_bounds.iter().copied().filter(move |outlives_predicate| { + super::test_type_match::can_match_erased_ty(tcx, *outlives_predicate, erased_ty) + }); // Next, collect regions we scraped from the well-formedness // constraints in the fn signature. To do that, we walk the list @@ -276,7 +277,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// ``` /// /// If we were given the `DefId` of `Foo::Bar`, we would return - /// `'a`. You could then apply the substitutions from the + /// `'a`. You could then apply the instantiations from the /// projection to convert this into your namespace. This also /// works if the user writes `where <Self as Foo<'a>>::Bar: 'a` on /// the trait. In fact, it works by searching for just such a @@ -307,22 +308,4 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { .filter_map(|p| p.no_bound_vars()) .map(|OutlivesPredicate(_, r)| r) } - - /// Searches through a predicate list for a predicate `T: 'a`. - /// - /// Careful: does not elaborate predicates, and just uses `==` - /// when comparing `ty` for equality, so `ty` must be something - /// that does not involve inference variables and where you - /// otherwise want a precise match. - fn collect_outlives_from_clause_list( - &self, - erased_ty: Ty<'tcx>, - clauses: impl Iterator<Item = ty::Clause<'tcx>>, - ) -> impl Iterator<Item = ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> - { - let tcx = self.tcx; - clauses.filter_map(|p| p.as_type_outlives_clause()).filter(move |outlives_predicate| { - super::test_type_match::can_match_erased_ty(tcx, *outlives_predicate, erased_ty) - }) - } } diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 9e1dab12b4d..f7690831c2a 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -23,19 +23,18 @@ //! this should be correctly updated. use super::equate::Equate; -use super::generalize::{self, CombineDelegate, Generalization}; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; use rustc_middle::infer::canonical::OriginalQueryValues; -use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue}; +use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{RelateResult, TypeRelation}; use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; -use rustc_middle::ty::{AliasRelationDirection, TyVar}; use rustc_middle::ty::{IntType, UintType}; +use rustc_span::Span; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -165,9 +164,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. - let compatible_types = self.probe(|_| { + self.probe(|_| { if a.ty() == b.ty() { - return Ok(()); + return; } // We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the @@ -177,51 +176,33 @@ impl<'tcx> InferCtxt<'tcx> { relation.param_env().and((a.ty(), b.ty())), &mut OriginalQueryValues::default(), ); - self.tcx.check_tys_might_be_eq(canonical).map_err(|_| { + self.tcx.check_tys_might_be_eq(canonical).unwrap_or_else(|_| { + // The error will only be reported later. If we emit an ErrorGuaranteed + // here, then we will never get to the code that actually emits the error. self.tcx.dcx().delayed_bug(format!( "cannot relate consts of different types (a={a:?}, b={b:?})", - )) - }) + )); + // We treat these constants as if they were of the same type, so that any + // such constants being used in impls make these impls match barring other mismatches. + // This helps with diagnostics down the road. + }); }); - // 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 = ty::Const::new_error(self.tcx, guar, a.ty()); - if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() { - return self.unify_const_variable(vid, a_error, relation.param_env()); - } - let b_error = ty::Const::new_error(self.tcx, guar, b.ty()); - if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() { - return self.unify_const_variable(vid, b_error, relation.param_env()); - } - - return Ok(if relation.a_is_expected() { a_error } else { b_error }); - } - match (a.kind(), b.kind()) { ( ty::ConstKind::Infer(InferConst::Var(a_vid)), ty::ConstKind::Infer(InferConst::Var(b_vid)), ) => { self.inner.borrow_mut().const_unification_table().union(a_vid, b_vid); - return Ok(a); + Ok(a) } ( ty::ConstKind::Infer(InferConst::EffectVar(a_vid)), ty::ConstKind::Infer(InferConst::EffectVar(b_vid)), ) => { - self.inner - .borrow_mut() - .effect_unification_table() - .unify_var_var(a_vid, b_vid) - .map_err(|a| effect_unification_error(self.tcx, relation.a_is_expected(), a))?; - return Ok(a); + self.inner.borrow_mut().effect_unification_table().union(a_vid, b_vid); + Ok(a) } // All other cases of inference with other variables are errors. @@ -239,27 +220,21 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(vid, b, relation.param_env()); + self.instantiate_const_var(relation, relation.a_is_expected(), vid, b)?; + Ok(b) } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(vid, a, relation.param_env()); + self.instantiate_const_var(relation, !relation.a_is_expected(), vid, a)?; + Ok(a) } (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => { - return self.unify_effect_variable( - relation.a_is_expected(), - vid, - EffectVarValue::Const(b), - ); + Ok(self.unify_effect_variable(vid, b)) } (_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => { - return self.unify_effect_variable( - !relation.a_is_expected(), - vid, - EffectVarValue::Const(a), - ); + Ok(self.unify_effect_variable(vid, a)) } (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) @@ -267,7 +242,7 @@ impl<'tcx> InferCtxt<'tcx> { { let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) }; - relation.register_predicates([ty::Binder::dummy(if self.next_trait_solver() { + relation.register_predicates([if self.next_trait_solver() { ty::PredicateKind::AliasRelate( a.into(), b.into(), @@ -275,78 +250,12 @@ impl<'tcx> InferCtxt<'tcx> { ) } else { ty::PredicateKind::ConstEquate(a, b) - })]); + }]); - return Ok(b); + Ok(b) } - _ => {} + _ => ty::relate::structurally_relate_consts(relation, a, b), } - - ty::relate::structurally_relate_consts(relation, a, b) - } - - /// Unifies the const variable `target_vid` with the given constant. - /// - /// This also tests if the given const `ct` contains an inference variable which was previously - /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct` - /// would result in an infinite type as we continuously replace an inference variable - /// in `ct` with `ct` itself. - /// - /// This is especially important as unevaluated consts use their parents generics. - /// They therefore often contain unused args, making these errors far more likely. - /// - /// A good example of this is the following: - /// - /// ```compile_fail,E0308 - /// #![feature(generic_const_exprs)] - /// - /// fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] { - /// todo!() - /// } - /// - /// fn main() { - /// let mut arr = Default::default(); - /// arr = bind(arr); - /// } - /// ``` - /// - /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics - /// of `fn bind` (meaning that its args contain `N`). - /// - /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`. - /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`. - /// - /// As `3 + 4` contains `N` in its args, this must not succeed. - /// - /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. - #[instrument(level = "debug", skip(self))] - fn unify_const_variable( - &self, - target_vid: ty::ConstVid, - ct: ty::Const<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - let span = match self.inner.borrow_mut().const_unification_table().probe_value(target_vid) { - ConstVariableValue::Known { value } => { - bug!("instantiating a known const var: {target_vid:?} {value} {ct}") - } - ConstVariableValue::Unknown { origin, universe: _ } => origin.span, - }; - // FIXME(generic_const_exprs): Occurs check failures for unevaluated - // constants and generic expressions are not yet handled correctly. - let Generalization { value_may_be_infer: value, needs_wf: _ } = generalize::generalize( - self, - &mut CombineDelegate { infcx: self, span }, - ct, - target_vid, - ty::Variance::Invariant, - )?; - - self.inner - .borrow_mut() - .const_unification_table() - .union_value(target_vid, ConstVariableValue::Known { value }); - Ok(value) } fn unify_integral_variable( @@ -380,18 +289,12 @@ impl<'tcx> InferCtxt<'tcx> { Ok(Ty::new_float(self.tcx, val)) } - fn unify_effect_variable( - &self, - vid_is_expected: bool, - vid: ty::EffectVid, - val: EffectVarValue<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { + fn unify_effect_variable(&self, vid: ty::EffectVid, val: ty::Const<'tcx>) -> ty::Const<'tcx> { self.inner .borrow_mut() .effect_unification_table() - .unify_var_value(vid, Some(val)) - .map_err(|e| effect_unification_error(self.tcx, vid_is_expected, e))?; - Ok(val.as_const(self.tcx)) + .union_value(vid, EffectVarValue::Known(val)); + val } } @@ -416,131 +319,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { Glb::new(self, a_is_expected) } - /// Here, `dir` is either `EqTo`, `SubtypeOf`, or `SupertypeOf`. - /// The idea is that we should ensure that the type `a_ty` is equal - /// to, a subtype of, or a supertype of (respectively) the type - /// to which `b_vid` is bound. - /// - /// Since `b_vid` has not yet been instantiated with a type, we - /// will first instantiate `b_vid` with a *generalized* version - /// of `a_ty`. Generalization introduces other inference - /// variables wherever subtyping could occur. - #[instrument(skip(self), level = "debug")] - pub fn instantiate( - &mut self, - a_ty: Ty<'tcx>, - ambient_variance: ty::Variance, - b_vid: ty::TyVid, - a_is_expected: bool, - ) -> RelateResult<'tcx, ()> { - // Get the actual variable that b_vid has been inferred to - debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown()); - - // Generalize type of `a_ty` appropriately depending on the - // direction. As an example, assume: - // - // - `a_ty == &'x ?1`, where `'x` is some free region and `?1` is an - // inference variable, - // - and `dir` == `SubtypeOf`. - // - // Then the generalized form `b_ty` would be `&'?2 ?3`, where - // `'?2` and `?3` are fresh region/type inference - // variables. (Down below, we will relate `a_ty <: b_ty`, - // adding constraints like `'x: '?2` and `?1 <: ?3`.) - let Generalization { value_may_be_infer: b_ty, needs_wf } = generalize::generalize( - self.infcx, - &mut CombineDelegate { infcx: self.infcx, span: self.trace.span() }, - a_ty, - b_vid, - ambient_variance, - )?; - - // Constrain `b_vid` to the generalized type `b_ty`. - if let &ty::Infer(TyVar(b_ty_vid)) = b_ty.kind() { - self.infcx.inner.borrow_mut().type_variables().equate(b_vid, b_ty_vid); - } else { - self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty); - } - - if needs_wf { - self.obligations.push(Obligation::new( - self.tcx(), - self.trace.cause.clone(), - self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( - b_ty.into(), - ))), - )); - } - - // Finally, relate `b_ty` to `a_ty`, as described in previous comment. - // - // FIXME(#16847): This code is non-ideal because all these subtype - // relations wind up attributed to the same spans. We need - // to associate causes/spans with each of the relations in - // the stack to get this right. - if b_ty.is_ty_var() { - // This happens for cases like `<?0 as Trait>::Assoc == ?0`. - // We can't instantiate `?0` here as that would result in a - // cyclic type. We instead delay the unification in case - // the alias can be normalized to something which does not - // mention `?0`. - if self.infcx.next_trait_solver() { - let (lhs, rhs, direction) = match ambient_variance { - ty::Variance::Invariant => { - (a_ty.into(), b_ty.into(), AliasRelationDirection::Equate) - } - ty::Variance::Covariant => { - (a_ty.into(), b_ty.into(), AliasRelationDirection::Subtype) - } - ty::Variance::Contravariant => { - (b_ty.into(), a_ty.into(), AliasRelationDirection::Subtype) - } - ty::Variance::Bivariant => unreachable!("bivariant generalization"), - }; - self.obligations.push(Obligation::new( - self.tcx(), - self.trace.cause.clone(), - self.param_env, - ty::PredicateKind::AliasRelate(lhs, rhs, direction), - )); - } else { - match a_ty.kind() { - &ty::Alias(ty::Projection, data) => { - // FIXME: This does not handle subtyping correctly, we could - // instead create a new inference variable for `a_ty`, emitting - // `Projection(a_ty, a_infer)` and `a_infer <: b_ty`. - self.obligations.push(Obligation::new( - self.tcx(), - self.trace.cause.clone(), - self.param_env, - ty::ProjectionPredicate { projection_ty: data, term: b_ty.into() }, - )) - } - // The old solver only accepts projection predicates for associated types. - ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => { - return Err(TypeError::CyclicTy(a_ty)); - } - _ => bug!("generalizated `{a_ty:?} to infer, not an alias"), - } - } - } else { - match ambient_variance { - ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty), - ty::Variance::Covariant => self.sub(a_is_expected).relate(a_ty, b_ty), - ty::Variance::Contravariant => self.sub(a_is_expected).relate_with_variance( - ty::Contravariant, - ty::VarianceDiagInfo::default(), - a_ty, - b_ty, - ), - ty::Variance::Bivariant => unreachable!("bivariant generalization"), - }?; - } - - Ok(()) - } - pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.obligations.extend(obligations); } @@ -553,6 +331,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { } pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { + fn span(&self) -> Span; + fn param_env(&self) -> ty::ParamEnv<'tcx>; /// Register obligations that must hold in order for this relation to hold @@ -593,11 +373,3 @@ fn float_unification_error<'tcx>( let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b)) } - -fn effect_unification_error<'tcx>( - _tcx: TyCtxt<'tcx>, - _a_is_expected: bool, - (_a, _b): (EffectVarValue<'tcx>, EffectVarValue<'tcx>), -) -> TypeError<'tcx> { - bug!("unexpected effect unification error") -} diff --git a/compiler/rustc_infer/src/infer/relate/equate.rs b/compiler/rustc_infer/src/infer/relate/equate.rs index cb62f258373..aefa9a5a0d6 100644 --- a/compiler/rustc_infer/src/infer/relate/equate.rs +++ b/compiler/rustc_infer/src/infer/relate/equate.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_hir::def_id::DefId; +use rustc_span::Span; /// Ensures `a` is made equal to `b`. Returns `a` on success. pub struct Equate<'combine, 'infcx, 'tcx> { @@ -81,12 +82,17 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { infcx.inner.borrow_mut().type_variables().equate(a_id, b_id); } - (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, ty::Invariant, a_id, self.a_is_expected)?; + (&ty::Infer(TyVar(a_vid)), _) => { + infcx.instantiate_ty_var(self, self.a_is_expected, a_vid, ty::Invariant, b)?; } - (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, ty::Invariant, b_id, self.a_is_expected)?; + (_, &ty::Infer(TyVar(b_vid))) => { + infcx.instantiate_ty_var(self, !self.a_is_expected, b_vid, ty::Invariant, a)?; + } + + (&ty::Error(e), _) | (_, &ty::Error(e)) => { + infcx.set_tainted_by_errors(e); + return Ok(Ty::new_error(self.tcx(), e)); } ( @@ -170,6 +176,10 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { } impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> { + fn span(&self) -> Span { + self.fields.trace.span() + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 417c8695e24..90f10a0eba9 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -1,5 +1,7 @@ use std::mem; +use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind, TypeVariableValue}; +use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; @@ -7,98 +9,241 @@ use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::MaxUniverse; -use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{AliasRelationDirection, InferConst, Term, TypeVisitable, TypeVisitableExt}; use rustc_span::Span; -use crate::infer::nll_relate::TypeRelatingDelegate; -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind, TypeVariableValue}; -use crate::infer::{InferCtxt, RegionVariableOrigin}; - -/// Attempts to generalize `term` for the type variable `for_vid`. -/// This checks for cycles -- that is, whether the type `term` -/// references `for_vid`. -pub fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> + Relate<'tcx>>( - infcx: &InferCtxt<'tcx>, - delegate: &mut D, - term: T, - for_vid: impl Into<ty::TermVid>, - ambient_variance: ty::Variance, -) -> RelateResult<'tcx, Generalization<T>> { - let (for_universe, root_vid) = match for_vid.into() { - ty::TermVid::Ty(ty_vid) => ( - infcx.probe_ty_var(ty_vid).unwrap_err(), - ty::TermVid::Ty(infcx.inner.borrow_mut().type_variables().sub_root_var(ty_vid)), - ), - ty::TermVid::Const(ct_vid) => ( - infcx.probe_const_var(ct_vid).unwrap_err(), - ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid).vid), - ), - }; - - let mut generalizer = Generalizer { - infcx, - delegate, - ambient_variance, - root_vid, - for_universe, - root_term: term.into(), - in_alias: false, - needs_wf: false, - cache: Default::default(), - }; - - assert!(!term.has_escaping_bound_vars()); - let value_may_be_infer = generalizer.relate(term, term)?; - let needs_wf = generalizer.needs_wf; - Ok(Generalization { value_may_be_infer, needs_wf }) -} - -/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking -/// in the generalizer code. -pub trait GeneralizerDelegate<'tcx> { - fn forbid_inference_vars() -> bool; - - fn span(&self) -> Span; +impl<'tcx> InferCtxt<'tcx> { + /// The idea is that we should ensure that the type variable `target_vid` + /// is equal to, a subtype of, or a supertype of `source_ty`. + /// + /// For this, we will instantiate `target_vid` with a *generalized* version + /// of `source_ty`. Generalization introduces other inference variables wherever + /// subtyping could occur. This also does the occurs checks, detecting whether + /// instantiating `target_vid` would result in a cyclic type. We eagerly error + /// in this case. + /// + /// This is *not* expected to be used anywhere except for an implementation of + /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all + /// other usecases (i.e. setting the value of a type var). + #[instrument(level = "debug", skip(self, relation, target_is_expected))] + pub fn instantiate_ty_var<R: ObligationEmittingRelation<'tcx>>( + &self, + relation: &mut R, + target_is_expected: bool, + target_vid: ty::TyVid, + ambient_variance: ty::Variance, + source_ty: Ty<'tcx>, + ) -> RelateResult<'tcx, ()> { + debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()); + + // Generalize `source_ty` depending on the current variance. As an example, assume + // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference + // variable. + // + // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh + // region/type inference variables. + // + // We then relate `generalized_ty <: source_ty`,adding constraints like `'x: '?2` and `?1 <: ?3`. + let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = + self.generalize(relation.span(), target_vid, ambient_variance, source_ty)?; + + // Constrain `b_vid` to the generalized type `generalized_ty`. + if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() { + self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid); + } else { + self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty); + } - fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; -} + // See the comment on `Generalization::has_unconstrained_ty_var`. + if has_unconstrained_ty_var { + relation.register_predicates([ty::ClauseKind::WellFormed(generalized_ty.into())]); + } -pub struct CombineDelegate<'cx, 'tcx> { - pub infcx: &'cx InferCtxt<'tcx>, - pub span: Span, -} + // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment. + // + // FIXME(#16847): This code is non-ideal because all these subtype + // relations wind up attributed to the same spans. We need + // to associate causes/spans with each of the relations in + // the stack to get this right. + if generalized_ty.is_ty_var() { + // This happens for cases like `<?0 as Trait>::Assoc == ?0`. + // We can't instantiate `?0` here as that would result in a + // cyclic type. We instead delay the unification in case + // the alias can be normalized to something which does not + // mention `?0`. + if self.next_trait_solver() { + let (lhs, rhs, direction) = match ambient_variance { + ty::Variance::Invariant => { + (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Equate) + } + ty::Variance::Covariant => { + (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Subtype) + } + ty::Variance::Contravariant => { + (source_ty.into(), generalized_ty.into(), AliasRelationDirection::Subtype) + } + ty::Variance::Bivariant => unreachable!("bivariant generalization"), + }; -impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> { - fn forbid_inference_vars() -> bool { - false - } + relation.register_predicates([ty::PredicateKind::AliasRelate(lhs, rhs, direction)]); + } else { + match source_ty.kind() { + &ty::Alias(ty::Projection, data) => { + // FIXME: This does not handle subtyping correctly, we could + // instead create a new inference variable `?normalized_source`, emitting + // `Projection(normalized_source, ?ty_normalized)` and `?normalized_source <: generalized_ty`. + relation.register_predicates([ty::ProjectionPredicate { + projection_ty: data, + term: generalized_ty.into(), + }]); + } + // The old solver only accepts projection predicates for associated types. + ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => { + return Err(TypeError::CyclicTy(source_ty)); + } + _ => bug!("generalized `{source_ty:?} to infer, not an alias"), + } + } + } else { + // HACK: make sure that we `a_is_expected` continues to be + // correct when relating the generalized type with the source. + if target_is_expected == relation.a_is_expected() { + relation.relate_with_variance( + ambient_variance, + ty::VarianceDiagInfo::default(), + generalized_ty, + source_ty, + )?; + } else { + relation.relate_with_variance( + ambient_variance.xform(ty::Contravariant), + ty::VarianceDiagInfo::default(), + source_ty, + generalized_ty, + )?; + } + } - fn span(&self) -> Span { - self.span + Ok(()) } - fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - self.infcx - .next_region_var_in_universe(RegionVariableOrigin::MiscVariable(self.span), universe) - } -} + /// Instantiates the const variable `target_vid` with the given constant. + /// + /// This also tests if the given const `ct` contains an inference variable which was previously + /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct` + /// would result in an infinite type as we continuously replace an inference variable + /// in `ct` with `ct` itself. + /// + /// This is especially important as unevaluated consts use their parents generics. + /// They therefore often contain unused args, making these errors far more likely. + /// + /// A good example of this is the following: + /// + /// ```compile_fail,E0308 + /// #![feature(generic_const_exprs)] + /// + /// fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] { + /// todo!() + /// } + /// + /// fn main() { + /// let mut arr = Default::default(); + /// arr = bind(arr); + /// } + /// ``` + /// + /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics + /// of `fn bind` (meaning that its args contain `N`). + /// + /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`. + /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`. + /// + /// As `3 + 4` contains `N` in its args, this must not succeed. + /// + /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. + #[instrument(level = "debug", skip(self, relation))] + pub(super) fn instantiate_const_var<R: ObligationEmittingRelation<'tcx>>( + &self, + relation: &mut R, + target_is_expected: bool, + target_vid: ty::ConstVid, + source_ct: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ()> { + // FIXME(generic_const_exprs): Occurs check failures for unevaluated + // constants and generic expressions are not yet handled correctly. + let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = + self.generalize(relation.span(), target_vid, ty::Variance::Invariant, source_ct)?; + + debug_assert!(!generalized_ct.is_ct_infer()); + if has_unconstrained_ty_var { + bug!("unconstrained ty var when generalizing `{source_ct:?}`"); + } -impl<'tcx, T> GeneralizerDelegate<'tcx> for T -where - T: TypeRelatingDelegate<'tcx>, -{ - fn forbid_inference_vars() -> bool { - <Self as TypeRelatingDelegate<'tcx>>::forbid_inference_vars() - } + self.inner + .borrow_mut() + .const_unification_table() + .union_value(target_vid, ConstVariableValue::Known { value: generalized_ct }); + + // HACK: make sure that we `a_is_expected` continues to be + // correct when relating the generalized type with the source. + if target_is_expected == relation.a_is_expected() { + relation.relate_with_variance( + ty::Variance::Invariant, + ty::VarianceDiagInfo::default(), + generalized_ct, + source_ct, + )?; + } else { + relation.relate_with_variance( + ty::Variance::Invariant, + ty::VarianceDiagInfo::default(), + source_ct, + generalized_ct, + )?; + } - fn span(&self) -> Span { - <Self as TypeRelatingDelegate<'tcx>>::span(&self) + Ok(()) } - fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - <Self as TypeRelatingDelegate<'tcx>>::generalize_existential(self, universe) + /// Attempts to generalize `source_term` for the type variable `target_vid`. + /// This checks for cycles -- that is, whether `source_term` references `target_vid`. + fn generalize<T: Into<Term<'tcx>> + Relate<'tcx>>( + &self, + span: Span, + target_vid: impl Into<ty::TermVid>, + ambient_variance: ty::Variance, + source_term: T, + ) -> RelateResult<'tcx, Generalization<T>> { + assert!(!source_term.has_escaping_bound_vars()); + let (for_universe, root_vid) = match target_vid.into() { + ty::TermVid::Ty(ty_vid) => ( + self.probe_ty_var(ty_vid).unwrap_err(), + ty::TermVid::Ty(self.inner.borrow_mut().type_variables().sub_root_var(ty_vid)), + ), + ty::TermVid::Const(ct_vid) => ( + self.probe_const_var(ct_vid).unwrap_err(), + ty::TermVid::Const( + self.inner.borrow_mut().const_unification_table().find(ct_vid).vid, + ), + ), + }; + + let mut generalizer = Generalizer { + infcx: self, + span, + root_vid, + for_universe, + ambient_variance, + root_term: source_term.into(), + in_alias: false, + has_unconstrained_ty_var: false, + cache: Default::default(), + }; + + let value_may_be_infer = generalizer.relate(source_term, source_term)?; + let has_unconstrained_ty_var = generalizer.has_unconstrained_ty_var; + Ok(Generalization { value_may_be_infer, has_unconstrained_ty_var }) } } @@ -115,18 +260,10 @@ where /// establishes `'0: 'x` as a constraint. /// /// [blog post]: https://is.gd/0hKvIr -struct Generalizer<'me, 'tcx, D> { +struct Generalizer<'me, 'tcx> { infcx: &'me InferCtxt<'tcx>, - /// This is used to abstract the behaviors of the three previous - /// generalizer-like implementations (`Generalizer`, `TypeGeneralizer`, - /// and `ConstInferUnifier`). See [`GeneralizerDelegate`] for more - /// information. - delegate: &'me mut D, - - /// After we generalize this type, we are going to relate it to - /// some other type. What will be the variance at this point? - ambient_variance: ty::Variance, + span: Span, /// The vid of the type variable that is in the process of being /// instantiated. If we find this within the value we are folding, @@ -138,6 +275,10 @@ struct Generalizer<'me, 'tcx, D> { /// we reject the relation. for_universe: ty::UniverseIndex, + /// After we generalize this type, we are going to relate it to + /// some other type. What will be the variance at this point? + ambient_variance: ty::Variance, + /// The root term (const or type) we're generalizing. Used for cycle errors. root_term: Term<'tcx>, @@ -150,11 +291,11 @@ struct Generalizer<'me, 'tcx, D> { /// hold by either normalizing the outer or the inner associated type. in_alias: bool, - /// See the field `needs_wf` in `Generalization`. - needs_wf: bool, + /// See the field `has_unconstrained_ty_var` in `Generalization`. + has_unconstrained_ty_var: bool, } -impl<'tcx, D> Generalizer<'_, 'tcx, D> { +impl<'tcx> Generalizer<'_, 'tcx> { /// Create an error that corresponds to the term kind in `root_term` fn cyclic_term_error(&self) -> TypeError<'tcx> { match self.root_term.unpack() { @@ -162,12 +303,52 @@ impl<'tcx, D> Generalizer<'_, 'tcx, D> { ty::TermKind::Const(ct) => TypeError::CyclicConst(ct), } } + + /// An occurs check failure inside of an alias does not mean + /// that the types definitely don't unify. We may be able + /// to normalize the alias after all. + /// + /// We handle this by lazily equating the alias and generalizing + /// it to an inference variable. + /// + /// This is incomplete and will hopefully soon get fixed by #119106. + fn generalize_alias_ty( + &mut self, + alias: ty::AliasTy<'tcx>, + ) -> Result<Ty<'tcx>, TypeError<'tcx>> { + let is_nested_alias = mem::replace(&mut self.in_alias, true); + let result = match self.relate(alias, alias) { + Ok(alias) => Ok(alias.to_ty(self.tcx())), + Err(e) => { + if is_nested_alias { + return Err(e); + } else { + let mut visitor = MaxUniverse::new(); + alias.visit_with(&mut visitor); + let infer_replacement_is_complete = + self.for_universe.can_name(visitor.max_universe()) + && !alias.has_escaping_bound_vars(); + if !infer_replacement_is_complete { + warn!("may incompletely handle alias type: {alias:?}"); + } + + debug!("generalization failure in alias"); + Ok(self.infcx.next_ty_var_in_universe( + TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: self.span, + }, + self.for_universe, + )) + } + } + }; + self.in_alias = is_nested_alias; + result + } } -impl<'tcx, D> TypeRelation<'tcx> for Generalizer<'_, 'tcx, D> -where - D: GeneralizerDelegate<'tcx>, -{ +impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -183,14 +364,14 @@ where fn relate_item_args( &mut self, item_def_id: DefId, - a_subst: ty::GenericArgsRef<'tcx>, - b_subst: ty::GenericArgsRef<'tcx>, + a_arg: ty::GenericArgsRef<'tcx>, + b_arg: ty::GenericArgsRef<'tcx>, ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> { if self.ambient_variance == ty::Variance::Invariant { // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles // (e.g., #41849). - relate::relate_args_invariantly(self, a_subst, b_subst) + relate::relate_args_invariantly(self, a_arg, b_arg) } else { let tcx = self.tcx(); let opt_variances = tcx.variances_of(item_def_id); @@ -198,8 +379,8 @@ where self, item_def_id, opt_variances, - a_subst, - b_subst, + a_arg, + b_arg, false, ) } @@ -236,12 +417,6 @@ where // subtyping. This is basically our "occurs check", preventing // us from creating infinitely sized types. let g = match *t.kind() { - ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) - if D::forbid_inference_vars() => - { - bug!("unexpected inference variable encountered in NLL generalization: {t}"); - } - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("unexpected infer type: {t}") } @@ -272,11 +447,10 @@ where } } - // Bivariant: make a fresh var, but we - // may need a WF predicate. See - // comment on `needs_wf` field for - // more info. - ty::Bivariant => self.needs_wf = true, + // Bivariant: make a fresh var, but remember that + // it is unconstrained. See the comment in + // `Generalization`. + ty::Bivariant => self.has_unconstrained_ty_var = true, // Co/contravariant: this will be // sufficiently constrained later on. @@ -318,43 +492,7 @@ where } } - ty::Alias(kind, data) => { - // An occurs check failure inside of an alias does not mean - // that the types definitely don't unify. We may be able - // to normalize the alias after all. - // - // We handle this by lazily equating the alias and generalizing - // it to an inference variable. - let is_nested_alias = mem::replace(&mut self.in_alias, true); - let result = match self.relate(data, data) { - Ok(data) => Ok(Ty::new_alias(self.tcx(), kind, data)), - Err(e) => { - if is_nested_alias { - return Err(e); - } else { - let mut visitor = MaxUniverse::new(); - t.visit_with(&mut visitor); - let infer_replacement_is_complete = - self.for_universe.can_name(visitor.max_universe()) - && !t.has_escaping_bound_vars(); - if !infer_replacement_is_complete { - warn!("may incompletely handle alias type: {t:?}"); - } - - debug!("generalization failure in alias"); - Ok(self.infcx.next_ty_var_in_universe( - TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: self.delegate.span(), - }, - self.for_universe, - )) - } - } - }; - self.in_alias = is_nested_alias; - result - } + ty::Alias(_, data) => self.generalize_alias_ty(data), _ => relate::structurally_relate_tys(self, t, t), }?; @@ -403,7 +541,10 @@ where } } - Ok(self.delegate.generalize_region(self.for_universe)) + Ok(self.infcx.next_region_var_in_universe( + RegionVariableOrigin::MiscVariable(self.span), + self.for_universe, + )) } #[instrument(level = "debug", skip(self, c2), ret)] @@ -415,9 +556,6 @@ where assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be == match c.kind() { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { - bug!("unexpected inference variable encountered in NLL generalization: {:?}", c); - } ty::ConstKind::Infer(InferConst::Var(vid)) => { // If root const vids are equal, then `root_vid` and // `vid` are related and we'd be inferring an infinitely @@ -452,6 +590,9 @@ where } } ty::ConstKind::Infer(InferConst::EffectVar(_)) => Ok(c), + // FIXME: Unevaluated constants are also not rigid, so the current + // approach of always relating them structurally is incomplete. + // // FIXME: remove this branch once `structurally_relate_consts` is fully // structural. ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => { @@ -511,30 +652,27 @@ pub struct Generalization<T> { /// recursion. pub value_may_be_infer: T, - /// If true, then the generalized type may not be well-formed, - /// even if the source type is well-formed, so we should add an - /// additional check to enforce that it is. This arises in - /// particular around 'bivariant' type parameters that are only - /// constrained by a where-clause. As an example, imagine a type: + /// In general, we do not check whether all types which occur during + /// type checking are well-formed. We only check wf of user-provided types + /// and when actually using a type, e.g. for method calls. + /// + /// This means that when subtyping, we may end up with unconstrained + /// inference variables if a generalized type has bivariant parameters. + /// A parameter may only be bivariant if it is constrained by a projection + /// bound in a where-clause. As an example, imagine a type: /// /// struct Foo<A, B> where A: Iterator<Item = B> { /// data: A /// } /// - /// here, `A` will be covariant, but `B` is - /// unconstrained. However, whatever it is, for `Foo` to be WF, it - /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`, - /// then after generalization we will wind up with a type like - /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C, - /// ?D>` (or `>:`), we will wind up with the requirement that `?A - /// <: ?C`, but no particular relationship between `?B` and `?D` - /// (after all, we do not know the variance of the normalized form - /// of `A::Item` with respect to `A`). If we do nothing else, this - /// may mean that `?D` goes unconstrained (as in #41677). So, in - /// this scenario where we create a new type variable in a - /// bivariant context, we set the `needs_wf` flag to true. This - /// will force the calling code to check that `WF(Foo<?C, ?D>)` - /// holds, which in turn implies that `?C::Item == ?D`. So once - /// `?C` is constrained, that should suffice to restrict `?D`. - pub needs_wf: bool, + /// here, `A` will be covariant, but `B` is unconstrained. + /// + /// However, whatever it is, for `Foo` to be WF, it must be equal to `A::Item`. + /// If we have an input `Foo<?A, ?B>`, then after generalization we will wind + /// up with a type like `Foo<?C, ?D>`. When we enforce `Foo<?A, ?B> <: Foo<?C, ?D>`, + /// we will wind up with the requirement that `?A <: ?C`, but no particular + /// relationship between `?B` and `?D` (after all, these types may be completely + /// different). If we do nothing else, this may mean that `?D` goes unconstrained + /// (as in #41677). To avoid this we emit a `WellFormed` obligation in these cases. + pub has_unconstrained_ty_var: bool, } diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index aa89124301e..6cf51354599 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -2,6 +2,7 @@ use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; use super::combine::{CombineFields, ObligationEmittingRelation}; use super::lattice::{self, LatticeDir}; @@ -134,6 +135,10 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, } impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> { + fn span(&self) -> Span { + self.fields.trace.span() + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 440df8c8936..90be80f67b4 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -38,24 +38,25 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { // First, we instantiate each bound region in the supertype with a // fresh placeholder region. Note that this automatically creates // a new universe if needed. - let sup_prime = self.infcx.instantiate_binder_with_placeholders(sup); + self.infcx.enter_forall(sup, |sup_prime| { + // Next, we instantiate each bound region in the subtype + // with a fresh region variable. These region variables -- + // but no other preexisting region variables -- can name + // the placeholders. + let sub_prime = + self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub); + debug!("a_prime={:?}", sub_prime); + debug!("b_prime={:?}", sup_prime); - // Next, we instantiate each bound region in the subtype - // with a fresh region variable. These region variables -- - // but no other preexisting region variables -- can name - // the placeholders. - let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub); - - debug!("a_prime={:?}", sub_prime); - debug!("b_prime={:?}", sup_prime); - - // Compare types now that bound regions have been replaced. - let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime)?; - - debug!("OK result={result:?}"); - // NOTE: returning the result here would be dangerous as it contains - // placeholders which **must not** be named afterwards. - Ok(()) + // Compare types now that bound regions have been replaced. + let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime); + if result.is_ok() { + debug!("OK result={result:?}"); + } + // NOTE: returning the result here would be dangerous as it contains + // placeholders which **must not** be named afterwards. + result.map(|_| ()) + }) } } @@ -68,9 +69,11 @@ impl<'tcx> InferCtxt<'tcx> { /// This is the first step of checking subtyping when higher-ranked things are involved. /// For more details visit the relevant sections of the [rustc dev guide]. /// + /// `fn enter_forall` should be preferred over this method. + /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html #[instrument(level = "debug", skip(self), ret)] - pub fn instantiate_binder_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T + pub fn enter_forall_and_leak_universe<T>(&self, binder: ty::Binder<'tcx, T>) -> T where T: TypeFoldable<TyCtxt<'tcx>> + Copy, { @@ -106,6 +109,31 @@ impl<'tcx> InferCtxt<'tcx> { self.tcx.replace_bound_vars_uncached(binder, delegate) } + /// Replaces all bound variables (lifetimes, types, and constants) bound by + /// `binder` with placeholder variables in a new universe and then calls the + /// closure `f` with the instantiated value. The new placeholders can only be + /// named by inference variables created inside of the closure `f` or afterwards. + /// + /// This is the first step of checking subtyping when higher-ranked things are involved. + /// For more details visit the relevant sections of the [rustc dev guide]. + /// + /// This method should be preferred over `fn enter_forall_and_leak_universe`. + /// + /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html + #[instrument(level = "debug", skip(self, f))] + pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U + where + T: TypeFoldable<TyCtxt<'tcx>> + Copy, + { + // FIXME: currently we do nothing to prevent placeholders with the new universe being + // used after exiting `f`. For example region subtyping can result in outlives constraints + // that name placeholders created in this function. Nested goals from type relations can + // also contain placeholders created by this function. + let value = self.enter_forall_and_leak_universe(forall); + debug!("?value"); + f(value) + } + /// See [RegionConstraintCollector::leak_check][1]. We only check placeholder /// leaking into `outer_universe`, i.e. placeholders which cannot be named by that /// universe. diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 87d777530c8..5b4f80fd73a 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -7,6 +7,7 @@ use crate::traits::{ObligationCause, PredicateObligations}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; /// "Least upper bound" (common supertype) pub struct Lub<'combine, 'infcx, 'tcx> { @@ -134,6 +135,10 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, } impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> { + fn span(&self) -> Span { + self.fields.trace.span() + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index f688c2b74a6..1207377e857 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -3,10 +3,9 @@ pub(super) mod combine; mod equate; -pub(super) mod generalize; +mod generalize; mod glb; mod higher_ranked; mod lattice; mod lub; -pub mod nll; mod sub; diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs deleted file mode 100644 index 8b80646a386..00000000000 --- a/compiler/rustc_infer/src/infer/relate/nll.rs +++ /dev/null @@ -1,717 +0,0 @@ -//! This code is kind of an alternate way of doing subtyping, -//! supertyping, and type equating, distinct from the `combine.rs` -//! code but very similar in its effect and design. Eventually the two -//! ought to be merged. This code is intended for use in NLL and chalk. -//! -//! Here are the key differences: -//! -//! - This code may choose to bypass some checks (e.g., the occurs check) -//! in the case where we know that there are no unbound type inference -//! variables. This is the case for NLL, because at NLL time types are fully -//! inferred up-to regions. -//! - This code uses "universes" to handle higher-ranked regions and -//! not the leak-check. This is "more correct" than what rustc does -//! and we are generally migrating in this direction, but NLL had to -//! get there first. -//! -//! Also, this code assumes that there are no bound types at all, not even -//! free ones. This is ok because: -//! - we are not relating anything quantified over some type variable -//! - we will have instantiated all the bound type vars already (the one -//! thing we relate in chalk are basically domain goals and their -//! constituents) - -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; -use rustc_span::{Span, Symbol}; -use std::fmt::Debug; - -use super::combine::ObligationEmittingRelation; -use super::generalize::{self, Generalization}; -use crate::infer::InferCtxt; -use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::traits::{Obligation, PredicateObligations}; - -pub struct TypeRelating<'me, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - infcx: &'me InferCtxt<'tcx>, - - /// Callback to use when we deduce an outlives relationship. - delegate: D, - - /// How are we relating `a` and `b`? - /// - /// - Covariant means `a <: b`. - /// - Contravariant means `b <: a`. - /// - Invariant means `a == b`. - /// - Bivariant means that it doesn't matter. - ambient_variance: ty::Variance, - - ambient_variance_info: ty::VarianceDiagInfo<'tcx>, -} - -pub trait TypeRelatingDelegate<'tcx> { - fn param_env(&self) -> ty::ParamEnv<'tcx>; - fn span(&self) -> Span; - - /// Push a constraint `sup: sub` -- this constraint must be - /// satisfied for the two types to be related. `sub` and `sup` may - /// be regions from the type or new variables created through the - /// delegate. - fn push_outlives( - &mut self, - sup: ty::Region<'tcx>, - sub: ty::Region<'tcx>, - info: ty::VarianceDiagInfo<'tcx>, - ); - - fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>); - - /// Creates a new universe index. Used when instantiating placeholders. - fn create_next_universe(&mut self) -> ty::UniverseIndex; - - /// Creates a new region variable representing a higher-ranked - /// region that is instantiated existentially. This creates an - /// inference variable, typically. - /// - /// So e.g., if you have `for<'a> fn(..) <: for<'b> fn(..)`, then - /// we will invoke this method to instantiate `'a` with an - /// inference variable (though `'b` would be instantiated first, - /// as a placeholder). - fn next_existential_region_var( - &mut self, - was_placeholder: bool, - name: Option<Symbol>, - ) -> ty::Region<'tcx>; - - /// Creates a new region variable representing a - /// higher-ranked region that is instantiated universally. - /// This creates a new region placeholder, typically. - /// - /// So e.g., if you have `for<'a> fn(..) <: for<'b> fn(..)`, then - /// we will invoke this method to instantiate `'b` with a - /// placeholder region. - fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx>; - - /// Creates a new existential region in the given universe. This - /// is used when handling subtyping and type variables -- if we - /// have that `?X <: Foo<'a>`, for example, we would instantiate - /// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh - /// existential variable created by this function. We would then - /// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives - /// relation stating that `'?0: 'a`). - fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; - - /// Enables some optimizations if we do not expect inference variables - /// in the RHS of the relation. - fn forbid_inference_vars() -> bool; -} - -impl<'me, 'tcx, D> TypeRelating<'me, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - pub fn new(infcx: &'me InferCtxt<'tcx>, delegate: D, ambient_variance: ty::Variance) -> Self { - Self { - infcx, - delegate, - ambient_variance, - ambient_variance_info: ty::VarianceDiagInfo::default(), - } - } - - fn ambient_covariance(&self) -> bool { - match self.ambient_variance { - ty::Variance::Covariant | ty::Variance::Invariant => true, - ty::Variance::Contravariant | ty::Variance::Bivariant => false, - } - } - - fn ambient_contravariance(&self) -> bool { - match self.ambient_variance { - ty::Variance::Contravariant | ty::Variance::Invariant => true, - ty::Variance::Covariant | ty::Variance::Bivariant => false, - } - } - - /// Push a new outlives requirement into our output set of - /// constraints. - fn push_outlives( - &mut self, - sup: ty::Region<'tcx>, - sub: ty::Region<'tcx>, - info: ty::VarianceDiagInfo<'tcx>, - ) { - debug!("push_outlives({:?}: {:?})", sup, sub); - - self.delegate.push_outlives(sup, sub, info); - } - - /// Relate a type inference variable with a value type. This works - /// by creating a "generalization" G of the value where all the - /// lifetimes are replaced with fresh inference values. This - /// generalization G becomes the value of the inference variable, - /// and is then related in turn to the value. So e.g. if you had - /// `vid = ?0` and `value = &'a u32`, we might first instantiate - /// `?0` to a type like `&'0 u32` where `'0` is a fresh variable, - /// and then relate `&'0 u32` with `&'a u32` (resulting in - /// relations between `'0` and `'a`). - /// - /// The variable `pair` can be either a `(vid, ty)` or `(ty, vid)` - /// -- in other words, it is always an (unresolved) inference - /// variable `vid` and a type `ty` that are being related, but the - /// vid may appear either as the "a" type or the "b" type, - /// depending on where it appears in the tuple. The trait - /// `VidValuePair` lets us work with the vid/type while preserving - /// the "sidedness" when necessary -- the sidedness is relevant in - /// particular for the variance and set of in-scope things. - fn relate_ty_var<PAIR: VidValuePair<'tcx>>( - &mut self, - pair: PAIR, - ) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("relate_ty_var({:?})", pair); - - let vid = pair.vid(); - let value_ty = pair.value_ty(); - - // FIXME(invariance) -- this logic assumes invariance, but that is wrong. - // This only presently applies to chalk integration, as NLL - // doesn't permit type variables to appear on both sides (and - // doesn't use lazy norm). - match *value_ty.kind() { - ty::Infer(ty::TyVar(value_vid)) => { - // Two type variables: just equate them. - self.infcx.inner.borrow_mut().type_variables().equate(vid, value_vid); - return Ok(value_ty); - } - - _ => (), - } - - let generalized_ty = self.generalize(value_ty, vid)?; - debug!("relate_ty_var: generalized_ty = {:?}", generalized_ty); - - if D::forbid_inference_vars() { - // In NLL, we don't have type inference variables - // floating around, so we can do this rather imprecise - // variant of the occurs-check. - assert!(!generalized_ty.has_non_region_infer()); - } - - self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty); - - // Relate the generalized kind to the original one. - let result = pair.relate_generalized_ty(self, generalized_ty); - - debug!("relate_ty_var: complete, result = {:?}", result); - result - } - - fn generalize(&mut self, ty: Ty<'tcx>, for_vid: ty::TyVid) -> RelateResult<'tcx, Ty<'tcx>> { - let Generalization { value_may_be_infer: ty, needs_wf: _ } = generalize::generalize( - self.infcx, - &mut self.delegate, - ty, - for_vid, - self.ambient_variance, - )?; - - if ty.is_ty_var() { - span_bug!(self.delegate.span(), "occurs check failure in MIR typeck"); - } - Ok(ty) - } - - fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; - let mut generalize = |ty, ty_is_expected| { - let var = self.infcx.next_ty_var_id_in_universe( - TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: self.delegate.span(), - }, - ty::UniverseIndex::ROOT, - ); - if ty_is_expected { - self.relate_ty_var((ty, var)) - } else { - self.relate_ty_var((var, ty)) - } - }; - let (a, b) = match (a.kind(), b.kind()) { - (&ty::Alias(ty::Opaque, ..), _) => (a, generalize(b, false)?), - (_, &ty::Alias(ty::Opaque, ..)) => (generalize(a, true)?, b), - _ => unreachable!( - "expected at least one opaque type in `relate_opaques`, got {a} and {b}." - ), - }; - let cause = ObligationCause::dummy_with_span(self.delegate.span()); - let obligations = self - .infcx - .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())? - .obligations; - self.delegate.register_obligations(obligations); - 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 -/// `relate_ty_var`, we always have the pair of a `TyVid` and a `Ty`, -/// but the ordering may vary (depending on whether the inference -/// variable was found on the `a` or `b` sides). Therefore, this trait -/// allows us to factor out common code, while preserving the order -/// when needed. -trait VidValuePair<'tcx>: Debug { - /// Extract the inference variable (which could be either the - /// first or second part of the tuple). - fn vid(&self) -> ty::TyVid; - - /// Extract the value it is being related to (which will be the - /// opposite part of the tuple from the vid). - fn value_ty(&self) -> Ty<'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. - fn relate_generalized_ty<D>( - &self, - relate: &mut TypeRelating<'_, 'tcx, D>, - generalized_ty: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - D: TypeRelatingDelegate<'tcx>; -} - -impl<'tcx> VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) { - fn vid(&self) -> ty::TyVid { - self.0 - } - - fn value_ty(&self) -> Ty<'tcx> { - self.1 - } - - fn relate_generalized_ty<D>( - &self, - relate: &mut TypeRelating<'_, 'tcx, D>, - generalized_ty: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - relate.relate(generalized_ty, self.value_ty()) - } -} - -// In this case, the "vid" is the "b" type. -impl<'tcx> VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) { - fn vid(&self) -> ty::TyVid { - self.1 - } - - fn value_ty(&self) -> Ty<'tcx> { - self.0 - } - - fn relate_generalized_ty<D>( - &self, - relate: &mut TypeRelating<'_, 'tcx, D>, - generalized_ty: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - relate.relate(self.value_ty(), generalized_ty) - } -} - -impl<'tcx, D> TypeRelation<'tcx> for TypeRelating<'_, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn tag(&self) -> &'static str { - "nll::subtype" - } - - fn a_is_expected(&self) -> bool { - true - } - - #[instrument(skip(self, info), level = "trace", ret)] - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - self.ambient_variance_info = self.ambient_variance_info.xform(info); - - debug!(?self.ambient_variance); - // In a bivariant context this always succeeds. - let r = - if self.ambient_variance == ty::Variance::Bivariant { a } else { self.relate(a, b)? }; - - self.ambient_variance = old_ambient_variance; - - Ok(r) - } - - #[instrument(skip(self), level = "debug")] - fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let infcx = self.infcx; - - let a = self.infcx.shallow_resolve(a); - - if !D::forbid_inference_vars() { - b = self.infcx.shallow_resolve(b); - } - - if a == b { - return Ok(a); - } - - match (a.kind(), b.kind()) { - (_, &ty::Infer(ty::TyVar(vid))) => { - if D::forbid_inference_vars() { - // Forbid inference variables in the RHS. - bug!("unexpected inference var {:?}", b) - } else { - self.relate_ty_var((a, vid)) - } - } - - (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)), - - ( - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), - ) if a_def_id == b_def_id || infcx.next_trait_solver() => { - infcx.super_combine_tys(self, a, b).or_else(|err| { - // This behavior is only there for the old solver, the new solver - // shouldn't ever fail. Instead, it unconditionally emits an - // alias-relate goal. - assert!(!self.infcx.next_trait_solver()); - self.tcx().dcx().span_delayed_bug( - self.delegate.span(), - "failure to relate an opaque to itself should result in an error later on", - ); - if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } - }) - } - (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) - | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if def_id.is_local() && !self.infcx.next_trait_solver() => - { - self.relate_opaques(a, b) - } - - _ => { - debug!(?a, ?b, ?self.ambient_variance); - - // Will also handle unification of `IntVar` and `FloatVar`. - self.infcx.super_combine_tys(self, a, b) - } - } - } - - #[instrument(skip(self), level = "trace")] - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!(?self.ambient_variance); - - if self.ambient_covariance() { - // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`. - self.push_outlives(a, b, self.ambient_variance_info); - } - - if self.ambient_contravariance() { - // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`. - self.push_outlives(b, a, self.ambient_variance_info); - } - - Ok(a) - } - - fn consts( - &mut self, - a: ty::Const<'tcx>, - mut b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - let a = self.infcx.shallow_resolve(a); - - if !D::forbid_inference_vars() { - b = self.infcx.shallow_resolve(b); - } - - match b.kind() { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { - // Forbid inference variables in the RHS. - self.infcx.dcx().span_delayed_bug( - self.delegate.span(), - format!("unexpected inference var {b:?}",), - ); - Ok(a) - } - // FIXME(invariance): see the related FIXME above. - _ => self.infcx.super_combine_consts(self, a, b), - } - } - - #[instrument(skip(self), level = "trace")] - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - // We want that - // - // ``` - // for<'a> fn(&'a u32) -> &'a u32 <: - // fn(&'b u32) -> &'b u32 - // ``` - // - // but not - // - // ``` - // fn(&'a u32) -> &'a u32 <: - // for<'b> fn(&'b u32) -> &'b u32 - // ``` - // - // We therefore proceed as follows: - // - // - Instantiate binders on `b` universally, yielding a universe U1. - // - Instantiate binders on `a` existentially in U1. - - debug!(?self.ambient_variance); - - if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) { - // Fast path for the common case. - self.relate(a, b)?; - return Ok(ty::Binder::dummy(a)); - } - - if self.ambient_covariance() { - // Covariance, so we want `for<..> A <: for<..> B` -- - // therefore we compare any instantiation of A (i.e., A - // instantiated with existentials) against every - // instantiation of B (i.e., B instantiated with - // universals). - - // Reset the ambient variance to covariant. This is needed - // to correctly handle cases like - // - // for<'a> fn(&'a u32, &'a u32) == for<'b, 'c> fn(&'b u32, &'c u32) - // - // Somewhat surprisingly, these two types are actually - // **equal**, even though the one on the right looks more - // polymorphic. The reason is due to subtyping. To see it, - // consider that each function can call the other: - // - // - The left function can call the right with `'b` and - // `'c` both equal to `'a` - // - // - The right function can call the left with `'a` set to - // `{P}`, where P is the point in the CFG where the call - // itself occurs. Note that `'b` and `'c` must both - // include P. At the point, the call works because of - // subtyping (i.e., `&'b u32 <: &{P} u32`). - let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); - - // 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.relate(a_replaced, b_replaced)?; - - self.ambient_variance = variance; - } - - if self.ambient_contravariance() { - // Contravariance, so we want `for<..> A :> for<..> B` - // -- therefore we compare every instantiation of A (i.e., - // A instantiated with universals) against any - // instantiation of B (i.e., B instantiated with - // existentials). Opposite of above. - - // 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); - - let a_replaced = self.instantiate_binder_with_placeholders(a); - let b_replaced = self.instantiate_binder_with_existentials(b); - - self.relate(a_replaced, b_replaced)?; - - self.ambient_variance = variance; - } - - Ok(a) - } -} - -impl<'tcx, D> ObligationEmittingRelation<'tcx> for TypeRelating<'_, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.delegate.param_env() - } - - fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) { - self.delegate.register_obligations( - obligations - .into_iter() - .map(|to_pred| { - Obligation::new(self.tcx(), ObligationCause::dummy(), self.param_env(), to_pred) - }) - .collect(), - ); - } - - 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!("cannot defer an alias-relate goal with Bivariant variance (yet?)") - } - })]); - } -} diff --git a/compiler/rustc_infer/src/infer/relate/sub.rs b/compiler/rustc_infer/src/infer/relate/sub.rs index 36876acd7c0..5bd3a238a67 100644 --- a/compiler/rustc_infer/src/infer/relate/sub.rs +++ b/compiler/rustc_infer/src/infer/relate/sub.rs @@ -6,6 +6,7 @@ use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::Span; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. @@ -103,12 +104,12 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { Ok(a) } - (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, ty::Contravariant, a_id, !self.a_is_expected)?; + (&ty::Infer(TyVar(a_vid)), _) => { + infcx.instantiate_ty_var(self, self.a_is_expected, a_vid, ty::Covariant, b)?; Ok(a) } - (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, ty::Covariant, b_id, self.a_is_expected)?; + (_, &ty::Infer(TyVar(b_vid))) => { + infcx.instantiate_ty_var(self, !self.a_is_expected, b_vid, ty::Contravariant, a)?; Ok(a) } @@ -199,6 +200,10 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { } impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> { + fn span(&self) -> Span { + self.fields.trace.span() + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 959b0903127..d5999331dfa 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -237,14 +237,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> { } ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => { debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool); - match self.infcx.probe_effect_var(vid) { - Some(c) => c.as_const(self.infcx.tcx), - None => ty::Const::new_infer( + self.infcx.probe_effect_var(vid).unwrap_or_else(|| { + ty::Const::new_infer( self.infcx.tcx, ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)), self.infcx.tcx.types.bool, - ), - } + ) + }) } _ => { if c.has_infer() { diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 58b8110157b..8b81eac8739 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -118,7 +118,7 @@ pub enum TypeVariableOriginKind { AdjustmentType, /// In type check, when we are type checking a function that - /// returns `-> dyn Foo`, we substitute a type variable for the + /// returns `-> dyn Foo`, we instantiate a type variable with the /// return type for diagnostic purposes. DynReturnFn, LatticeVariable, diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 221b78048cb..97f9a4b291d 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -16,14 +16,15 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] #![feature(associated_type_bounds)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(extend_one)] #![feature(let_chains)] #![feature(if_let_guard)] -#![feature(min_specialization)] -#![feature(never_type)] +#![feature(iterator_try_collect)] +#![cfg_attr(bootstrap, feature(min_specialization))] #![feature(try_blocks)] #![recursion_limit = "512"] // For rustdoc diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 64b9714c7c0..c495810858f 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -52,18 +52,8 @@ pub trait TraitEngine<'tcx>: 'tcx { ) -> Vec<PredicateObligation<'tcx>>; } -pub trait TraitEngineExt<'tcx> { - fn register_predicate_obligations( - &mut self, - infcx: &InferCtxt<'tcx>, - obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, - ); - - #[must_use] - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; -} - -impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { +#[extension(pub trait TraitEngineExt<'tcx>)] +impl<'tcx, T: ?Sized + TraitEngine<'tcx>> T { fn register_predicate_obligations( &mut self, infcx: &InferCtxt<'tcx>, @@ -74,6 +64,7 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { } } + #[must_use] fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { let errors = self.select_where_possible(infcx); if !errors.is_empty() { diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 6f218019dee..0253f5a2df2 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -2,10 +2,9 @@ use super::ObjectSafetyViolation; use crate::infer::InferCtxt; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::Map; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Span; @@ -62,14 +61,14 @@ pub fn report_object_safety_error<'tcx>( err.span_label(span, format!("`{trait_str}` cannot be made into an object")); if let Some(hir_id) = hir_id - && let Some(hir::Node::Ty(ty)) = tcx.hir().find(hir_id) + && let hir::Node::Ty(ty) = tcx.hir_node(hir_id) && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind { let mut hir_id = hir_id; - while let hir::Node::Ty(ty) = tcx.hir().get_parent(hir_id) { + while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) { hir_id = ty.hir_id; } - if tcx.hir().get_parent(hir_id).fn_sig().is_some() { + if tcx.parent_hir_node(hir_id).fn_sig().is_some() { // Do not suggest `impl Trait` when dealing with things like super-traits. err.span_suggestion_verbose( ty.span.until(trait_ref.span), @@ -178,12 +177,13 @@ pub fn report_object_safety_error<'tcx>( ))); } impls => { - let types = impls + let mut types = impls .iter() .map(|t| { with_no_trimmed_paths!(format!(" {}", tcx.type_of(*t).instantiate_identity(),)) }) .collect::<Vec<_>>(); + types.sort(); err.help(format!( "the following types implement the trait, consider defining an enum where each \ variant holds one of these types, implementing `{}` for this new enum and using \ diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index fdae093aac8..72ec07375ac 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -13,12 +13,15 @@ use std::hash::{Hash, Hasher}; use hir::def_id::LocalDefId; use rustc_hir as hir; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::solve::Certainty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt}; use rustc_span::Span; pub use self::ImplSource::*; pub use self::SelectionError::*; +use crate::infer::InferCtxt; pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::project::MismatchedProjectionTypes; @@ -116,6 +119,11 @@ pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>; pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>; +/// A callback that can be provided to `inspect_typeck`. Invoked on evaluation +/// of root obligations. +pub type ObligationInspector<'tcx> = + fn(&InferCtxt<'tcx>, &PredicateObligation<'tcx>, Result<Certainty, NoSolution>); + pub struct FulfillmentError<'tcx> { pub obligation: PredicateObligation<'tcx>, pub code: FulfillmentErrorCode<'tcx>, diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 50190058a76..e9df0505cbb 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -285,7 +285,8 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { let obligations = predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| { elaboratable.child_with_derived_cause( - clause.subst_supertrait(tcx, &bound_clause.rebind(data.trait_ref)), + clause + .instantiate_supertrait(tcx, &bound_clause.rebind(data.trait_ref)), span, bound_clause.rebind(data), index, |
