1
Fork 0

Auto merge of #109206 - matthiaskrgr:rollup-oev8ax6, r=matthiaskrgr

Rollup of 10 pull requests

Successful merges:

 - #108875 (rustdoc: fix type search for `Option` combinators)
 - #108971 (error-msg: impl better suggestion for `E0532`)
 - #109139 (rustdoc: DocFS: Replace rayon with threadpool and enable it for all targets)
 - #109151 (Assert def-kind is correct for alias types)
 - #109158 (error-msg: expand suggestion for `unused_def` lint)
 - #109166 (make `define_opaque_types` fully explicit)
 - #109171 (Some cleanups in our normalization logic)
 - #109180 (Unequal → Not equal)
 - #109185 (rustdoc: remove `std::` from primitive intra-doc link tooltips)
 - #109192 (Mention UEFI target promotion in release notes for 1.67.0)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-03-16 11:06:02 +00:00
commit 7ac4b82ddd
73 changed files with 792 additions and 412 deletions

View file

@ -5458,13 +5458,13 @@ dependencies = [
"itertools", "itertools",
"minifier", "minifier",
"once_cell", "once_cell",
"rayon",
"regex", "regex",
"rustdoc-json-types", "rustdoc-json-types",
"serde", "serde",
"serde_json", "serde_json",
"smallvec", "smallvec",
"tempfile", "tempfile",
"threadpool",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"tracing-tree", "tracing-tree",
@ -6209,6 +6209,15 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "threadpool"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
dependencies = [
"num_cpus",
]
[[package]] [[package]]
name = "tidy" name = "tidy"
version = "0.1.0" version = "0.1.0"

View file

@ -125,12 +125,13 @@ Compiler
- [Optimize field ordering by grouping m\*2^n-sized fields with equivalently aligned ones.](https://github.com/rust-lang/rust/pull/102750/) - [Optimize field ordering by grouping m\*2^n-sized fields with equivalently aligned ones.](https://github.com/rust-lang/rust/pull/102750/)
- [Stabilize native library modifier `verbatim`.](https://github.com/rust-lang/rust/pull/104360/) - [Stabilize native library modifier `verbatim`.](https://github.com/rust-lang/rust/pull/104360/)
Added and removed targets: Added, updated, and removed targets:
- [Add a tier 3 target for PowerPC on AIX](https://github.com/rust-lang/rust/pull/102293/), `powerpc64-ibm-aix`. - [Add a tier 3 target for PowerPC on AIX](https://github.com/rust-lang/rust/pull/102293/), `powerpc64-ibm-aix`.
- [Add a tier 3 target for the Sony PlayStation 1](https://github.com/rust-lang/rust/pull/102689/), `mipsel-sony-psx`. - [Add a tier 3 target for the Sony PlayStation 1](https://github.com/rust-lang/rust/pull/102689/), `mipsel-sony-psx`.
- [Add tier 3 `no_std` targets for the QNX Neutrino RTOS](https://github.com/rust-lang/rust/pull/102701/), - [Add tier 3 `no_std` targets for the QNX Neutrino RTOS](https://github.com/rust-lang/rust/pull/102701/),
`aarch64-unknown-nto-qnx710` and `x86_64-pc-nto-qnx710`. `aarch64-unknown-nto-qnx710` and `x86_64-pc-nto-qnx710`.
- [Promote UEFI targets to tier 2](https://github.com/rust-lang/rust/pull/103933/), `aarch64-unknown-uefi`, `i686-unknown-uefi`, and `x86_64-unknown-uefi`.
- [Remove tier 3 `linuxkernel` targets](https://github.com/rust-lang/rust/pull/104015/) (not used by the actual kernel). - [Remove tier 3 `linuxkernel` targets](https://github.com/rust-lang/rust/pull/104015/) (not used by the actual kernel).
Refer to Rust's [platform support page][platform-support-doc] Refer to Rust's [platform support page][platform-support-doc]

View file

@ -306,7 +306,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
} }
// By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
// pair of array indices are unequal, so that when `places_conflict` returns true, we // pair of array indices are not equal, so that when `places_conflict` returns true, we
// will be assured that two places being compared definitely denotes the same sets of // will be assured that two places being compared definitely denotes the same sets of
// locations. // locations.
let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| { let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| {

View file

@ -23,6 +23,6 @@ Or maybe did you mean to unify? Consider using a guard:
# let (A, B, C) = (1, 2, 3); # let (A, B, C) = (1, 2, 3);
match (A, B, C) { match (A, B, C) {
(x, x2, see) if x == x2 => { /* A and B are equal, do one thing */ } (x, x2, see) if x == x2 => { /* A and B are equal, do one thing */ }
(y, z, see) => { /* A and B unequal; do another thing */ } (y, z, see) => { /* A and B not equal; do another thing */ }
} }
``` ```

View file

@ -367,7 +367,7 @@ impl LockstepIterSize {
/// ///
/// Example: `$($($x $y)+*);+` -- we need to make sure that `x` and `y` repeat the same amount as /// Example: `$($($x $y)+*);+` -- we need to make sure that `x` and `y` repeat the same amount as
/// each other at the given depth when the macro was invoked. If they don't it might mean they were /// each other at the given depth when the macro was invoked. If they don't it might mean they were
/// declared at unequal depths or there was a compile bug. For example, if we have 3 repetitions of /// declared at depths which weren't equal or there was a compiler bug. For example, if we have 3 repetitions of
/// the outer sequence and 4 repetitions of the inner sequence for `x`, we should have the same for /// the outer sequence and 4 repetitions of the inner sequence for `x`, we should have the same for
/// `y`; otherwise, we can't transcribe them both at the given depth. /// `y`; otherwise, we can't transcribe them both at the given depth.
fn lockstep_iter_size( fn lockstep_iter_size(

View file

@ -9,8 +9,8 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_hir::ItemKind; use rustc_hir::ItemKind;
use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::{self, RegionResolutionError}; use rustc_infer::infer::{self, RegionResolutionError};
use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
@ -235,7 +235,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
use rustc_type_ir::sty::TyKind::*; use rustc_type_ir::sty::TyKind::*;
match (source.kind(), target.kind()) { match (source.kind(), target.kind()) {
(&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {} if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok()
&& mutbl_a == *mutbl_b => {}
(&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (), (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
(&Adt(def_a, substs_a), &Adt(def_b, substs_b)) (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
if def_a.is_struct() && def_b.is_struct() => if def_a.is_struct() && def_b.is_struct() =>
@ -278,7 +279,9 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
} }
} }
if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) { if let Ok(ok) =
infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, ty_a, ty_b)
{
if ok.obligations.is_empty() { if ok.obligations.is_empty() {
create_err( create_err(
"the trait `DispatchFromDyn` may only be implemented \ "the trait `DispatchFromDyn` may only be implemented \
@ -504,7 +507,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
// we may have to evaluate constraint // we may have to evaluate constraint
// expressions in the course of execution.) // expressions in the course of execution.)
// See e.g., #41936. // See e.g., #41936.
if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) { if let Ok(ok) = infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, a, b) {
if ok.obligations.is_empty() { if ok.obligations.is_empty() {
return None; return None;
} }

View file

@ -102,7 +102,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::Node; use rustc_hir::Node;
use rustc_infer::infer::{InferOk, TyCtxtInferExt}; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
use rustc_macros::fluent_messages; use rustc_macros::fluent_messages;
use rustc_middle::middle; use rustc_middle::middle;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
@ -165,7 +165,7 @@ fn require_same_types<'tcx>(
) -> bool { ) -> bool {
let infcx = &tcx.infer_ctxt().build(); let infcx = &tcx.infer_ctxt().build();
let param_env = ty::ParamEnv::empty(); let param_env = ty::ParamEnv::empty();
let errors = match infcx.at(cause, param_env).eq(expected, actual) { let errors = match infcx.at(cause, param_env).eq(DefineOpaqueTypes::No, expected, actual) {
Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations), Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
Err(err) => { Err(err) => {
infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit(); infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();

View file

@ -8,7 +8,7 @@ use rustc_hir as hir;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_hir_analysis::astconv::AstConv; use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::{DefineOpaqueTypes, LateBoundRegionConversionTime};
use rustc_infer::infer::{InferOk, InferResult}; use rustc_infer::infer::{InferOk, InferResult};
use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::subst::InternalSubsts;
@ -563,10 +563,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) { ) {
// Check that E' = S'. // Check that E' = S'.
let cause = self.misc(hir_ty.span); let cause = self.misc(hir_ty.span);
let InferOk { value: (), obligations } = self let InferOk { value: (), obligations } = self.at(&cause, self.param_env).eq(
.at(&cause, self.param_env) DefineOpaqueTypes::Yes,
.define_opaque_types(true) *expected_ty,
.eq(*expected_ty, supplied_ty)?; supplied_ty,
)?;
all_obligations.extend(obligations); all_obligations.extend(obligations);
} }
@ -576,10 +577,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
supplied_sig.output(), supplied_sig.output(),
); );
let cause = &self.misc(decl.output.span()); let cause = &self.misc(decl.output.span());
let InferOk { value: (), obligations } = self let InferOk { value: (), obligations } = self.at(cause, self.param_env).eq(
.at(cause, self.param_env) DefineOpaqueTypes::Yes,
.define_opaque_types(true) expected_sigs.liberated_sig.output(),
.eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?; supplied_output_ty,
)?;
all_obligations.extend(obligations); all_obligations.extend(obligations);
let inputs = inputs.into_iter().map(|ty| self.resolve_vars_if_possible(ty)); let inputs = inputs.into_iter().map(|ty| self.resolve_vars_if_possible(ty));

View file

@ -45,7 +45,7 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Expr; use rustc_hir::Expr;
use rustc_hir_analysis::astconv::AstConv; use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult}; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
use rustc_infer::traits::Obligation; use rustc_infer::traits::Obligation;
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::{ use rustc_middle::ty::adjustment::{
@ -143,11 +143,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
self.commit_if_ok(|_| { self.commit_if_ok(|_| {
let at = self.at(&self.cause, self.fcx.param_env).define_opaque_types(true); let at = self.at(&self.cause, self.fcx.param_env);
if self.use_lub { if self.use_lub {
at.lub(b, a) at.lub(DefineOpaqueTypes::Yes, b, a)
} else { } else {
at.sup(b, a) at.sup(DefineOpaqueTypes::Yes, b, a)
.map(|InferOk { value: (), obligations }| InferOk { value: a, obligations }) .map(|InferOk { value: (), obligations }| InferOk { value: a, obligations })
} }
}) })
@ -175,7 +175,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// so this will have the side-effect of making sure we have no ambiguities // so this will have the side-effect of making sure we have no ambiguities
// due to `[type error]` and `_` not coercing together. // due to `[type error]` and `_` not coercing together.
let _ = self.commit_if_ok(|_| { let _ = self.commit_if_ok(|_| {
self.at(&self.cause, self.param_env).define_opaque_types(true).eq(a, b) self.at(&self.cause, self.param_env).eq(DefineOpaqueTypes::Yes, a, b)
}); });
return success(vec![], self.fcx.tcx.ty_error(guar), vec![]); return success(vec![], self.fcx.tcx.ty_error(guar), vec![]);
} }
@ -1101,9 +1101,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(ty::FnDef(..), ty::FnDef(..)) => { (ty::FnDef(..), ty::FnDef(..)) => {
// Don't reify if the function types have a LUB, i.e., they // Don't reify if the function types have a LUB, i.e., they
// are the same function and their parameters have a LUB. // are the same function and their parameters have a LUB.
match self match self.commit_if_ok(|_| {
.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) self.at(cause, self.param_env).lub(
{ DefineOpaqueTypes::No,
prev_ty,
new_ty,
)
}) {
// We have a LUB of prev_ty and new_ty, just return it. // We have a LUB of prev_ty and new_ty, just return it.
Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)),
Err(_) => { Err(_) => {
@ -1153,7 +1157,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let sig = self let sig = self
.at(cause, self.param_env) .at(cause, self.param_env)
.trace(prev_ty, new_ty) .trace(prev_ty, new_ty)
.lub(a_sig, b_sig) .lub(DefineOpaqueTypes::No, a_sig, b_sig)
.map(|ok| self.register_infer_ok_obligations(ok))?; .map(|ok| self.register_infer_ok_obligations(ok))?;
// Reify both sides and return the reified fn pointer type. // Reify both sides and return the reified fn pointer type.
@ -1237,7 +1241,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
return self return self
.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) .commit_if_ok(|_| {
self.at(cause, self.param_env).lub(DefineOpaqueTypes::No, prev_ty, new_ty)
})
.map(|ok| self.register_infer_ok_obligations(ok)); .map(|ok| self.register_infer_ok_obligations(ok));
} }
} }
@ -1248,8 +1254,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(e) = first_error { if let Some(e) = first_error {
Err(e) Err(e)
} else { } else {
self.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) self.commit_if_ok(|_| {
.map(|ok| self.register_infer_ok_obligations(ok)) self.at(cause, self.param_env).lub(DefineOpaqueTypes::No, prev_ty, new_ty)
})
.map(|ok| self.register_infer_ok_obligations(ok))
} }
} }
Ok(ok) => { Ok(ok) => {
@ -1487,8 +1495,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
assert!(expression_ty.is_unit(), "if let hack without unit type"); assert!(expression_ty.is_unit(), "if let hack without unit type");
fcx.at(cause, fcx.param_env) fcx.at(cause, fcx.param_env)
// needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
.define_opaque_types(true) .eq_exp(
.eq_exp(label_expression_as_expected, expression_ty, self.merged_ty()) DefineOpaqueTypes::Yes,
label_expression_as_expected,
expression_ty,
self.merged_ty(),
)
.map(|infer_ok| { .map(|infer_ok| {
fcx.register_infer_ok_obligations(infer_ok); fcx.register_infer_ok_obligations(infer_ok);
expression_ty expression_ty

View file

@ -8,7 +8,7 @@ use rustc_hir::def::CtorKind;
use rustc_hir::intravisit::Visitor; use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node}; use rustc_hir::{is_range_literal, Node};
use rustc_infer::infer::InferOk; use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::middle::stability::EvalResult; use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::adjustment::AllowTwoPhase;
@ -113,7 +113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>, expected: Ty<'tcx>,
actual: Ty<'tcx>, actual: Ty<'tcx>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
match self.at(cause, self.param_env).define_opaque_types(true).sup(expected, actual) { match self.at(cause, self.param_env).sup(DefineOpaqueTypes::Yes, expected, actual) {
Ok(InferOk { obligations, value: () }) => { Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations); self.register_predicates(obligations);
None None
@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>, expected: Ty<'tcx>,
actual: Ty<'tcx>, actual: Ty<'tcx>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
match self.at(cause, self.param_env).define_opaque_types(true).eq(expected, actual) { match self.at(cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, actual) {
Ok(InferOk { obligations, value: () }) => { Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations); self.register_predicates(obligations);
None None

View file

@ -36,6 +36,7 @@ use rustc_hir_analysis::astconv::AstConv as _;
use rustc_hir_analysis::check::ty_kind_suggestion; use rustc_hir_analysis::check::ty_kind_suggestion;
use rustc_infer::infer; use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::InferOk; use rustc_infer::infer::InferOk;
use rustc_infer::traits::ObligationCause; use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability; use rustc_middle::middle::stability;
@ -1683,7 +1684,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(_) = remaining_fields.remove(&ident) { if let Some(_) = remaining_fields.remove(&ident) {
let target_ty = self.field_ty(base_expr.span, f, substs); let target_ty = self.field_ty(base_expr.span, f, substs);
let cause = self.misc(base_expr.span); let cause = self.misc(base_expr.span);
match self.at(&cause, self.param_env).sup(target_ty, fru_ty) { match self.at(&cause, self.param_env).sup(
DefineOpaqueTypes::No,
target_ty,
fru_ty,
) {
Ok(InferOk { obligations, value: () }) => { Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations) self.register_predicates(obligations)
} }

View file

@ -19,7 +19,7 @@ use rustc_hir_analysis::astconv::{
}; };
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::InferResult; use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::error::TypeError; use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
@ -558,7 +558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let span = self.tcx.hir().body(body_id).value.span; let span = self.tcx.hir().body(body_id).value.span;
let ok = self let ok = self
.at(&self.misc(span), self.param_env) .at(&self.misc(span), self.param_env)
.eq(interior, witness) .eq(DefineOpaqueTypes::No, interior, witness)
.expect("Failed to unify generator interior type"); .expect("Failed to unify generator interior type");
let mut obligations = ok.obligations; let mut obligations = ok.obligations;
@ -1341,7 +1341,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This also occurs for an enum variant on a type alias. // This also occurs for an enum variant on a type alias.
let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).subst(tcx, substs)); let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).subst(tcx, substs));
let self_ty = self.normalize(span, self_ty); let self_ty = self.normalize(span, self_ty);
match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) { match self.at(&self.misc(span), self.param_env).eq(
DefineOpaqueTypes::No,
impl_ty,
self_ty,
) {
Ok(ok) => self.register_infer_ok_obligations(ok), Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => { Err(_) => {
self.tcx.sess.delay_span_bug( self.tcx.sess.delay_span_bug(

View file

@ -24,8 +24,8 @@ use rustc_hir_analysis::structured_errors::StructuredDiagnostic;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt}; use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk;
use rustc_infer::infer::TypeTrace; use rustc_infer::infer::TypeTrace;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, IsSuggestable, Ty}; use rustc_middle::ty::{self, IsSuggestable, Ty};
@ -301,9 +301,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 3. Check if the formal type is a supertype of the checked one // 3. Check if the formal type is a supertype of the checked one
// and register any such obligations for future type checks // and register any such obligations for future type checks
let supertype_error = self let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup(
.at(&self.misc(provided_arg.span), self.param_env) DefineOpaqueTypes::No,
.sup(formal_input_ty, coerced_ty); formal_input_ty,
coerced_ty,
);
let subtyping_error = match supertype_error { let subtyping_error = match supertype_error {
Ok(InferOk { obligations, value: () }) => { Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations); self.register_predicates(obligations);
@ -585,7 +587,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Using probe here, since we don't want this subtyping to affect inference. // Using probe here, since we don't want this subtyping to affect inference.
let subtyping_error = self.probe(|_| { let subtyping_error = self.probe(|_| {
self.at(&self.misc(arg_span), self.param_env).sup(formal_input_ty, coerced_ty).err() self.at(&self.misc(arg_span), self.param_env)
.sup(DefineOpaqueTypes::No, formal_input_ty, coerced_ty)
.err()
}); });
// Same as above: if either the coerce type or the checked type is an error type, // Same as above: if either the coerce type or the checked type is an error type,

View file

@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdSet; use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind}; use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
use rustc_infer::infer::RegionVariableOrigin; use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin};
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData}; use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitableExt};
@ -327,7 +327,11 @@ pub fn resolve_interior<'a, 'tcx>(
); );
// Unify the type variable inside the generator with the new witness // Unify the type variable inside the generator with the new witness
match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(interior, witness) { match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(
DefineOpaqueTypes::No,
interior,
witness,
) {
Ok(ok) => fcx.register_infer_ok_obligations(ok), Ok(ok) => fcx.register_infer_ok_obligations(ok),
_ => bug!("failed to relate {interior} and {witness}"), _ => bug!("failed to relate {interior} and {witness}"),
} }

View file

@ -8,7 +8,7 @@ use rustc_hir_analysis::astconv::generics::{
check_generic_arg_count_for_call, create_substs_for_generic_args, check_generic_arg_count_for_call, create_substs_for_generic_args,
}; };
use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall}; use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
use rustc_infer::infer::{self, InferOk}; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
@ -478,7 +478,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
substs, substs,
})), })),
); );
match self.at(&cause, self.param_env).sup(method_self_ty, self_ty) { match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::No, method_self_ty, self_ty) {
Ok(InferOk { obligations, value: () }) => { Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations); self.register_predicates(obligations);
} }

View file

@ -13,6 +13,7 @@ use rustc_hir_analysis::astconv::InferCtxtExt as _;
use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_hir_analysis::autoderef::{self, Autoderef};
use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_middle::middle::stability; use rustc_middle::middle::stability;
use rustc_middle::ty::fast_reject::TreatProjections; use rustc_middle::ty::fast_reject::TreatProjections;
@ -930,7 +931,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if let Some(self_ty) = self_ty { if let Some(self_ty) = self_ty {
if self if self
.at(&ObligationCause::dummy(), self.param_env) .at(&ObligationCause::dummy(), self.param_env)
.sup(fty.inputs()[0], self_ty) .sup(DefineOpaqueTypes::No, fty.inputs()[0], self_ty)
.is_err() .is_err()
{ {
return false; return false;
@ -1436,9 +1437,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
CandidateSource::Trait(candidate.item.container_id(self.tcx)) CandidateSource::Trait(candidate.item.container_id(self.tcx))
} }
TraitCandidate(trait_ref) => self.probe(|_| { TraitCandidate(trait_ref) => self.probe(|_| {
let _ = self let _ = self.at(&ObligationCause::dummy(), self.param_env).sup(
.at(&ObligationCause::dummy(), self.param_env) DefineOpaqueTypes::No,
.sup(candidate.xform_self_ty, self_ty); candidate.xform_self_ty,
self_ty,
);
match self.select_trait_candidate(trait_ref) { match self.select_trait_candidate(trait_ref) {
Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => { Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
// If only a single impl matches, make the error message point // If only a single impl matches, make the error message point
@ -1465,10 +1468,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.probe(|_| { self.probe(|_| {
// First check that the self type can be related. // First check that the self type can be related.
let sub_obligations = match self let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env).sup(
.at(&ObligationCause::dummy(), self.param_env) DefineOpaqueTypes::No,
.sup(probe.xform_self_ty, self_ty) probe.xform_self_ty,
{ self_ty,
) {
Ok(InferOk { obligations, value: () }) => obligations, Ok(InferOk { obligations, value: () }) => obligations,
Err(err) => { Err(err) => {
debug!("--> cannot relate self-types {:?}", err); debug!("--> cannot relate self-types {:?}", err);
@ -1683,7 +1687,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if let ProbeResult::Match = result if let ProbeResult::Match = result
&& self && self
.at(&ObligationCause::dummy(), self.param_env) .at(&ObligationCause::dummy(), self.param_env)
.sup(return_ty, xform_ret_ty) .sup(DefineOpaqueTypes::No, return_ty, xform_ret_ty)
.is_err() .is_err()
{ {
result = ProbeResult::BadReturnType; result = ProbeResult::BadReturnType;

View file

@ -30,16 +30,20 @@ use super::*;
use rustc_middle::ty::relate::{Relate, TypeRelation}; use rustc_middle::ty::relate::{Relate, TypeRelation};
use rustc_middle::ty::{Const, ImplSubject}; use rustc_middle::ty::{Const, ImplSubject};
/// Whether we should define opaque types or just treat them opaquely.
///
/// Currently only used to prevent predicate matching from matching anything
/// against opaque types.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum DefineOpaqueTypes {
Yes,
No,
}
pub struct At<'a, 'tcx> { pub struct At<'a, 'tcx> {
pub infcx: &'a InferCtxt<'tcx>, pub infcx: &'a InferCtxt<'tcx>,
pub cause: &'a ObligationCause<'tcx>, pub cause: &'a ObligationCause<'tcx>,
pub param_env: ty::ParamEnv<'tcx>, pub param_env: ty::ParamEnv<'tcx>,
/// Whether we should define opaque types
/// or just treat them opaquely.
/// Currently only used to prevent predicate
/// matching from matching anything against opaque
/// types.
pub define_opaque_types: bool,
} }
pub struct Trace<'a, 'tcx> { pub struct Trace<'a, 'tcx> {
@ -55,7 +59,7 @@ impl<'tcx> InferCtxt<'tcx> {
cause: &'a ObligationCause<'tcx>, cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
) -> At<'a, 'tcx> { ) -> At<'a, 'tcx> {
At { infcx: self, cause, param_env, define_opaque_types: false } At { infcx: self, cause, param_env }
} }
/// Forks the inference context, creating a new inference context with the same inference /// Forks the inference context, creating a new inference context with the same inference
@ -84,7 +88,6 @@ impl<'tcx> InferCtxt<'tcx> {
pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
fn to_trace( fn to_trace(
tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
a_is_expected: bool, a_is_expected: bool,
a: Self, a: Self,
@ -93,33 +96,21 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
} }
impl<'a, 'tcx> At<'a, 'tcx> { impl<'a, 'tcx> At<'a, 'tcx> {
pub fn define_opaque_types(self, define_opaque_types: bool) -> Self {
Self { define_opaque_types, ..self }
}
/// Hacky routine for equating two impl headers in coherence.
pub fn eq_impl_headers(
self,
expected: &ty::ImplHeader<'tcx>,
actual: &ty::ImplHeader<'tcx>,
) -> InferResult<'tcx, ()> {
debug!("eq_impl_header({:?} = {:?})", expected, actual);
match (expected.trait_ref, actual.trait_ref) {
(Some(a_ref), Some(b_ref)) => self.eq(a_ref, b_ref),
(None, None) => self.eq(expected.self_ty, actual.self_ty),
_ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
}
}
/// Makes `a <: b`, where `a` may or may not be expected. /// Makes `a <: b`, where `a` may or may not be expected.
/// ///
/// See [`At::trace_exp`] and [`Trace::sub`] for a version of /// See [`At::trace_exp`] and [`Trace::sub`] for a version of
/// this method that only requires `T: Relate<'tcx>` /// this method that only requires `T: Relate<'tcx>`
pub fn sub_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()> pub fn sub_exp<T>(
self,
define_opaque_types: DefineOpaqueTypes,
a_is_expected: bool,
a: T,
b: T,
) -> InferResult<'tcx, ()>
where where
T: ToTrace<'tcx>, T: ToTrace<'tcx>,
{ {
self.trace_exp(a_is_expected, a, b).sub(a, b) self.trace_exp(a_is_expected, a, b).sub(define_opaque_types, a, b)
} }
/// Makes `actual <: expected`. For example, if type-checking a /// Makes `actual <: expected`. For example, if type-checking a
@ -129,54 +120,81 @@ impl<'a, 'tcx> At<'a, 'tcx> {
/// ///
/// See [`At::trace`] and [`Trace::sub`] for a version of /// See [`At::trace`] and [`Trace::sub`] for a version of
/// this method that only requires `T: Relate<'tcx>` /// this method that only requires `T: Relate<'tcx>`
pub fn sup<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> pub fn sup<T>(
self,
define_opaque_types: DefineOpaqueTypes,
expected: T,
actual: T,
) -> InferResult<'tcx, ()>
where where
T: ToTrace<'tcx>, T: ToTrace<'tcx>,
{ {
self.sub_exp(false, actual, expected) self.sub_exp(define_opaque_types, false, actual, expected)
} }
/// Makes `expected <: actual`. /// Makes `expected <: actual`.
/// ///
/// See [`At::trace`] and [`Trace::sub`] for a version of /// See [`At::trace`] and [`Trace::sub`] for a version of
/// this method that only requires `T: Relate<'tcx>` /// this method that only requires `T: Relate<'tcx>`
pub fn sub<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> pub fn sub<T>(
self,
define_opaque_types: DefineOpaqueTypes,
expected: T,
actual: T,
) -> InferResult<'tcx, ()>
where where
T: ToTrace<'tcx>, T: ToTrace<'tcx>,
{ {
self.sub_exp(true, expected, actual) self.sub_exp(define_opaque_types, true, expected, actual)
} }
/// Makes `expected <: actual`. /// Makes `expected <: actual`.
/// ///
/// See [`At::trace_exp`] and [`Trace::eq`] for a version of /// See [`At::trace_exp`] and [`Trace::eq`] for a version of
/// this method that only requires `T: Relate<'tcx>` /// this method that only requires `T: Relate<'tcx>`
pub fn eq_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()> pub fn eq_exp<T>(
self,
define_opaque_types: DefineOpaqueTypes,
a_is_expected: bool,
a: T,
b: T,
) -> InferResult<'tcx, ()>
where where
T: ToTrace<'tcx>, T: ToTrace<'tcx>,
{ {
self.trace_exp(a_is_expected, a, b).eq(a, b) self.trace_exp(a_is_expected, a, b).eq(define_opaque_types, a, b)
} }
/// Makes `expected <: actual`. /// Makes `expected <: actual`.
/// ///
/// See [`At::trace`] and [`Trace::eq`] for a version of /// See [`At::trace`] and [`Trace::eq`] for a version of
/// this method that only requires `T: Relate<'tcx>` /// this method that only requires `T: Relate<'tcx>`
pub fn eq<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> pub fn eq<T>(
self,
define_opaque_types: DefineOpaqueTypes,
expected: T,
actual: T,
) -> InferResult<'tcx, ()>
where where
T: ToTrace<'tcx>, T: ToTrace<'tcx>,
{ {
self.trace(expected, actual).eq(expected, actual) self.trace(expected, actual).eq(define_opaque_types, expected, actual)
} }
pub fn relate<T>(self, expected: T, variance: ty::Variance, actual: T) -> InferResult<'tcx, ()> pub fn relate<T>(
self,
define_opaque_types: DefineOpaqueTypes,
expected: T,
variance: ty::Variance,
actual: T,
) -> InferResult<'tcx, ()>
where where
T: ToTrace<'tcx>, T: ToTrace<'tcx>,
{ {
match variance { match variance {
ty::Variance::Covariant => self.sub(expected, actual), ty::Variance::Covariant => self.sub(define_opaque_types, expected, actual),
ty::Variance::Invariant => self.eq(expected, actual), ty::Variance::Invariant => self.eq(define_opaque_types, expected, actual),
ty::Variance::Contravariant => self.sup(expected, actual), ty::Variance::Contravariant => self.sup(define_opaque_types, expected, actual),
// We could make this make sense but it's not readily // We could make this make sense but it's not readily
// exposed and I don't feel like dealing with it. Note // exposed and I don't feel like dealing with it. Note
@ -195,11 +213,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
/// ///
/// See [`At::trace`] and [`Trace::lub`] for a version of /// See [`At::trace`] and [`Trace::lub`] for a version of
/// this method that only requires `T: Relate<'tcx>` /// this method that only requires `T: Relate<'tcx>`
pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T> pub fn lub<T>(
self,
define_opaque_types: DefineOpaqueTypes,
expected: T,
actual: T,
) -> InferResult<'tcx, T>
where where
T: ToTrace<'tcx>, T: ToTrace<'tcx>,
{ {
self.trace(expected, actual).lub(expected, actual) self.trace(expected, actual).lub(define_opaque_types, expected, actual)
} }
/// Computes the greatest-lower-bound, or mutual subtype, of two /// Computes the greatest-lower-bound, or mutual subtype, of two
@ -208,11 +231,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
/// ///
/// See [`At::trace`] and [`Trace::glb`] for a version of /// See [`At::trace`] and [`Trace::glb`] for a version of
/// this method that only requires `T: Relate<'tcx>` /// this method that only requires `T: Relate<'tcx>`
pub fn glb<T>(self, expected: T, actual: T) -> InferResult<'tcx, T> pub fn glb<T>(
self,
define_opaque_types: DefineOpaqueTypes,
expected: T,
actual: T,
) -> InferResult<'tcx, T>
where where
T: ToTrace<'tcx>, T: ToTrace<'tcx>,
{ {
self.trace(expected, actual).glb(expected, actual) self.trace(expected, actual).glb(define_opaque_types, expected, actual)
} }
/// Sets the "trace" values that will be used for /// Sets the "trace" values that will be used for
@ -233,7 +261,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
where where
T: ToTrace<'tcx>, T: ToTrace<'tcx>,
{ {
let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b); let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
Trace { at: self, trace, a_is_expected } Trace { at: self, trace, a_is_expected }
} }
} }
@ -242,13 +270,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
/// Makes `a <: b` where `a` may or may not be expected (if /// Makes `a <: b` where `a` may or may not be expected (if
/// `a_is_expected` is true, then `a` is expected). /// `a_is_expected` is true, then `a` is expected).
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
pub fn sub<T>(self, a: T, b: T) -> InferResult<'tcx, ()> pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
where where
T: Relate<'tcx>, T: Relate<'tcx>,
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields fields
.sub(a_is_expected) .sub(a_is_expected)
.relate(a, b) .relate(a, b)
@ -259,13 +287,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
/// Makes `a == b`; the expectation is set by the call to /// Makes `a == b`; the expectation is set by the call to
/// `trace()`. /// `trace()`.
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
pub fn eq<T>(self, a: T, b: T) -> InferResult<'tcx, ()> pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
where where
T: Relate<'tcx>, T: Relate<'tcx>,
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields fields
.equate(a_is_expected) .equate(a_is_expected)
.relate(a, b) .relate(a, b)
@ -274,13 +302,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
} }
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
pub fn lub<T>(self, a: T, b: T) -> InferResult<'tcx, T> pub fn lub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
where where
T: Relate<'tcx>, T: Relate<'tcx>,
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields fields
.lub(a_is_expected) .lub(a_is_expected)
.relate(a, b) .relate(a, b)
@ -289,13 +317,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
} }
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
pub fn glb<T>(self, a: T, b: T) -> InferResult<'tcx, T> pub fn glb<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
where where
T: Relate<'tcx>, T: Relate<'tcx>,
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields fields
.glb(a_is_expected) .glb(a_is_expected)
.relate(a, b) .relate(a, b)
@ -306,7 +334,6 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> { impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
fn to_trace( fn to_trace(
tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
a_is_expected: bool, a_is_expected: bool,
a: Self, a: Self,
@ -314,10 +341,10 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
) -> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> {
match (a, b) { match (a, b) {
(ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => { (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
ToTrace::to_trace(tcx, cause, a_is_expected, trait_ref_a, trait_ref_b) ToTrace::to_trace(cause, a_is_expected, trait_ref_a, trait_ref_b)
} }
(ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => { (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
ToTrace::to_trace(tcx, cause, a_is_expected, ty_a, ty_b) ToTrace::to_trace(cause, a_is_expected, ty_a, ty_b)
} }
(ImplSubject::Trait(_), ImplSubject::Inherent(_)) (ImplSubject::Trait(_), ImplSubject::Inherent(_))
| (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => { | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
@ -329,7 +356,6 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
fn to_trace( fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
a_is_expected: bool, a_is_expected: bool,
a: Self, a: Self,
@ -344,7 +370,6 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
fn to_trace( fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
a_is_expected: bool, a_is_expected: bool,
a: Self, a: Self,
@ -356,7 +381,6 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
impl<'tcx> ToTrace<'tcx> for Const<'tcx> { impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
fn to_trace( fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
a_is_expected: bool, a_is_expected: bool,
a: Self, a: Self,
@ -371,7 +395,6 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
fn to_trace( fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
a_is_expected: bool, a_is_expected: bool,
a: Self, a: Self,
@ -399,7 +422,6 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
fn to_trace( fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
a_is_expected: bool, a_is_expected: bool,
a: Self, a: Self,
@ -411,7 +433,6 @@ impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
fn to_trace( fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
a_is_expected: bool, a_is_expected: bool,
a: Self, a: Self,
@ -426,7 +447,6 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
fn to_trace( fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
a_is_expected: bool, a_is_expected: bool,
a: Self, a: Self,
@ -441,24 +461,17 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
fn to_trace( fn to_trace(
tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
a_is_expected: bool, a_is_expected: bool,
a: Self, a: Self,
b: Self, b: Self,
) -> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> {
let a_ty = tcx.mk_projection(a.def_id, a.substs); TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) }
let b_ty = tcx.mk_projection(b.def_id, b.substs);
TypeTrace {
cause: cause.clone(),
values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())),
}
} }
} }
impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
fn to_trace( fn to_trace(
_: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
a_is_expected: bool, a_is_expected: bool,
a: Self, a: Self,

View file

@ -14,7 +14,7 @@ use crate::infer::canonical::{
}; };
use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin}; use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
use crate::traits::query::{Fallible, NoSolution}; use crate::traits::query::{Fallible, NoSolution};
use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt}; use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt};
@ -510,7 +510,7 @@ impl<'tcx> InferCtxt<'tcx> {
let b = substitute_value(self.tcx, &result_subst, b); let b = substitute_value(self.tcx, &result_subst, b);
debug!(?a, ?b, "constrain opaque type"); debug!(?a, ?b, "constrain opaque type");
obligations obligations
.extend(self.at(cause, param_env).define_opaque_types(true).eq(a, b)?.obligations); .extend(self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, a, b)?.obligations);
} }
Ok(InferOk { value: result_subst, obligations }) Ok(InferOk { value: result_subst, obligations })
@ -603,8 +603,11 @@ impl<'tcx> InferCtxt<'tcx> {
match (value1.unpack(), value2.unpack()) { match (value1.unpack(), value2.unpack()) {
(GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
obligations obligations.extend(
.extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); self.at(cause, param_env)
.eq(DefineOpaqueTypes::Yes, v1, v2)?
.into_obligations(),
);
} }
(GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2)) (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
if re1.is_erased() && re2.is_erased() => if re1.is_erased() && re2.is_erased() =>
@ -612,11 +615,14 @@ impl<'tcx> InferCtxt<'tcx> {
// no action needed // no action needed
} }
(GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => { (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => {
obligations obligations.extend(
.extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); self.at(cause, param_env)
.eq(DefineOpaqueTypes::Yes, v1, v2)?
.into_obligations(),
);
} }
(GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
let ok = self.at(cause, param_env).eq(v1, v2)?; let ok = self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, v1, v2)?;
obligations.extend(ok.into_obligations()); obligations.extend(ok.into_obligations());
} }
_ => { _ => {

View file

@ -27,7 +27,7 @@ use super::glb::Glb;
use super::lub::Lub; use super::lub::Lub;
use super::sub::Sub; use super::sub::Sub;
use super::type_variable::TypeVariableValue; use super::type_variable::TypeVariableValue;
use super::{InferCtxt, MiscVariable, TypeTrace}; use super::{DefineOpaqueTypes, InferCtxt, MiscVariable, TypeTrace};
use crate::traits::{Obligation, PredicateObligations}; use crate::traits::{Obligation, PredicateObligations};
use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::sso::SsoHashMap;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
@ -52,12 +52,7 @@ pub struct CombineFields<'infcx, 'tcx> {
pub cause: Option<ty::relate::Cause>, pub cause: Option<ty::relate::Cause>,
pub param_env: ty::ParamEnv<'tcx>, pub param_env: ty::ParamEnv<'tcx>,
pub obligations: PredicateObligations<'tcx>, pub obligations: PredicateObligations<'tcx>,
/// Whether we should define opaque types pub define_opaque_types: DefineOpaqueTypes,
/// or just treat them opaquely.
/// Currently only used to prevent predicate
/// matching from matching anything against opaque
/// types.
pub define_opaque_types: bool,
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]

View file

@ -1,3 +1,4 @@
use crate::infer::DefineOpaqueTypes;
use crate::traits::PredicateObligations; use crate::traits::PredicateObligations;
use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir}; use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir};
@ -110,7 +111,8 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
} }
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if self.fields.define_opaque_types && def_id.is_local() => if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
&& def_id.is_local() =>
{ {
self.fields.obligations.extend( self.fields.obligations.extend(
infcx infcx

View file

@ -1568,6 +1568,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => { ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
(false, Mismatch::Fixed("trait")) (false, Mismatch::Fixed("trait"))
} }
ValuePairs::Aliases(infer::ExpectedFound { expected, .. }) => {
(false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id)))
}
ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")), ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
}; };
let Some(vals) = self.values_str(values) else { let Some(vals) = self.values_str(values) else {
@ -2124,6 +2127,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
match values { match values {
infer::Regions(exp_found) => self.expected_found_str(exp_found), infer::Regions(exp_found) => self.expected_found_str(exp_found),
infer::Terms(exp_found) => self.expected_found_str_term(exp_found), infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
infer::Aliases(exp_found) => self.expected_found_str(exp_found),
infer::TraitRefs(exp_found) => { infer::TraitRefs(exp_found) => {
let pretty_exp_found = ty::error::ExpectedFound { let pretty_exp_found = ty::error::ExpectedFound {
expected: exp_found.expected.print_only_trait_path(), expected: exp_found.expected.print_only_trait_path(),

View file

@ -2,8 +2,8 @@
use super::combine::{CombineFields, ObligationEmittingRelation}; use super::combine::{CombineFields, ObligationEmittingRelation};
use super::lattice::{self, LatticeDir}; use super::lattice::{self, LatticeDir};
use super::InferCtxt;
use super::Subtype; use super::Subtype;
use super::{DefineOpaqueTypes, InferCtxt};
use crate::traits::{ObligationCause, PredicateObligations}; use crate::traits::{ObligationCause, PredicateObligations};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
@ -142,7 +142,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
Ok(()) Ok(())
} }
fn define_opaque_types(&self) -> bool { fn define_opaque_types(&self) -> DefineOpaqueTypes {
self.fields.define_opaque_types self.fields.define_opaque_types
} }
} }

View file

@ -19,7 +19,7 @@
use super::combine::ObligationEmittingRelation; use super::combine::ObligationEmittingRelation;
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::InferCtxt; use super::{DefineOpaqueTypes, InferCtxt};
use crate::traits::ObligationCause; use crate::traits::ObligationCause;
use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::relate::RelateResult;
@ -36,7 +36,7 @@ pub trait LatticeDir<'f, 'tcx>: ObligationEmittingRelation<'tcx> {
fn cause(&self) -> &ObligationCause<'tcx>; fn cause(&self) -> &ObligationCause<'tcx>;
fn define_opaque_types(&self) -> bool; fn define_opaque_types(&self) -> DefineOpaqueTypes;
// Relates the type `v` to `a` and `b` such that `v` represents // Relates the type `v` to `a` and `b` such that `v` represents
// the LUB/GLB of `a` and `b` as appropriate. // the LUB/GLB of `a` and `b` as appropriate.
@ -110,7 +110,7 @@ where
) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b), ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if this.define_opaque_types() && def_id.is_local() => if this.define_opaque_types() == DefineOpaqueTypes::Yes && def_id.is_local() =>
{ {
this.register_obligations( this.register_obligations(
infcx infcx

View file

@ -2,8 +2,8 @@
use super::combine::{CombineFields, ObligationEmittingRelation}; use super::combine::{CombineFields, ObligationEmittingRelation};
use super::lattice::{self, LatticeDir}; use super::lattice::{self, LatticeDir};
use super::InferCtxt;
use super::Subtype; use super::Subtype;
use super::{DefineOpaqueTypes, InferCtxt};
use crate::traits::{ObligationCause, PredicateObligations}; use crate::traits::{ObligationCause, PredicateObligations};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
@ -142,7 +142,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
Ok(()) Ok(())
} }
fn define_opaque_types(&self) -> bool { fn define_opaque_types(&self) -> DefineOpaqueTypes {
self.fields.define_opaque_types self.fields.define_opaque_types
} }
} }

View file

@ -1,3 +1,4 @@
pub use self::at::DefineOpaqueTypes;
pub use self::freshen::TypeFreshener; pub use self::freshen::TypeFreshener;
pub use self::lexical_region_resolve::RegionResolutionError; pub use self::lexical_region_resolve::RegionResolutionError;
pub use self::LateBoundRegionConversionTime::*; pub use self::LateBoundRegionConversionTime::*;
@ -338,6 +339,7 @@ pub struct InferCtxt<'tcx> {
pub enum ValuePairs<'tcx> { pub enum ValuePairs<'tcx> {
Regions(ExpectedFound<ty::Region<'tcx>>), Regions(ExpectedFound<ty::Region<'tcx>>),
Terms(ExpectedFound<ty::Term<'tcx>>), Terms(ExpectedFound<ty::Term<'tcx>>),
Aliases(ExpectedFound<ty::AliasTy<'tcx>>),
TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>), TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>), PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
Sigs(ExpectedFound<ty::FnSig<'tcx>>), Sigs(ExpectedFound<ty::FnSig<'tcx>>),
@ -729,7 +731,7 @@ impl<'tcx> InferCtxt<'tcx> {
&'a self, &'a self,
trace: TypeTrace<'tcx>, trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
define_opaque_types: bool, define_opaque_types: DefineOpaqueTypes,
) -> CombineFields<'a, 'tcx> { ) -> CombineFields<'a, 'tcx> {
CombineFields { CombineFields {
infcx: self, infcx: self,
@ -864,7 +866,7 @@ impl<'tcx> InferCtxt<'tcx> {
T: at::ToTrace<'tcx>, T: at::ToTrace<'tcx>,
{ {
let origin = &ObligationCause::dummy(); let origin = &ObligationCause::dummy();
self.probe(|_| self.at(origin, param_env).sub(a, b).is_ok()) self.probe(|_| self.at(origin, param_env).sub(DefineOpaqueTypes::No, a, b).is_ok())
} }
pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
@ -872,7 +874,7 @@ impl<'tcx> InferCtxt<'tcx> {
T: at::ToTrace<'tcx>, T: at::ToTrace<'tcx>,
{ {
let origin = &ObligationCause::dummy(); let origin = &ObligationCause::dummy();
self.probe(|_| self.at(origin, param_env).eq(a, b).is_ok()) self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::No, a, b).is_ok())
} }
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
@ -967,7 +969,8 @@ impl<'tcx> InferCtxt<'tcx> {
let ty::SubtypePredicate { a_is_expected, a, b } = let ty::SubtypePredicate { a_is_expected, a, b } =
self.instantiate_binder_with_placeholders(predicate); self.instantiate_binder_with_placeholders(predicate);
let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; let ok =
self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)?;
Ok(ok.unit()) Ok(ok.unit())
})) }))

View file

@ -1,3 +1,5 @@
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::{DefineOpaqueTypes, InferResult};
use crate::errors::OpaqueHiddenTypeDiag; use crate::errors::OpaqueHiddenTypeDiag;
use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
use crate::traits; use crate::traits;
@ -16,18 +18,13 @@ use rustc_middle::ty::{
TypeVisitable, TypeVisitableExt, TypeVisitor, TypeVisitable, TypeVisitableExt, TypeVisitor,
}; };
use rustc_span::Span; use rustc_span::Span;
use std::ops::ControlFlow; use std::ops::ControlFlow;
pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
mod table; mod table;
pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
pub use table::{OpaqueTypeStorage, OpaqueTypeTable}; pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::InferResult;
/// Information about the opaque types whose values we /// Information about the opaque types whose values we
/// are inferring in this function (these are the `impl Trait` that /// are inferring in this function (these are the `impl Trait` that
/// appear in the return type). /// appear in the return type).
@ -547,8 +544,7 @@ impl<'tcx> InferCtxt<'tcx> {
if let Some(prev) = prev { if let Some(prev) = prev {
obligations = self obligations = self
.at(&cause, param_env) .at(&cause, param_env)
.define_opaque_types(true) .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
.eq_exp(a_is_expected, prev, hidden_ty)?
.obligations; .obligations;
} }

View file

@ -1,5 +1,5 @@
use super::combine::{CombineFields, RelationDir}; use super::combine::{CombineFields, RelationDir};
use super::{ObligationEmittingRelation, SubregionOrigin}; use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin};
use crate::traits::{Obligation, PredicateObligations}; use crate::traits::{Obligation, PredicateObligations};
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
@ -138,7 +138,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
} }
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if self.fields.define_opaque_types && def_id.is_local() => if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
&& def_id.is_local() =>
{ {
self.fields.obligations.extend( self.fields.obligations.extend(
infcx infcx

View file

@ -1390,7 +1390,7 @@ pub struct UnusedOp<'a> {
pub op: &'a str, pub op: &'a str,
#[label] #[label]
pub label: Span, pub label: Span,
#[suggestion(style = "verbose", code = "let _ = ", applicability = "machine-applicable")] #[suggestion(style = "verbose", code = "let _ = ", applicability = "maybe-incorrect")]
pub suggestion: Span, pub suggestion: Span,
} }
@ -1434,17 +1434,15 @@ pub struct UnusedDef<'a, 'b> {
} }
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
pub enum UnusedDefSuggestion { #[suggestion(
#[suggestion( lint_suggestion,
lint_suggestion, style = "verbose",
style = "verbose", code = "let _ = ",
code = "let _ = ", applicability = "maybe-incorrect"
applicability = "machine-applicable" )]
)] pub struct UnusedDefSuggestion {
Default { #[primary_span]
#[primary_span] pub span: Span,
span: Span,
},
} }
// Needed because of def_path_str // Needed because of def_path_str

View file

@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span); let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span);
let type_lint_emitted_or_suppressed = match must_use_result { let type_lint_emitted_or_suppressed = match must_use_result {
Some(path) => { Some(path) => {
emit_must_use_untranslated(cx, &path, "", "", 1); emit_must_use_untranslated(cx, &path, "", "", 1, false);
true true
} }
None => false, None => false,
@ -358,6 +358,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_pre_path, descr_pre_path,
descr_post_path, descr_post_path,
1, 1,
false,
) )
}) })
.is_some() .is_some()
@ -370,6 +371,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_pre: &str, descr_pre: &str,
descr_post: &str, descr_post: &str,
plural_len: usize, plural_len: usize,
is_inner: bool,
) { ) {
let plural_suffix = pluralize!(plural_len); let plural_suffix = pluralize!(plural_len);
@ -377,20 +379,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
MustUsePath::Suppressed => {} MustUsePath::Suppressed => {}
MustUsePath::Boxed(path) => { MustUsePath::Boxed(path) => {
let descr_pre = &format!("{}boxed ", descr_pre); let descr_pre = &format!("{}boxed ", descr_pre);
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
} }
MustUsePath::Opaque(path) => { MustUsePath::Opaque(path) => {
let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix); let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix);
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
} }
MustUsePath::TraitObject(path) => { MustUsePath::TraitObject(path) => {
let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post); let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post);
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true);
} }
MustUsePath::TupleElement(elems) => { MustUsePath::TupleElement(elems) => {
for (index, path) in elems { for (index, path) in elems {
let descr_post = &format!(" in tuple element {}", index); let descr_post = &format!(" in tuple element {}", index);
emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); emit_must_use_untranslated(
cx, path, descr_pre, descr_post, plural_len, true,
);
} }
} }
MustUsePath::Array(path, len) => { MustUsePath::Array(path, len) => {
@ -401,6 +405,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_pre, descr_pre,
descr_post, descr_post,
plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)), plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
true,
); );
} }
MustUsePath::Closure(span) => { MustUsePath::Closure(span) => {
@ -418,19 +423,6 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
); );
} }
MustUsePath::Def(span, def_id, reason) => { MustUsePath::Def(span, def_id, reason) => {
let suggestion = if matches!(
cx.tcx.get_diagnostic_name(*def_id),
Some(sym::add)
| Some(sym::sub)
| Some(sym::mul)
| Some(sym::div)
| Some(sym::rem)
| Some(sym::neg),
) {
Some(UnusedDefSuggestion::Default { span: span.shrink_to_lo() })
} else {
None
};
cx.emit_spanned_lint( cx.emit_spanned_lint(
UNUSED_MUST_USE, UNUSED_MUST_USE,
*span, *span,
@ -440,7 +432,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
cx, cx,
def_id: *def_id, def_id: *def_id,
note: *reason, note: *reason,
suggestion, suggestion: (!is_inner)
.then_some(UnusedDefSuggestion { span: span.shrink_to_lo() }),
}, },
); );
} }

View file

@ -1081,7 +1081,7 @@ pub enum Rvalue<'tcx> {
/// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
/// ///
/// For addition, subtraction, and multiplication on integers the error condition is set when /// For addition, subtraction, and multiplication on integers the error condition is set when
/// the infinite precision result would be unequal to the actual result. /// the infinite precision result would not be equal to the actual result.
/// ///
/// Other combinations of types and operators are unsupported. /// Other combinations of types and operators are unsupported.
CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),

View file

@ -2215,7 +2215,7 @@ rustc_queries! {
} }
/// Used in `super_combine_consts` to ICE if the type of the two consts are definitely not going to end up being /// Used in `super_combine_consts` to ICE if the type of the two consts are definitely not going to end up being
/// equal to eachother. This might return `Ok` even if the types are unequal, but will never return `Err` if /// equal to eachother. This might return `Ok` even if the types are not equal, but will never return `Err` if
/// the types might be equal. /// the types might be equal.
query check_tys_might_be_eq(arg: Canonical<'tcx, (ty::ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>) -> Result<(), NoSolution> { query check_tys_might_be_eq(arg: Canonical<'tcx, (ty::ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>) -> Result<(), NoSolution> {
desc { "check whether two const param are definitely not equal to eachother"} desc { "check whether two const param are definitely not equal to eachother"}

View file

@ -237,7 +237,7 @@ impl ScalarInt {
} }
/// Tries to convert the `ScalarInt` to an unsigned integer of the given size. /// Tries to convert the `ScalarInt` to an unsigned integer of the given size.
/// Fails if the size of the `ScalarInt` is unequal to `size` and returns the /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the
/// `ScalarInt`s size in that case. /// `ScalarInt`s size in that case.
#[inline] #[inline]
pub fn try_to_uint(self, size: Size) -> Result<u128, Size> { pub fn try_to_uint(self, size: Size) -> Result<u128, Size> {
@ -297,7 +297,7 @@ impl ScalarInt {
} }
/// Tries to convert the `ScalarInt` to a signed integer of the given size. /// Tries to convert the `ScalarInt` to a signed integer of the given size.
/// Fails if the size of the `ScalarInt` is unequal to `size` and returns the /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the
/// `ScalarInt`s size in that case. /// `ScalarInt`s size in that case.
#[inline] #[inline]
pub fn try_to_int(self, size: Size) -> Result<i128, Size> { pub fn try_to_int(self, size: Size) -> Result<i128, Size> {
@ -306,35 +306,35 @@ impl ScalarInt {
} }
/// Tries to convert the `ScalarInt` to i8. /// Tries to convert the `ScalarInt` to i8.
/// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 1 }` /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 1 }`
/// and returns the `ScalarInt`s size in that case. /// and returns the `ScalarInt`s size in that case.
pub fn try_to_i8(self) -> Result<i8, Size> { pub fn try_to_i8(self) -> Result<i8, Size> {
self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap()) self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap())
} }
/// Tries to convert the `ScalarInt` to i16. /// Tries to convert the `ScalarInt` to i16.
/// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 2 }` /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 2 }`
/// and returns the `ScalarInt`s size in that case. /// and returns the `ScalarInt`s size in that case.
pub fn try_to_i16(self) -> Result<i16, Size> { pub fn try_to_i16(self) -> Result<i16, Size> {
self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap()) self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap())
} }
/// Tries to convert the `ScalarInt` to i32. /// Tries to convert the `ScalarInt` to i32.
/// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 4 }` /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 4 }`
/// and returns the `ScalarInt`s size in that case. /// and returns the `ScalarInt`s size in that case.
pub fn try_to_i32(self) -> Result<i32, Size> { pub fn try_to_i32(self) -> Result<i32, Size> {
self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap()) self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap())
} }
/// Tries to convert the `ScalarInt` to i64. /// Tries to convert the `ScalarInt` to i64.
/// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 8 }` /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 8 }`
/// and returns the `ScalarInt`s size in that case. /// and returns the `ScalarInt`s size in that case.
pub fn try_to_i64(self) -> Result<i64, Size> { pub fn try_to_i64(self) -> Result<i64, Size> {
self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap()) self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap())
} }
/// Tries to convert the `ScalarInt` to i128. /// Tries to convert the `ScalarInt` to i128.
/// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 16 }` /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 16 }`
/// and returns the `ScalarInt`s size in that case. /// and returns the `ScalarInt`s size in that case.
pub fn try_to_i128(self) -> Result<i128, Size> { pub fn try_to_i128(self) -> Result<i128, Size> {
self.try_to_int(Size::from_bits(128)).map(|v| i128::try_from(v).unwrap()) self.try_to_int(Size::from_bits(128)).map(|v| i128::try_from(v).unwrap())

View file

@ -71,6 +71,7 @@ use rustc_type_ir::WithCachedTypeInfo;
use rustc_type_ir::{CollectAndApply, DynKind, Interner, TypeFlags}; use rustc_type_ir::{CollectAndApply, DynKind, Interner, TypeFlags};
use std::any::Any; use std::any::Any;
use std::assert_matches::debug_assert_matches;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt; use std::fmt;
@ -2049,6 +2050,12 @@ impl<'tcx> TyCtxt<'tcx> {
#[inline] #[inline]
pub fn mk_alias(self, kind: ty::AliasKind, alias_ty: ty::AliasTy<'tcx>) -> Ty<'tcx> { pub fn mk_alias(self, kind: ty::AliasKind, alias_ty: ty::AliasTy<'tcx>) -> Ty<'tcx> {
debug_assert_matches!(
(kind, self.def_kind(alias_ty.def_id)),
(ty::Opaque, DefKind::OpaqueTy)
| (ty::Projection, DefKind::AssocTy)
| (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
);
self.mk_ty_from_kind(Alias(kind, alias_ty)) self.mk_ty_from_kind(Alias(kind, alias_ty))
} }

View file

@ -1289,25 +1289,41 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => { PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
let span = find_span(&source, err); let span = find_span(&source, err);
err.span_label(self.r.def_span(def_id), &format!("`{path_str}` defined here")); err.span_label(self.r.def_span(def_id), &format!("`{path_str}` defined here"));
let (tail, descr, applicability) = match source {
PathSource::Pat | PathSource::TupleStruct(..) => {
("", "pattern", Applicability::MachineApplicable)
}
_ => (": val", "literal", Applicability::HasPlaceholders),
};
let (tail, descr, applicability, old_fields) = match source {
PathSource::Pat => ("", "pattern", Applicability::MachineApplicable, None),
PathSource::TupleStruct(_, args) => (
"",
"pattern",
Applicability::MachineApplicable,
Some(
args.iter()
.map(|a| self.r.tcx.sess.source_map().span_to_snippet(*a).ok())
.collect::<Vec<Option<String>>>(),
),
),
_ => (": val", "literal", Applicability::HasPlaceholders, None),
};
let field_ids = self.r.field_def_ids(def_id); let field_ids = self.r.field_def_ids(def_id);
let (fields, applicability) = match field_ids { let (fields, applicability) = match field_ids {
Some(field_ids) => ( Some(field_ids) => {
field_ids let fields = field_ids.iter().map(|&id| self.r.tcx.item_name(id));
.iter()
.map(|&field_id| { let fields = if let Some(old_fields) = old_fields {
format!("{}{tail}", self.r.tcx.item_name(field_id)) fields
}) .enumerate()
.collect::<Vec<String>>() .map(|(idx, new)| (new, old_fields.get(idx)))
.join(", "), .map(|(new, old)| {
applicability, let new = new.to_ident_string();
), if let Some(Some(old)) = old && new != *old { format!("{}: {}", new, old) } else { new }
})
.collect::<Vec<String>>()
} else {
fields.map(|f| format!("{f}{tail}")).collect::<Vec<String>>()
};
(fields.join(", "), applicability)
}
None => ("/* fields */".to_string(), Applicability::HasPlaceholders), None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
}; };
let pad = match field_ids { let pad = match field_ids {

View file

@ -2,7 +2,7 @@ use rustc_hir::def_id::DefId;
use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime};
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::ObligationCause; use rustc_infer::traits::ObligationCause;
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
@ -144,7 +144,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
self.infcx self.infcx
.at(&ObligationCause::dummy(), param_env) .at(&ObligationCause::dummy(), param_env)
.eq(lhs, rhs) .eq(DefineOpaqueTypes::No, lhs, rhs)
.map(|InferOk { value: (), obligations }| { .map(|InferOk { value: (), obligations }| {
obligations.into_iter().map(|o| o.into()).collect() obligations.into_iter().map(|o| o.into()).collect()
}) })

View file

@ -19,7 +19,7 @@ use std::mem;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt};
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_middle::traits::solve::{ use rustc_middle::traits::solve::{
CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData, CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData,
@ -268,7 +268,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
let InferOk { value: (), obligations } = self let InferOk { value: (), obligations } = self
.infcx .infcx
.at(&ObligationCause::dummy(), goal.param_env) .at(&ObligationCause::dummy(), goal.param_env)
.sub(goal.predicate.a, goal.predicate.b)?; .sub(DefineOpaqueTypes::No, goal.predicate.a, goal.predicate.b)?;
self.evaluate_all_and_make_canonical_response( self.evaluate_all_and_make_canonical_response(
obligations.into_iter().map(|pred| pred.into()).collect(), obligations.into_iter().map(|pred| pred.into()).collect(),
) )

View file

@ -7,6 +7,7 @@ use crate::errors::UnableToConstructConstantValue;
use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectAndUnifyResult;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::visit::TypeVisitableExt;
@ -814,7 +815,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
match (evaluate(c1), evaluate(c2)) { match (evaluate(c1), evaluate(c2)) {
(Ok(c1), Ok(c2)) => { (Ok(c1), Ok(c2)) => {
match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2) match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(DefineOpaqueTypes::No,c1, c2)
{ {
Ok(_) => (), Ok(_) => (),
Err(_) => return false, Err(_) => return false,

View file

@ -17,7 +17,7 @@ use crate::traits::{
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic; use rustc_errors::Diagnostic;
use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::{DefineOpaqueTypes, DefiningAnchor, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util; use rustc_infer::traits::util;
use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
@ -181,7 +181,7 @@ fn overlap_within_probe<'cx, 'tcx>(
let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id); let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id); let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id);
let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?; let obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
debug!("overlap: unification check succeeded"); debug!("overlap: unification check succeeded");
if overlap_mode.use_implicit_negative() { if overlap_mode.use_implicit_negative() {
@ -207,20 +207,25 @@ fn overlap_within_probe<'cx, 'tcx>(
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
} }
fn equate_impl_headers<'cx, 'tcx>( #[instrument(level = "debug", skip(infcx), ret)]
selcx: &mut SelectionContext<'cx, 'tcx>, fn equate_impl_headers<'tcx>(
impl1_header: &ty::ImplHeader<'tcx>, infcx: &InferCtxt<'tcx>,
impl2_header: &ty::ImplHeader<'tcx>, impl1: &ty::ImplHeader<'tcx>,
impl2: &ty::ImplHeader<'tcx>,
) -> Option<PredicateObligations<'tcx>> { ) -> Option<PredicateObligations<'tcx>> {
// Do `a` and `b` unify? If not, no overlap. let result = match (impl1.trait_ref, impl2.trait_ref) {
debug!("equate_impl_headers(impl1_header={:?}, impl2_header={:?}", impl1_header, impl2_header); (Some(impl1_ref), Some(impl2_ref)) => infcx
selcx .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
.infcx .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref),
.at(&ObligationCause::dummy(), ty::ParamEnv::empty()) (None, None) => infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
.define_opaque_types(true) DefineOpaqueTypes::Yes,
.eq_impl_headers(impl1_header, impl2_header) impl1.self_ty,
.map(|infer_ok| infer_ok.obligations) impl2.self_ty,
.ok() ),
_ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
};
result.map(|infer_ok| infer_ok.obligations).ok()
} }
/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including /// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
@ -325,7 +330,7 @@ fn equate<'tcx>(
) -> bool { ) -> bool {
// do the impls unify? If not, not disjoint. // do the impls unify? If not, not disjoint.
let Ok(InferOk { obligations: more_obligations, .. }) = let Ok(InferOk { obligations: more_obligations, .. }) =
infcx.at(&ObligationCause::dummy(), impl_env).eq(subject1, subject2) infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No,subject1, subject2)
else { else {
debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2); debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
return true; return true;

View file

@ -11,7 +11,7 @@ use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::canonical::{ use rustc_infer::infer::canonical::{
Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse, Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
}; };
use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
use rustc_infer::traits::query::Fallible; use rustc_infer::traits::query::Fallible;
use rustc_infer::traits::{ use rustc_infer::traits::{
FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
@ -128,8 +128,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
{ {
self.infcx self.infcx
.at(cause, param_env) .at(cause, param_env)
.define_opaque_types(true) .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, a, b)
.eq_exp(a_is_expected, a, b)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
} }
@ -142,8 +141,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> { ) -> Result<(), TypeError<'tcx>> {
self.infcx self.infcx
.at(cause, param_env) .at(cause, param_env)
.define_opaque_types(true) .eq(DefineOpaqueTypes::Yes, expected, actual)
.eq(expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
} }
@ -157,8 +155,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> { ) -> Result<(), TypeError<'tcx>> {
self.infcx self.infcx
.at(cause, param_env) .at(cause, param_env)
.define_opaque_types(true) .sub(DefineOpaqueTypes::Yes, expected, actual)
.sub(expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
} }
@ -172,8 +169,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> { ) -> Result<(), TypeError<'tcx>> {
self.infcx self.infcx
.at(cause, param_env) .at(cause, param_env)
.define_opaque_types(true) .sup(DefineOpaqueTypes::Yes, expected, actual)
.sup(expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
} }

View file

@ -2,6 +2,7 @@ use crate::infer::{InferCtxt, TyOrConstInferVar};
use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::ProjectionCacheKey; use rustc_infer::traits::ProjectionCacheKey;
use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation}; use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation};
use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::interpret::ErrorHandled;
@ -515,7 +516,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
if let Ok(new_obligations) = infcx if let Ok(new_obligations) = infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.trace(c1, c2) .trace(c1, c2)
.eq(a.substs, b.substs) .eq(DefineOpaqueTypes::No, a.substs, b.substs)
{ {
return ProcessResult::Changed(mk_pending( return ProcessResult::Changed(mk_pending(
new_obligations.into_obligations(), new_obligations.into_obligations(),
@ -524,8 +525,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
} }
(_, Unevaluated(_)) | (Unevaluated(_), _) => (), (_, Unevaluated(_)) | (Unevaluated(_), _) => (),
(_, _) => { (_, _) => {
if let Ok(new_obligations) = if let Ok(new_obligations) = infcx
infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2) .at(&obligation.cause, obligation.param_env)
.eq(DefineOpaqueTypes::No, c1, c2)
{ {
return ProcessResult::Changed(mk_pending( return ProcessResult::Changed(mk_pending(
new_obligations.into_obligations(), new_obligations.into_obligations(),
@ -565,12 +567,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
match (evaluate(c1), evaluate(c2)) { match (evaluate(c1), evaluate(c2)) {
(Ok(c1), Ok(c2)) => { (Ok(c1), Ok(c2)) => {
match self match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
.selcx DefineOpaqueTypes::No,
.infcx c1,
.at(&obligation.cause, obligation.param_env) c2,
.eq(c1, c2) ) {
{
Ok(inf_ok) => { Ok(inf_ok) => {
ProcessResult::Changed(mk_pending(inf_ok.into_obligations())) ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
} }
@ -610,12 +611,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
bug!("AliasEq is only used for new solver") bug!("AliasEq is only used for new solver")
} }
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
match self match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
.selcx DefineOpaqueTypes::No,
.infcx ct.ty(),
.at(&obligation.cause, obligation.param_env) ty,
.eq(ct.ty(), ty) ) {
{
Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())), Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError( Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError(
SelectionError::Unimplemented, SelectionError::Unimplemented,

View file

@ -28,6 +28,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::at::At; use rustc_infer::infer::at::At;
use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::ImplSourceBuiltinData; use rustc_infer::traits::ImplSourceBuiltinData;
use rustc_middle::traits::select::OverflowError; use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
@ -285,12 +286,12 @@ fn project_and_unify_type<'cx, 'tcx>(
); );
obligations.extend(new); obligations.extend(new);
match infcx // Need to define opaque types to support nested opaque types like `impl Fn() -> impl Trait`
.at(&obligation.cause, obligation.param_env) match infcx.at(&obligation.cause, obligation.param_env).eq(
// This is needed to support nested opaque types like `impl Fn() -> impl Trait` DefineOpaqueTypes::Yes,
.define_opaque_types(true) normalized,
.eq(normalized, actual) actual,
{ ) {
Ok(InferOk { obligations: inferred_obligations, value: () }) => { Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations); obligations.extend(inferred_obligations);
ProjectAndUnifyResult::Holds(obligations) ProjectAndUnifyResult::Holds(obligations)
@ -467,6 +468,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
return ty; return ty;
} }
let (kind, data) = match *ty.kind() {
ty::Alias(kind, alias_ty) => (kind, alias_ty),
_ => return ty.super_fold_with(self),
};
// We try to be a little clever here as a performance optimization in // We try to be a little clever here as a performance optimization in
// cases where there are nested projections under binders. // cases where there are nested projections under binders.
// For example: // For example:
@ -490,13 +496,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
// replace bound vars if the current type is a `Projection` and we need // replace bound vars if the current type is a `Projection` and we need
// to make sure we don't forget to fold the substs regardless. // to make sure we don't forget to fold the substs regardless.
match *ty.kind() { match kind {
// This is really important. While we *can* handle this, this has // This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with // severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark. // late-bound regions. See `issue-88862` benchmark.
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) ty::Opaque if !data.substs.has_escaping_bound_vars() => {
if !substs.has_escaping_bound_vars() =>
{
// Only normalize `impl Trait` outside of type inference, usually in codegen. // Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() { match self.param_env.reveal() {
Reveal::UserFacing => ty.super_fold_with(self), Reveal::UserFacing => ty.super_fold_with(self),
@ -512,8 +516,8 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
); );
} }
let substs = substs.fold_with(self); let substs = data.substs.fold_with(self);
let generic_ty = self.interner().type_of(def_id); let generic_ty = self.interner().type_of(data.def_id);
let concrete_ty = generic_ty.subst(self.interner(), substs); let concrete_ty = generic_ty.subst(self.interner(), substs);
self.depth += 1; self.depth += 1;
let folded_ty = self.fold_ty(concrete_ty); let folded_ty = self.fold_ty(concrete_ty);
@ -522,8 +526,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
} }
} }
} }
ty::Opaque => ty.super_fold_with(self),
ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => { ty::Projection if !data.has_escaping_bound_vars() => {
// This branch is *mostly* just an optimization: when we don't // This branch is *mostly* just an optimization: when we don't
// have escaping bound vars, we don't need to replace them with // have escaping bound vars, we don't need to replace them with
// placeholders (see branch below). *Also*, we know that we can // placeholders (see branch below). *Also*, we know that we can
@ -562,7 +567,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
normalized_ty.ty().unwrap() normalized_ty.ty().unwrap()
} }
ty::Alias(ty::Projection, data) => { ty::Projection => {
// If there are escaping bound vars, we temporarily replace the // If there are escaping bound vars, we temporarily replace the
// bound vars with placeholders. Note though, that in the case // bound vars with placeholders. Note though, that in the case
// that we still can't project for whatever reason (e.g. self // that we still can't project for whatever reason (e.g. self
@ -611,8 +616,6 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
); );
normalized_ty normalized_ty
} }
_ => ty.super_fold_with(self),
} }
} }
@ -2064,7 +2067,11 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
debug!(?cache_projection, ?obligation_projection); debug!(?cache_projection, ?obligation_projection);
match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) { match infcx.at(cause, param_env).eq(
DefineOpaqueTypes::No,
cache_projection,
obligation_projection,
) {
Ok(InferOk { value: _, obligations }) => { Ok(InferOk { value: _, obligations }) => {
nested_obligations.extend(obligations); nested_obligations.extend(obligations);
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations); assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);

View file

@ -197,23 +197,30 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
return Ok(*ty); return Ok(*ty);
} }
let (kind, data) = match *ty.kind() {
ty::Alias(kind, data) => (kind, data),
_ => {
let res = ty.try_super_fold_with(self)?;
self.cache.insert(ty, res);
return Ok(res);
}
};
// See note in `rustc_trait_selection::traits::project` about why we // See note in `rustc_trait_selection::traits::project` about why we
// wait to fold the substs. // wait to fold the substs.
// Wrap this in a closure so we don't accidentally return from the outer function // Wrap this in a closure so we don't accidentally return from the outer function
let res = match *ty.kind() { let res = match kind {
// This is really important. While we *can* handle this, this has // This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with // severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark. // late-bound regions. See `issue-88862` benchmark.
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) ty::Opaque if !data.substs.has_escaping_bound_vars() => {
if !substs.has_escaping_bound_vars() =>
{
// Only normalize `impl Trait` outside of type inference, usually in codegen. // Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() { match self.param_env.reveal() {
Reveal::UserFacing => ty.try_super_fold_with(self)?, Reveal::UserFacing => ty.try_super_fold_with(self)?,
Reveal::All => { Reveal::All => {
let substs = substs.try_fold_with(self)?; let substs = data.substs.try_fold_with(self)?;
let recursion_limit = self.interner().recursion_limit(); let recursion_limit = self.interner().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) { if !recursion_limit.value_within_limit(self.anon_depth) {
// A closure or generator may have itself as in its upvars. // A closure or generator may have itself as in its upvars.
@ -228,7 +235,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
return ty.try_super_fold_with(self); return ty.try_super_fold_with(self);
} }
let generic_ty = self.interner().type_of(def_id); let generic_ty = self.interner().type_of(data.def_id);
let concrete_ty = generic_ty.subst(self.interner(), substs); let concrete_ty = generic_ty.subst(self.interner(), substs);
self.anon_depth += 1; self.anon_depth += 1;
if concrete_ty == ty { if concrete_ty == ty {
@ -248,62 +255,22 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
} }
} }
ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => { ty::Opaque => ty.try_super_fold_with(self)?,
// This branch is just an optimization: when we don't have escaping bound vars,
// we don't need to replace them with placeholders (see branch below).
let tcx = self.infcx.tcx; ty::Projection => {
let data = data.try_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
// so we cannot canonicalize it.
let c_data = self
.infcx
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
let result = tcx.normalize_projection_ty(c_data)?;
// We don't expect ambiguity.
if result.is_ambiguous() {
// Rustdoc normalizes possibly not well-formed types, so only
// treat this as a bug if we're not in rustdoc.
if !tcx.sess.opts.actually_rustdoc {
tcx.sess.delay_span_bug(
DUMMY_SP,
format!("unexpected ambiguity: {:?} {:?}", c_data, result),
);
}
return Err(NoSolution);
}
let InferOk { value: result, obligations } =
self.infcx.instantiate_query_response_and_region_obligations(
self.cause,
self.param_env,
&orig_values,
result,
)?;
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
let res = result.normalized_ty;
// `tcx.normalize_projection_ty` may normalize to a type that still has
// unevaluated consts, so keep normalizing here if that's the case.
if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
res.try_super_fold_with(self)?
} else {
res
}
}
ty::Alias(ty::Projection, data) => {
// See note in `rustc_trait_selection::traits::project` // See note in `rustc_trait_selection::traits::project`
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
let infcx = self.infcx; let infcx = self.infcx;
let (data, mapped_regions, mapped_types, mapped_consts) = // Just an optimization: When we don't have escaping bound vars,
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); // we don't need to replace them with placeholders.
let (data, maps) = if data.has_escaping_bound_vars() {
let (data, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
(data, Some((mapped_regions, mapped_types, mapped_consts)))
} else {
(data, None)
};
let data = data.try_fold_with(self)?; let data = data.try_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default(); let mut orig_values = OriginalQueryValues::default();
@ -337,14 +304,18 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
debug!("QueryNormalizer: result = {:#?}", result); debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations); debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations); self.obligations.extend(obligations);
let res = PlaceholderReplacer::replace_placeholders( let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
infcx, PlaceholderReplacer::replace_placeholders(
mapped_regions, infcx,
mapped_types, mapped_regions,
mapped_consts, mapped_types,
&self.universes, mapped_consts,
result.normalized_ty, &self.universes,
); result.normalized_ty,
)
} else {
result.normalized_ty
};
// `tcx.normalize_projection_ty` may normalize to a type that still has // `tcx.normalize_projection_ty` may normalize to a type that still has
// unevaluated consts, so keep normalizing here if that's the case. // unevaluated consts, so keep normalizing here if that's the case.
if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
@ -353,8 +324,6 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
res res
} }
} }
_ => ty.try_super_fold_with(self)?,
}; };
self.cache.insert(ty, res); self.cache.insert(ty, res);

View file

@ -8,8 +8,8 @@
//! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate,
TraitRef, Ty, TyCtxt, TypeVisitableExt, TraitRef, Ty, TyCtxt, TypeVisitableExt,
@ -177,7 +177,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligations.extend(self.infcx.commit_if_ok(|_| { obligations.extend(self.infcx.commit_if_ok(|_| {
self.infcx self.infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.sup(placeholder_trait_predicate, candidate) .sup(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
.map(|InferOk { obligations, .. }| obligations) .map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented) .map_err(|_| Unimplemented)
})?); })?);
@ -462,7 +462,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested.extend(self.infcx.commit_if_ok(|_| { nested.extend(self.infcx.commit_if_ok(|_| {
self.infcx self.infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.sup(obligation_trait_ref, upcast_trait_ref) .sup(DefineOpaqueTypes::No, obligation_trait_ref, upcast_trait_ref)
.map(|InferOk { obligations, .. }| obligations) .map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented) .map_err(|_| Unimplemented)
})?); })?);
@ -827,11 +827,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) )
}); });
// needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
self.infcx self.infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
// needed for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs .sup(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
.define_opaque_types(true)
.sup(obligation_trait_ref, expected_trait_ref)
.map(|InferOk { mut obligations, .. }| { .map(|InferOk { mut obligations, .. }| {
obligations.extend(nested); obligations.extend(nested);
obligations obligations
@ -896,7 +895,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self let InferOk { obligations, .. } = self
.infcx .infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.sup(target, source_trait) .sup(DefineOpaqueTypes::No, target, source_trait)
.map_err(|_| Unimplemented)?; .map_err(|_| Unimplemented)?;
nested.extend(obligations); nested.extend(obligations);
@ -995,7 +994,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self let InferOk { obligations, .. } = self
.infcx .infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.sup(target, source_trait) .sup(DefineOpaqueTypes::No, target, source_trait)
.map_err(|_| Unimplemented)?; .map_err(|_| Unimplemented)?;
nested.extend(obligations); nested.extend(obligations);
@ -1066,7 +1065,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self let InferOk { obligations, .. } = self
.infcx .infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.eq(b, a) .eq(DefineOpaqueTypes::No, b, a)
.map_err(|_| Unimplemented)?; .map_err(|_| Unimplemented)?;
nested.extend(obligations); nested.extend(obligations);
} }
@ -1114,7 +1113,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self let InferOk { obligations, .. } = self
.infcx .infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.eq(target, new_struct) .eq(DefineOpaqueTypes::No, target, new_struct)
.map_err(|_| Unimplemented)?; .map_err(|_| Unimplemented)?;
nested.extend(obligations); nested.extend(obligations);
@ -1144,7 +1143,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self let InferOk { obligations, .. } = self
.infcx .infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.eq(target, new_tuple) .eq(DefineOpaqueTypes::No, target, new_tuple)
.map_err(|_| Unimplemented)?; .map_err(|_| Unimplemented)?;
nested.extend(obligations); nested.extend(obligations);

View file

@ -38,6 +38,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::Diagnostic; use rustc_errors::Diagnostic;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::traits::TraitEngine; use rustc_infer::traits::TraitEngine;
use rustc_infer::traits::TraitEngineExt; use rustc_infer::traits::TraitEngineExt;
@ -912,7 +913,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.infcx .infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.trace(c1, c2) .trace(c1, c2)
.eq(a.substs, b.substs) .eq(DefineOpaqueTypes::No, a.substs, b.substs)
{ {
let mut obligations = new_obligations.obligations; let mut obligations = new_obligations.obligations;
self.add_depth( self.add_depth(
@ -930,7 +931,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let Ok(new_obligations) = self if let Ok(new_obligations) = self
.infcx .infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.eq(c1, c2) .eq(DefineOpaqueTypes::No, c1, c2)
{ {
let mut obligations = new_obligations.obligations; let mut obligations = new_obligations.obligations;
self.add_depth( self.add_depth(
@ -964,8 +965,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match (evaluate(c1), evaluate(c2)) { match (evaluate(c1), evaluate(c2)) {
(Ok(c1), Ok(c2)) => { (Ok(c1), Ok(c2)) => {
match self.infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2) match self.infcx.at(&obligation.cause, obligation.param_env).eq(
{ DefineOpaqueTypes::No,
c1,
c2,
) {
Ok(inf_ok) => self.evaluate_predicates_recursively( Ok(inf_ok) => self.evaluate_predicates_recursively(
previous_stack, previous_stack,
inf_ok.into_obligations(), inf_ok.into_obligations(),
@ -993,7 +997,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
match self.infcx.at(&obligation.cause, obligation.param_env).eq(ct.ty(), ty) { match self.infcx.at(&obligation.cause, obligation.param_env).eq(
DefineOpaqueTypes::No,
ct.ty(),
ty,
) {
Ok(inf_ok) => self.evaluate_predicates_recursively( Ok(inf_ok) => self.evaluate_predicates_recursively(
previous_stack, previous_stack,
inf_ok.into_obligations(), inf_ok.into_obligations(),
@ -1751,7 +1759,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}); });
self.infcx self.infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) .sup(DefineOpaqueTypes::No, ty::Binder::dummy(placeholder_trait_ref), trait_bound)
.map(|InferOk { obligations: _, value: () }| { .map(|InferOk { obligations: _, value: () }| {
// This method is called within a probe, so we can't have // This method is called within a probe, so we can't have
// inference variables and placeholders escape. // inference variables and placeholders escape.
@ -1813,7 +1821,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let is_match = self let is_match = self
.infcx .infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.sup(obligation.predicate, infer_projection) .sup(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
.map_or(false, |InferOk { obligations, value: () }| { .map_or(false, |InferOk { obligations, value: () }| {
self.evaluate_predicates_recursively( self.evaluate_predicates_recursively(
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
@ -2534,7 +2542,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
let InferOk { obligations, .. } = self let InferOk { obligations, .. } = self
.infcx .infcx
.at(&cause, obligation.param_env) .at(&cause, obligation.param_env)
.eq(placeholder_obligation_trait_ref, impl_trait_ref) .eq(DefineOpaqueTypes::No, placeholder_obligation_trait_ref, impl_trait_ref)
.map_err(|e| { .map_err(|e| {
debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx())) debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx()))
})?; })?;
@ -2584,7 +2592,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
) -> Result<Vec<PredicateObligation<'tcx>>, ()> { ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
self.infcx self.infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) .sup(DefineOpaqueTypes::No, obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
.map(|InferOk { obligations, .. }| obligations) .map(|InferOk { obligations, .. }| obligations)
.map_err(|_| ()) .map_err(|_| ())
} }

View file

@ -10,6 +10,7 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
pub mod specialization_graph; pub mod specialization_graph;
use rustc_infer::infer::DefineOpaqueTypes;
use specialization_graph::GraphExt; use specialization_graph::GraphExt;
use crate::errors::NegativePositiveConflict; use crate::errors::NegativePositiveConflict;
@ -193,7 +194,7 @@ fn fulfill_implication<'tcx>(
// do the impls unify? If not, no specialization. // do the impls unify? If not, no specialization.
let Ok(InferOk { obligations: more_obligations, .. }) = let Ok(InferOk { obligations: more_obligations, .. }) =
infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait, target_trait) infcx.at(&ObligationCause::dummy(), param_env, ).eq(DefineOpaqueTypes::No,source_trait, target_trait)
else { else {
debug!( debug!(
"fulfill_implication: {:?} does not unify with {:?}", "fulfill_implication: {:?} does not unify with {:?}",

View file

@ -1,15 +1,14 @@
use super::NormalizeExt;
use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Diagnostic; use rustc_errors::Diagnostic;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::InferOk;
use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{GenericArg, SubstsRef};
use rustc_span::Span; use rustc_span::Span;
use smallvec::SmallVec; use smallvec::SmallVec;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{GenericArg, SubstsRef};
use super::NormalizeExt;
use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext};
use rustc_infer::infer::InferOk;
pub use rustc_infer::traits::{self, util::*}; pub use rustc_infer::traits::{self, util::*};
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -201,6 +200,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) { ) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
let subject = selcx.tcx().bound_impl_subject(impl_def_id); let subject = selcx.tcx().bound_impl_subject(impl_def_id);
let subject = subject.subst(selcx.tcx(), impl_substs); let subject = subject.subst(selcx.tcx(), impl_substs);
let InferOk { value: subject, obligations: normalization_obligations1 } = let InferOk { value: subject, obligations: normalization_obligations1 } =
selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(subject); selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(subject);

View file

@ -1738,11 +1738,11 @@ impl<T: ?Sized + PartialEq> PartialEq for Rc<T> {
/// Inequality for two `Rc`s. /// Inequality for two `Rc`s.
/// ///
/// Two `Rc`s are unequal if their inner values are unequal. /// Two `Rc`s are not equal if their inner values are not equal.
/// ///
/// If `T` also implements `Eq` (implying reflexivity of equality), /// If `T` also implements `Eq` (implying reflexivity of equality),
/// two `Rc`s that point to the same allocation are /// two `Rc`s that point to the same allocation are
/// never unequal. /// always equal.
/// ///
/// # Examples /// # Examples
/// ///

View file

@ -2475,10 +2475,10 @@ impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
/// Inequality for two `Arc`s. /// Inequality for two `Arc`s.
/// ///
/// Two `Arc`s are unequal if their inner values are unequal. /// Two `Arc`s are not equal if their inner values are not equal.
/// ///
/// If `T` also implements `Eq` (implying reflexivity of equality), /// If `T` also implements `Eq` (implying reflexivity of equality),
/// two `Arc`s that point to the same value are never unequal. /// two `Arc`s that point to the same value are always equal.
/// ///
/// # Examples /// # Examples
/// ///

View file

@ -158,7 +158,7 @@ mod sip;
/// ///
/// Implementations of `hash` should ensure that the data they /// Implementations of `hash` should ensure that the data they
/// pass to the `Hasher` are prefix-free. That is, /// pass to the `Hasher` are prefix-free. That is,
/// unequal values should cause two different sequences of values to be written, /// values which are not equal should cause two different sequences of values to be written,
/// and neither of the two sequences should be a prefix of the other. /// and neither of the two sequences should be a prefix of the other.
/// ///
/// For example, the standard implementation of [`Hash` for `&str`][impl] passes an extra /// For example, the standard implementation of [`Hash` for `&str`][impl] passes an extra

View file

@ -3721,7 +3721,7 @@ pub trait Iterator {
} }
} }
/// Determines if the elements of this [`Iterator`] are unequal to those of /// Determines if the elements of this [`Iterator`] are not equal to those of
/// another. /// another.
/// ///
/// # Examples /// # Examples

View file

@ -1110,7 +1110,7 @@ impl<T: Copy> Copy for (T,) {
/// - [NaN (not a number)](#associatedconstant.NAN): this value results from /// - [NaN (not a number)](#associatedconstant.NAN): this value results from
/// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected /// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
/// behavior: /// behavior:
/// - It is unequal to any float, including itself! This is the reason `f32` /// - It is not equal to any float, including itself! This is the reason `f32`
/// doesn't implement the `Eq` trait. /// doesn't implement the `Eq` trait.
/// - It is also neither smaller nor greater than any float, making it /// - It is also neither smaller nor greater than any float, making it
/// impossible to sort by the default comparison operation, which is the /// impossible to sort by the default comparison operation, which is the

View file

@ -1110,7 +1110,7 @@ impl<T: Copy> Copy for (T,) {
/// - [NaN (not a number)](#associatedconstant.NAN): this value results from /// - [NaN (not a number)](#associatedconstant.NAN): this value results from
/// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected /// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
/// behavior: /// behavior:
/// - It is unequal to any float, including itself! This is the reason `f32` /// - It is not equal to any float, including itself! This is the reason `f32`
/// doesn't implement the `Eq` trait. /// doesn't implement the `Eq` trait.
/// - It is also neither smaller nor greater than any float, making it /// - It is also neither smaller nor greater than any float, making it
/// impossible to sort by the default comparison operation, which is the /// impossible to sort by the default comparison operation, which is the

View file

@ -35,7 +35,7 @@ use crate::sys::locks as sys;
/// `owner` can be checked by other threads that want to see if they already /// `owner` can be checked by other threads that want to see if they already
/// hold the lock, so needs to be atomic. If it compares equal, we're on the /// hold the lock, so needs to be atomic. If it compares equal, we're on the
/// same thread that holds the mutex and memory access can use relaxed ordering /// same thread that holds the mutex and memory access can use relaxed ordering
/// since we're not dealing with multiple threads. If it compares unequal, /// since we're not dealing with multiple threads. If it's not equal,
/// synchronization is left to the mutex, making relaxed memory ordering for /// synchronization is left to the mutex, making relaxed memory ordering for
/// the `owner` field fine in all cases. /// the `owner` field fine in all cases.
pub struct ReentrantMutex<T> { pub struct ReentrantMutex<T> {

View file

@ -20,15 +20,13 @@ smallvec = "1.8.1"
tempfile = "3" tempfile = "3"
tracing = "0.1" tracing = "0.1"
tracing-tree = "0.2.0" tracing-tree = "0.2.0"
threadpool = "1.8.1"
[dependencies.tracing-subscriber] [dependencies.tracing-subscriber]
version = "0.3.3" version = "0.3.3"
default-features = false default-features = false
features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"]
[target.'cfg(windows)'.dependencies]
rayon = "1.5.1"
[dev-dependencies] [dev-dependencies]
expect-test = "1.4.0" expect-test = "1.4.0"

View file

@ -1,6 +1,6 @@
use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_infer::infer::{InferOk, TyCtxtInferExt}; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
use rustc_infer::traits; use rustc_infer::traits;
use rustc_middle::ty::ToPredicate; use rustc_middle::ty::ToPredicate;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
@ -47,8 +47,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
// Require the type the impl is implemented on to match // Require the type the impl is implemented on to match
// our type, and ignore the impl if there was a mismatch. // our type, and ignore the impl if there was a mismatch.
let cause = traits::ObligationCause::dummy(); let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, impl_trait_ref.self_ty(), impl_ty) else {
let Ok(eq_result) = infcx.at(&cause, param_env).eq(impl_trait_ref.self_ty(), impl_ty) else {
continue continue
}; };
let InferOk { value: (), obligations } = eq_result; let InferOk { value: (), obligations } = eq_result;

View file

@ -2,18 +2,20 @@
//! //!
//! On Windows this indirects IO into threads to work around performance issues //! On Windows this indirects IO into threads to work around performance issues
//! with Defender (and other similar virus scanners that do blocking operations). //! with Defender (and other similar virus scanners that do blocking operations).
//! On other platforms this is a thin shim to fs.
//! //!
//! Only calls needed to permit this workaround have been abstracted: thus //! Only calls needed to permit this workaround have been abstracted: thus
//! fs::read is still done directly via the fs module; if in future rustdoc //! fs::read is still done directly via the fs module; if in future rustdoc
//! needs to read-after-write from a file, then it would be added to this //! needs to read-after-write from a file, then it would be added to this
//! abstraction. //! abstraction.
use std::cmp::max;
use std::fs; use std::fs;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::string::ToString; use std::string::ToString;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use std::thread::available_parallelism;
use threadpool::ThreadPool;
pub(crate) trait PathError { pub(crate) trait PathError {
fn new<S, P: AsRef<Path>>(e: S, path: P) -> Self fn new<S, P: AsRef<Path>>(e: S, path: P) -> Self
@ -24,11 +26,21 @@ pub(crate) trait PathError {
pub(crate) struct DocFS { pub(crate) struct DocFS {
sync_only: bool, sync_only: bool,
errors: Option<Sender<String>>, errors: Option<Sender<String>>,
pool: ThreadPool,
} }
impl DocFS { impl DocFS {
pub(crate) fn new(errors: Sender<String>) -> DocFS { pub(crate) fn new(errors: Sender<String>) -> DocFS {
DocFS { sync_only: false, errors: Some(errors) } const MINIMUM_NB_THREADS: usize = 2;
DocFS {
sync_only: false,
errors: Some(errors),
pool: ThreadPool::new(
available_parallelism()
.map(|nb| max(nb.get(), MINIMUM_NB_THREADS))
.unwrap_or(MINIMUM_NB_THREADS),
),
}
} }
pub(crate) fn set_sync_only(&mut self, sync_only: bool) { pub(crate) fn set_sync_only(&mut self, sync_only: bool) {
@ -54,12 +66,11 @@ impl DocFS {
where where
E: PathError, E: PathError,
{ {
#[cfg(windows)]
if !self.sync_only { if !self.sync_only {
// A possible future enhancement after more detailed profiling would // A possible future enhancement after more detailed profiling would
// be to create the file sync so errors are reported eagerly. // be to create the file sync so errors are reported eagerly.
let sender = self.errors.clone().expect("can't write after closing"); let sender = self.errors.clone().expect("can't write after closing");
rayon::spawn(move || { self.pool.execute(move || {
fs::write(&path, contents).unwrap_or_else(|e| { fs::write(&path, contents).unwrap_or_else(|e| {
sender.send(format!("\"{}\": {}", path.display(), e)).unwrap_or_else(|_| { sender.send(format!("\"{}\": {}", path.display(), e)).unwrap_or_else(|_| {
panic!("failed to send error on \"{}\"", path.display()) panic!("failed to send error on \"{}\"", path.display())
@ -70,9 +81,12 @@ impl DocFS {
fs::write(&path, contents).map_err(|e| E::new(e, path))?; fs::write(&path, contents).map_err(|e| E::new(e, path))?;
} }
#[cfg(not(windows))]
fs::write(&path, contents).map_err(|e| E::new(e, path))?;
Ok(()) Ok(())
} }
} }
impl Drop for DocFS {
fn drop(&mut self) {
self.pool.join();
}
}

View file

@ -771,6 +771,12 @@ pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Cont
.or_else(|| cache.external_paths.get(&did)) .or_else(|| cache.external_paths.get(&did))
else { return String::new() }; else { return String::new() };
let mut buf = Buffer::new(); let mut buf = Buffer::new();
let fqp = if *shortty == ItemType::Primitive {
// primitives are documented in a crate, but not actually part of it
&fqp[fqp.len() - 1..]
} else {
&fqp
};
if let &Some(UrlFragment::Item(id)) = fragment { if let &Some(UrlFragment::Item(id)) = fragment {
write!(buf, "{} ", cx.tcx().def_descr(id)); write!(buf, "{} ", cx.tcx().def_descr(id));
for component in fqp { for component in fqp {

View file

@ -486,7 +486,7 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>(
} }
// First, check if it's "Self". // First, check if it's "Self".
let arg = if let Some(self_) = self_ { let mut arg = if let Some(self_) = self_ {
match &*arg { match &*arg {
Type::BorrowedRef { type_, .. } if type_.is_self_type() => self_, Type::BorrowedRef { type_, .. } if type_.is_self_type() => self_,
type_ if type_.is_self_type() => self_, type_ if type_.is_self_type() => self_,
@ -496,11 +496,16 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>(
arg arg
}; };
// strip references from the argument type
while let Type::BorrowedRef { type_, .. } = &*arg {
arg = &*type_;
}
// If this argument is a type parameter and not a trait bound or a type, we need to look // If this argument is a type parameter and not a trait bound or a type, we need to look
// for its bounds. // for its bounds.
if let Type::Generic(arg_s) = *arg { if let Type::Generic(arg_s) = *arg {
// First we check if the bounds are in a `where` predicate... // First we check if the bounds are in a `where` predicate...
if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g { for where_pred in generics.where_predicates.iter().filter(|g| match g {
WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s, WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s,
_ => false, _ => false,
}) { }) {

View file

@ -1,7 +1,18 @@
const QUERY = 'option, fnonce -> option'; const QUERY = [
'option, fnonce -> option',
'option -> default',
];
const EXPECTED = { const EXPECTED = [
'others': [ {
{ 'path': 'std::option::Option', 'name': 'map' }, 'others': [
], { 'path': 'std::option::Option', 'name': 'map' },
}; ],
},
{
'others': [
{ 'path': 'std::option::Option', 'name': 'unwrap_or_default' },
{ 'path': 'std::option::Option', 'name': 'get_or_insert_default' },
],
},
];

View file

@ -1,4 +1,4 @@
const QUERY = ['trait<nested>', '-> trait<nested>', 't1, t2']; const QUERY = ['trait<nested>', '-> trait<nested>', 't1, t2', '-> shazam', 'drizzel -> shazam'];
const EXPECTED = [ const EXPECTED = [
{ {
@ -16,4 +16,15 @@ const EXPECTED = [
{ 'path': 'where_clause', 'name': 'presto' }, { 'path': 'where_clause', 'name': 'presto' },
], ],
}, },
{
'others': [
{ 'path': 'where_clause', 'name': 'bippety' },
{ 'path': 'where_clause::Drizzel', 'name': 'boppety' },
],
},
{
'others': [
{ 'path': 'where_clause::Drizzel', 'name': 'boppety' },
],
},
]; ];

View file

@ -14,3 +14,17 @@ pub trait T2<'a, T> {
} }
pub fn presto<A, B>(_: A, _: B) where A: T1, B: for <'b> T2<'b, Nested> {} pub fn presto<A, B>(_: A, _: B) where A: T1, B: for <'b> T2<'b, Nested> {}
pub trait Shazam {}
pub fn bippety<X>() -> &'static X where X: Shazam {
panic!()
}
pub struct Drizzel<T>(T);
impl<T> Drizzel<T> {
pub fn boppety(&self) -> &T where T: Shazam {
panic!();
}
}

View file

@ -2,6 +2,8 @@
// @has prim_methods/index.html // @has prim_methods/index.html
// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char' // @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]/@title' 'primitive char'
// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8' // @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]/@title' 'method char::len_utf8'
//! A [`char`] and its [`char::len_utf8`]. //! A [`char`] and its [`char::len_utf8`].

View file

@ -35,6 +35,10 @@ note: the lint level is defined here
| |
LL | #![warn(unused_must_use)] LL | #![warn(unused_must_use)]
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = MustUseDeprecated::new();
| +++++++
warning: 5 warnings emitted warning: 5 warnings emitted

View file

@ -5,7 +5,7 @@ LL | FooB { x: i32, y: i32 }
| ----------------------- `FooB` defined here | ----------------------- `FooB` defined here
... ...
LL | FooB(a, b) => println!("{} {}", a, b), LL | FooB(a, b) => println!("{} {}", a, b),
| ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }` | ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: b }`
error: aborting due to previous error error: aborting due to previous error

View file

@ -10,12 +10,21 @@ note: the lint level is defined here
| |
LL | #![warn(unused_must_use)] LL | #![warn(unused_must_use)]
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = need_to_use_this_value();
| +++++++
warning: unused return value of `MyStruct::need_to_use_this_method_value` that must be used warning: unused return value of `MyStruct::need_to_use_this_method_value` that must be used
--> $DIR/fn_must_use.rs:60:5 --> $DIR/fn_must_use.rs:60:5
| |
LL | m.need_to_use_this_method_value(); LL | m.need_to_use_this_method_value();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = m.need_to_use_this_method_value();
| +++++++
warning: unused return value of `EvenNature::is_even` that must be used warning: unused return value of `EvenNature::is_even` that must be used
--> $DIR/fn_must_use.rs:61:5 --> $DIR/fn_must_use.rs:61:5
@ -24,24 +33,43 @@ LL | m.is_even(); // trait method!
| ^^^^^^^^^^^ | ^^^^^^^^^^^
| |
= note: no side effects = note: no side effects
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = m.is_even(); // trait method!
| +++++++
warning: unused return value of `MyStruct::need_to_use_this_associated_function_value` that must be used warning: unused return value of `MyStruct::need_to_use_this_associated_function_value` that must be used
--> $DIR/fn_must_use.rs:64:5 --> $DIR/fn_must_use.rs:64:5
| |
LL | MyStruct::need_to_use_this_associated_function_value(); LL | MyStruct::need_to_use_this_associated_function_value();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = MyStruct::need_to_use_this_associated_function_value();
| +++++++
warning: unused return value of `std::cmp::PartialEq::eq` that must be used warning: unused return value of `std::cmp::PartialEq::eq` that must be used
--> $DIR/fn_must_use.rs:70:5 --> $DIR/fn_must_use.rs:70:5
| |
LL | 2.eq(&3); LL | 2.eq(&3);
| ^^^^^^^^ | ^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = 2.eq(&3);
| +++++++
warning: unused return value of `std::cmp::PartialEq::eq` that must be used warning: unused return value of `std::cmp::PartialEq::eq` that must be used
--> $DIR/fn_must_use.rs:71:5 --> $DIR/fn_must_use.rs:71:5
| |
LL | m.eq(&n); LL | m.eq(&n);
| ^^^^^^^^ | ^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = m.eq(&n);
| +++++++
warning: unused comparison that must be used warning: unused comparison that must be used
--> $DIR/fn_must_use.rs:74:5 --> $DIR/fn_must_use.rs:74:5

View file

@ -10,6 +10,10 @@ note: the lint level is defined here
| |
LL | #![warn(unused_must_use)] LL | #![warn(unused_must_use)]
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = Box::from_raw(ptr);
| +++++++
warning: 1 warning emitted warning: 1 warning emitted

View file

@ -9,12 +9,21 @@ note: the lint level is defined here
| |
LL | #![deny(unused_must_use)] LL | #![deny(unused_must_use)]
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo();
| +++++++
error: unused return value of `bar` that must be used error: unused return value of `bar` that must be used
--> $DIR/must_use-unit.rs:15:5 --> $DIR/must_use-unit.rs:15:5
| |
LL | bar(); LL | bar();
| ^^^^^ | ^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = bar();
| +++++++
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -16,12 +16,22 @@ error: unused return value of `foo` that must be used
| |
LL | foo(); LL | foo();
| ^^^^^ | ^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo();
| +++++++
error: unused output of future returned by `foo` that must be used error: unused output of future returned by `foo` that must be used
--> $DIR/unused-async.rs:33:5 --> $DIR/unused-async.rs:33:5
| |
LL | foo().await; LL | foo().await;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo().await;
| +++++++
error: unused implementer of `Future` that must be used error: unused implementer of `Future` that must be used
--> $DIR/unused-async.rs:34:5 --> $DIR/unused-async.rs:34:5
@ -36,12 +46,22 @@ error: unused return value of `bar` that must be used
| |
LL | bar(); LL | bar();
| ^^^^^ | ^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = bar();
| +++++++
error: unused output of future returned by `bar` that must be used error: unused output of future returned by `bar` that must be used
--> $DIR/unused-async.rs:36:5 --> $DIR/unused-async.rs:36:5
| |
LL | bar().await; LL | bar().await;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = bar().await;
| +++++++
error: unused implementer of `Future` that must be used error: unused implementer of `Future` that must be used
--> $DIR/unused-async.rs:37:5 --> $DIR/unused-async.rs:37:5

View file

@ -9,6 +9,10 @@ note: the lint level is defined here
| |
LL | #![deny(unused_results, unused_must_use)] LL | #![deny(unused_results, unused_must_use)]
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo::<MustUse>();
| +++++++
error: unused `MustUseMsg` that must be used error: unused `MustUseMsg` that must be used
--> $DIR/unused-result.rs:22:5 --> $DIR/unused-result.rs:22:5
@ -17,6 +21,10 @@ LL | foo::<MustUseMsg>();
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^
| |
= note: some message = note: some message
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo::<MustUseMsg>();
| +++++++
error: unused result of type `isize` error: unused result of type `isize`
--> $DIR/unused-result.rs:34:5 --> $DIR/unused-result.rs:34:5
@ -35,6 +43,11 @@ error: unused `MustUse` that must be used
| |
LL | foo::<MustUse>(); LL | foo::<MustUse>();
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo::<MustUse>();
| +++++++
error: unused `MustUseMsg` that must be used error: unused `MustUseMsg` that must be used
--> $DIR/unused-result.rs:36:5 --> $DIR/unused-result.rs:36:5
@ -43,6 +56,10 @@ LL | foo::<MustUseMsg>();
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^
| |
= note: some message = note: some message
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo::<MustUseMsg>();
| +++++++
error: aborting due to 5 previous errors error: aborting due to 5 previous errors

View file

@ -146,42 +146,76 @@ note: the lint level is defined here
| |
LL | #![deny(unused_attributes, unused_must_use)] LL | #![deny(unused_attributes, unused_must_use)]
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = X;
| +++++++
error: unused `Y` that must be used error: unused `Y` that must be used
--> $DIR/unused_attributes-must_use.rs:104:5 --> $DIR/unused_attributes-must_use.rs:104:5
| |
LL | Y::Z; LL | Y::Z;
| ^^^^ | ^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = Y::Z;
| +++++++
error: unused `U` that must be used error: unused `U` that must be used
--> $DIR/unused_attributes-must_use.rs:105:5 --> $DIR/unused_attributes-must_use.rs:105:5
| |
LL | U { unit: () }; LL | U { unit: () };
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = U { unit: () };
| +++++++
error: unused return value of `U::method` that must be used error: unused return value of `U::method` that must be used
--> $DIR/unused_attributes-must_use.rs:106:5 --> $DIR/unused_attributes-must_use.rs:106:5
| |
LL | U::method(); LL | U::method();
| ^^^^^^^^^^^ | ^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = U::method();
| +++++++
error: unused return value of `foo` that must be used error: unused return value of `foo` that must be used
--> $DIR/unused_attributes-must_use.rs:107:5 --> $DIR/unused_attributes-must_use.rs:107:5
| |
LL | foo(); LL | foo();
| ^^^^^ | ^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo();
| +++++++
error: unused return value of `foreign_foo` that must be used error: unused return value of `foreign_foo` that must be used
--> $DIR/unused_attributes-must_use.rs:110:9 --> $DIR/unused_attributes-must_use.rs:110:9
| |
LL | foreign_foo(); LL | foreign_foo();
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foreign_foo();
| +++++++
error: unused return value of `Use::get_four` that must be used error: unused return value of `Use::get_four` that must be used
--> $DIR/unused_attributes-must_use.rs:118:5 --> $DIR/unused_attributes-must_use.rs:118:5
| |
LL | ().get_four(); LL | ().get_four();
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = ().get_four();
| +++++++
error: aborting due to 28 previous errors error: aborting due to 28 previous errors

View file

@ -0,0 +1,44 @@
// run-rustfix
#![allow(unused)]
use Foo::{FooB, FooA};
enum Foo {
FooA { opt_x: Option<i32>, y: i32 },
FooB { x: i32, y: i32 }
}
fn main() {
let f = FooB { x: 3, y: 4 };
match f {
FooB { x: a, y: b } => println!("{} {}", a, b),
//~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
_ => (),
}
match f {
FooB { x, y } => println!("{} {}", x, y),
//~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
_ => (),
}
match f {
FooA { opt_x: Some(x), y } => println!("{} {}", x, y),
//~^ ERROR expected tuple struct or tuple variant, found variant `FooA`
_ => (),
}
match f {
FooB { x: a, y: _ } => println!("{}", a),
//~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
_ => (),
}
match f {
FooB { x, y } => (),
//~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
_ => (),
}
}

View file

@ -0,0 +1,44 @@
// run-rustfix
#![allow(unused)]
use Foo::{FooB, FooA};
enum Foo {
FooA { opt_x: Option<i32>, y: i32 },
FooB { x: i32, y: i32 }
}
fn main() {
let f = FooB { x: 3, y: 4 };
match f {
FooB(a, b) => println!("{} {}", a, b),
//~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
_ => (),
}
match f {
FooB(x, y) => println!("{} {}", x, y),
//~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
_ => (),
}
match f {
FooA(Some(x), y) => println!("{} {}", x, y),
//~^ ERROR expected tuple struct or tuple variant, found variant `FooA`
_ => (),
}
match f {
FooB(a, _, _) => println!("{}", a),
//~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
_ => (),
}
match f {
FooB() => (),
//~^ ERROR expected tuple struct or tuple variant, found variant `FooB`
_ => (),
}
}

View file

@ -0,0 +1,48 @@
error[E0532]: expected tuple struct or tuple variant, found variant `FooB`
--> $DIR/issue-106862.rs:16:9
|
LL | FooB { x: i32, y: i32 }
| ----------------------- `FooB` defined here
...
LL | FooB(a, b) => println!("{} {}", a, b),
| ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: b }`
error[E0532]: expected tuple struct or tuple variant, found variant `FooB`
--> $DIR/issue-106862.rs:22:9
|
LL | FooB { x: i32, y: i32 }
| ----------------------- `FooB` defined here
...
LL | FooB(x, y) => println!("{} {}", x, y),
| ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }`
error[E0532]: expected tuple struct or tuple variant, found variant `FooA`
--> $DIR/issue-106862.rs:28:9
|
LL | FooA { opt_x: Option<i32>, y: i32 },
| ----------------------------------- `FooA` defined here
...
LL | FooA(Some(x), y) => println!("{} {}", x, y),
| ^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FooA { opt_x: Some(x), y }`
error[E0532]: expected tuple struct or tuple variant, found variant `FooB`
--> $DIR/issue-106862.rs:34:9
|
LL | FooB { x: i32, y: i32 }
| ----------------------- `FooB` defined here
...
LL | FooB(a, _, _) => println!("{}", a),
| ^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: _ }`
error[E0532]: expected tuple struct or tuple variant, found variant `FooB`
--> $DIR/issue-106862.rs:40:9
|
LL | FooB { x: i32, y: i32 }
| ----------------------- `FooB` defined here
...
LL | FooB() => (),
| ^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }`
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0532`.