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",
"minifier",
"once_cell",
"rayon",
"regex",
"rustdoc-json-types",
"serde",
"serde_json",
"smallvec",
"tempfile",
"threadpool",
"tracing",
"tracing-subscriber",
"tracing-tree",
@ -6209,6 +6209,15 @@ dependencies = [
"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]]
name = "tidy"
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/)
- [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 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/),
`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).
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
// 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
// locations.
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);
match (A, B, C) {
(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
/// 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
/// `y`; otherwise, we can't transcribe them both at the given depth.
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::ItemKind;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::{self, RegionResolutionError};
use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
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::*;
match (source.kind(), target.kind()) {
(&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 => (),
(&Adt(def_a, substs_a), &Adt(def_b, substs_b))
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() {
create_err(
"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
// expressions in the course of execution.)
// 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() {
return None;
}

View File

@ -102,7 +102,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_hir as hir;
use rustc_hir::Node;
use rustc_infer::infer::{InferOk, TyCtxtInferExt};
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
use rustc_macros::fluent_messages;
use rustc_middle::middle;
use rustc_middle::ty::query::Providers;
@ -165,7 +165,7 @@ fn require_same_types<'tcx>(
) -> bool {
let infcx = &tcx.infer_ctxt().build();
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),
Err(err) => {
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_analysis::astconv::AstConv;
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_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::ty::subst::InternalSubsts;
@ -563,10 +563,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
// Check that E' = S'.
let cause = self.misc(hir_ty.span);
let InferOk { value: (), obligations } = self
.at(&cause, self.param_env)
.define_opaque_types(true)
.eq(*expected_ty, supplied_ty)?;
let InferOk { value: (), obligations } = self.at(&cause, self.param_env).eq(
DefineOpaqueTypes::Yes,
*expected_ty,
supplied_ty,
)?;
all_obligations.extend(obligations);
}
@ -576,10 +577,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
supplied_sig.output(),
);
let cause = &self.misc(decl.output.span());
let InferOk { value: (), obligations } = self
.at(cause, self.param_env)
.define_opaque_types(true)
.eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
let InferOk { value: (), obligations } = self.at(cause, self.param_env).eq(
DefineOpaqueTypes::Yes,
expected_sigs.liberated_sig.output(),
supplied_output_ty,
)?;
all_obligations.extend(obligations);
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_analysis::astconv::AstConv;
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_middle::lint::in_external_macro;
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>> {
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
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 {
at.lub(b, a)
at.lub(DefineOpaqueTypes::Yes, b, a)
} else {
at.sup(b, a)
at.sup(DefineOpaqueTypes::Yes, b, a)
.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
// due to `[type error]` and `_` not coercing together.
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![]);
}
@ -1101,9 +1101,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(ty::FnDef(..), ty::FnDef(..)) => {
// Don't reify if the function types have a LUB, i.e., they
// are the same function and their parameters have a LUB.
match self
.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
{
match self.commit_if_ok(|_| {
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.
Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)),
Err(_) => {
@ -1153,7 +1157,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let sig = self
.at(cause, self.param_env)
.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))?;
// Reify both sides and return the reified fn pointer type.
@ -1237,7 +1241,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
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));
}
}
@ -1248,8 +1254,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(e) = first_error {
Err(e)
} else {
self.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
.map(|ok| self.register_infer_ok_obligations(ok))
self.commit_if_ok(|_| {
self.at(cause, self.param_env).lub(DefineOpaqueTypes::No, prev_ty, new_ty)
})
.map(|ok| self.register_infer_ok_obligations(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");
fcx.at(cause, fcx.param_env)
// needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
.define_opaque_types(true)
.eq_exp(label_expression_as_expected, expression_ty, self.merged_ty())
.eq_exp(
DefineOpaqueTypes::Yes,
label_expression_as_expected,
expression_ty,
self.merged_ty(),
)
.map(|infer_ok| {
fcx.register_infer_ok_obligations(infer_ok);
expression_ty

View File

@ -8,7 +8,7 @@ use rustc_hir::def::CtorKind;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
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::middle::stability::EvalResult;
use rustc_middle::ty::adjustment::AllowTwoPhase;
@ -113,7 +113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> 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: () }) => {
self.register_predicates(obligations);
None
@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> 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: () }) => {
self.register_predicates(obligations);
None

View File

@ -36,6 +36,7 @@ use rustc_hir_analysis::astconv::AstConv as _;
use rustc_hir_analysis::check::ty_kind_suggestion;
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::InferOk;
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability;
@ -1683,7 +1684,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(_) = remaining_fields.remove(&ident) {
let target_ty = self.field_ty(base_expr.span, f, substs);
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: () }) => {
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::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::error::TypeError;
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 ok = self
.at(&self.misc(span), self.param_env)
.eq(interior, witness)
.eq(DefineOpaqueTypes::No, interior, witness)
.expect("Failed to unify generator interior type");
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.
let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).subst(tcx, substs));
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),
Err(_) => {
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_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk;
use rustc_infer::infer::TypeTrace;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::visit::TypeVisitableExt;
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
// and register any such obligations for future type checks
let supertype_error = self
.at(&self.misc(provided_arg.span), self.param_env)
.sup(formal_input_ty, coerced_ty);
let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup(
DefineOpaqueTypes::No,
formal_input_ty,
coerced_ty,
);
let subtyping_error = match supertype_error {
Ok(InferOk { obligations, value: () }) => {
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.
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,

View File

@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, Visitor};
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::ty::fold::FnMutDelegate;
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
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),
_ => 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,
};
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::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
@ -478,7 +478,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
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: () }) => {
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_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_middle::middle::stability;
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 self
.at(&ObligationCause::dummy(), self.param_env)
.sup(fty.inputs()[0], self_ty)
.sup(DefineOpaqueTypes::No, fty.inputs()[0], self_ty)
.is_err()
{
return false;
@ -1436,9 +1437,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
CandidateSource::Trait(candidate.item.container_id(self.tcx))
}
TraitCandidate(trait_ref) => self.probe(|_| {
let _ = self
.at(&ObligationCause::dummy(), self.param_env)
.sup(candidate.xform_self_ty, self_ty);
let _ = self.at(&ObligationCause::dummy(), self.param_env).sup(
DefineOpaqueTypes::No,
candidate.xform_self_ty,
self_ty,
);
match self.select_trait_candidate(trait_ref) {
Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
// If only a single impl matches, make the error message point
@ -1465,10 +1468,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.probe(|_| {
// First check that the self type can be related.
let sub_obligations = match self
.at(&ObligationCause::dummy(), self.param_env)
.sup(probe.xform_self_ty, self_ty)
{
let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env).sup(
DefineOpaqueTypes::No,
probe.xform_self_ty,
self_ty,
) {
Ok(InferOk { obligations, value: () }) => obligations,
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
@ -1683,7 +1687,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if let ProbeResult::Match = result
&& self
.at(&ObligationCause::dummy(), self.param_env)
.sup(return_ty, xform_ret_ty)
.sup(DefineOpaqueTypes::No, return_ty, xform_ret_ty)
.is_err()
{
result = ProbeResult::BadReturnType;

View File

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

View File

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

View File

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

View File

@ -1,3 +1,4 @@
use crate::infer::DefineOpaqueTypes;
use crate::traits::PredicateObligations;
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, .. }))
if self.fields.define_opaque_types && def_id.is_local() =>
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
&& def_id.is_local() =>
{
self.fields.obligations.extend(
infcx

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
use super::combine::{CombineFields, RelationDir};
use super::{ObligationEmittingRelation, SubregionOrigin};
use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin};
use crate::traits::{Obligation, PredicateObligations};
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
@ -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, .. }))
if self.fields.define_opaque_types && def_id.is_local() =>
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
&& def_id.is_local() =>
{
self.fields.obligations.extend(
infcx

View File

@ -1390,7 +1390,7 @@ pub struct UnusedOp<'a> {
pub op: &'a str,
#[label]
pub label: Span,
#[suggestion(style = "verbose", code = "let _ = ", applicability = "machine-applicable")]
#[suggestion(style = "verbose", code = "let _ = ", applicability = "maybe-incorrect")]
pub suggestion: Span,
}
@ -1434,17 +1434,15 @@ pub struct UnusedDef<'a, 'b> {
}
#[derive(Subdiagnostic)]
pub enum UnusedDefSuggestion {
#[suggestion(
lint_suggestion,
style = "verbose",
code = "let _ = ",
applicability = "machine-applicable"
)]
Default {
#[primary_span]
span: Span,
},
#[suggestion(
lint_suggestion,
style = "verbose",
code = "let _ = ",
applicability = "maybe-incorrect"
)]
pub struct UnusedDefSuggestion {
#[primary_span]
pub span: Span,
}
// 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 type_lint_emitted_or_suppressed = match must_use_result {
Some(path) => {
emit_must_use_untranslated(cx, &path, "", "", 1);
emit_must_use_untranslated(cx, &path, "", "", 1, false);
true
}
None => false,
@ -358,6 +358,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_pre_path,
descr_post_path,
1,
false,
)
})
.is_some()
@ -370,6 +371,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_pre: &str,
descr_post: &str,
plural_len: usize,
is_inner: bool,
) {
let plural_suffix = pluralize!(plural_len);
@ -377,20 +379,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
MustUsePath::Suppressed => {}
MustUsePath::Boxed(path) => {
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) => {
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) => {
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) => {
for (index, path) in elems {
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) => {
@ -401,6 +405,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_pre,
descr_post,
plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
true,
);
}
MustUsePath::Closure(span) => {
@ -418,19 +423,6 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
);
}
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(
UNUSED_MUST_USE,
*span,
@ -440,7 +432,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
cx,
def_id: *def_id,
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.
///
/// 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.
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
/// 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.
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"}

View File

@ -237,7 +237,7 @@ impl ScalarInt {
}
/// 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.
#[inline]
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.
/// 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.
#[inline]
pub fn try_to_int(self, size: Size) -> Result<i128, Size> {
@ -306,35 +306,35 @@ impl ScalarInt {
}
/// 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.
pub fn try_to_i8(self) -> Result<i8, Size> {
self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap())
}
/// 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.
pub fn try_to_i16(self) -> Result<i16, Size> {
self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap())
}
/// 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.
pub fn try_to_i32(self) -> Result<i32, Size> {
self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap())
}
/// 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.
pub fn try_to_i64(self) -> Result<i64, Size> {
self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap())
}
/// 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.
pub fn try_to_i128(self) -> Result<i128, Size> {
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 std::any::Any;
use std::assert_matches::debug_assert_matches;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt;
@ -2049,6 +2050,12 @@ impl<'tcx> TyCtxt<'tcx> {
#[inline]
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))
}

View File

@ -1289,25 +1289,41 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
let span = find_span(&source, err);
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 (fields, applicability) = match field_ids {
Some(field_ids) => (
field_ids
.iter()
.map(|&field_id| {
format!("{}{tail}", self.r.tcx.item_name(field_id))
})
.collect::<Vec<String>>()
.join(", "),
applicability,
),
Some(field_ids) => {
let fields = field_ids.iter().map(|&id| self.r.tcx.item_name(id));
let fields = if let Some(old_fields) = old_fields {
fields
.enumerate()
.map(|(idx, new)| (new, old_fields.get(idx)))
.map(|(new, old)| {
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),
};
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::canonical::CanonicalVarValues;
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::ObligationCause;
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
@ -144,7 +144,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
self.infcx
.at(&ObligationCause::dummy(), param_env)
.eq(lhs, rhs)
.eq(DefineOpaqueTypes::No, lhs, rhs)
.map(|InferOk { value: (), obligations }| {
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_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_middle::traits::solve::{
CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData,
@ -268,7 +268,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
let InferOk { value: (), obligations } = self
.infcx
.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(
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::InferCtxt;
use crate::traits::project::ProjectAndUnifyResult;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::TypeVisitableExt;
@ -814,7 +815,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
match (evaluate(c1), evaluate(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(_) => (),
Err(_) => return false,

View File

@ -17,7 +17,7 @@ use crate::traits::{
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic;
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_middle::traits::specialization_graph::OverlapMode;
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 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");
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 })
}
fn equate_impl_headers<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
impl1_header: &ty::ImplHeader<'tcx>,
impl2_header: &ty::ImplHeader<'tcx>,
#[instrument(level = "debug", skip(infcx), ret)]
fn equate_impl_headers<'tcx>(
infcx: &InferCtxt<'tcx>,
impl1: &ty::ImplHeader<'tcx>,
impl2: &ty::ImplHeader<'tcx>,
) -> Option<PredicateObligations<'tcx>> {
// Do `a` and `b` unify? If not, no overlap.
debug!("equate_impl_headers(impl1_header={:?}, impl2_header={:?}", impl1_header, impl2_header);
selcx
.infcx
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
.define_opaque_types(true)
.eq_impl_headers(impl1_header, impl2_header)
.map(|infer_ok| infer_ok.obligations)
.ok()
let result = match (impl1.trait_ref, impl2.trait_ref) {
(Some(impl1_ref), Some(impl2_ref)) => infcx
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
.eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref),
(None, None) => infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
DefineOpaqueTypes::Yes,
impl1.self_ty,
impl2.self_ty,
),
_ => 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
@ -325,7 +330,7 @@ fn equate<'tcx>(
) -> bool {
// do the impls unify? If not, not disjoint.
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 {
debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
return true;

View File

@ -11,7 +11,7 @@ use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::canonical::{
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::{
FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
@ -128,8 +128,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
{
self.infcx
.at(cause, param_env)
.define_opaque_types(true)
.eq_exp(a_is_expected, a, b)
.eq_exp(DefineOpaqueTypes::Yes, a_is_expected, a, b)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
@ -142,8 +141,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> {
self.infcx
.at(cause, param_env)
.define_opaque_types(true)
.eq(expected, actual)
.eq(DefineOpaqueTypes::Yes, expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
@ -157,8 +155,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> {
self.infcx
.at(cause, param_env)
.define_opaque_types(true)
.sub(expected, actual)
.sub(DefineOpaqueTypes::Yes, expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
@ -172,8 +169,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
) -> Result<(), TypeError<'tcx>> {
self.infcx
.at(cause, param_env)
.define_opaque_types(true)
.sup(expected, actual)
.sup(DefineOpaqueTypes::Yes, expected, actual)
.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::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::ProjectionCacheKey;
use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation};
use rustc_middle::mir::interpret::ErrorHandled;
@ -515,7 +516,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
if let Ok(new_obligations) = infcx
.at(&obligation.cause, obligation.param_env)
.trace(c1, c2)
.eq(a.substs, b.substs)
.eq(DefineOpaqueTypes::No, a.substs, b.substs)
{
return ProcessResult::Changed(mk_pending(
new_obligations.into_obligations(),
@ -524,8 +525,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
}
(_, Unevaluated(_)) | (Unevaluated(_), _) => (),
(_, _) => {
if let Ok(new_obligations) =
infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2)
if let Ok(new_obligations) = infcx
.at(&obligation.cause, obligation.param_env)
.eq(DefineOpaqueTypes::No, c1, c2)
{
return ProcessResult::Changed(mk_pending(
new_obligations.into_obligations(),
@ -565,12 +567,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
match (evaluate(c1), evaluate(c2)) {
(Ok(c1), Ok(c2)) => {
match self
.selcx
.infcx
.at(&obligation.cause, obligation.param_env)
.eq(c1, c2)
{
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
DefineOpaqueTypes::No,
c1,
c2,
) {
Ok(inf_ok) => {
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")
}
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
match self
.selcx
.infcx
.at(&obligation.cause, obligation.param_env)
.eq(ct.ty(), ty)
{
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
DefineOpaqueTypes::No,
ct.ty(),
ty,
) {
Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError(
SelectionError::Unimplemented,

View File

@ -28,6 +28,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::at::At;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::ImplSourceBuiltinData;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
@ -285,12 +286,12 @@ fn project_and_unify_type<'cx, 'tcx>(
);
obligations.extend(new);
match infcx
.at(&obligation.cause, obligation.param_env)
// This is needed to support nested opaque types like `impl Fn() -> impl Trait`
.define_opaque_types(true)
.eq(normalized, actual)
{
// Need to define opaque types to support nested opaque types like `impl Fn() -> impl Trait`
match infcx.at(&obligation.cause, obligation.param_env).eq(
DefineOpaqueTypes::Yes,
normalized,
actual,
) {
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
ProjectAndUnifyResult::Holds(obligations)
@ -467,6 +468,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
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
// cases where there are nested projections under binders.
// 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
// 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
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
if !substs.has_escaping_bound_vars() =>
{
ty::Opaque if !data.substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() {
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 generic_ty = self.interner().type_of(def_id);
let substs = data.substs.fold_with(self);
let generic_ty = self.interner().type_of(data.def_id);
let concrete_ty = generic_ty.subst(self.interner(), substs);
self.depth += 1;
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
// have escaping bound vars, we don't need to replace them with
// 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()
}
ty::Alias(ty::Projection, data) => {
ty::Projection => {
// If there are escaping bound vars, we temporarily replace the
// bound vars with placeholders. Note though, that in the case
// 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
}
_ => ty.super_fold_with(self),
}
}
@ -2064,7 +2067,11 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
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 }) => {
nested_obligations.extend(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);
}
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
// wait to fold the substs.
// 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
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
if !substs.has_escaping_bound_vars() =>
{
ty::Opaque if !data.substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.try_super_fold_with(self)?,
Reveal::All => {
let substs = substs.try_fold_with(self)?;
let substs = data.substs.try_fold_with(self)?;
let recursion_limit = self.interner().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) {
// 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);
}
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);
self.anon_depth += 1;
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() => {
// 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).
ty::Opaque => ty.try_super_fold_with(self)?,
let tcx = self.infcx.tcx;
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) => {
ty::Projection => {
// See note in `rustc_trait_selection::traits::project`
let tcx = self.infcx.tcx;
let infcx = self.infcx;
let (data, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
// Just an optimization: When we don't have escaping bound vars,
// 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 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: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
let res = PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
result.normalized_ty,
);
let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
result.normalized_ty,
)
} else {
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) {
@ -353,8 +324,6 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
res
}
}
_ => ty.try_super_fold_with(self)?,
};
self.cache.insert(ty, res);

View File

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

View File

@ -38,6 +38,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::Diagnostic;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::traits::TraitEngine;
use rustc_infer::traits::TraitEngineExt;
@ -912,7 +913,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.infcx
.at(&obligation.cause, obligation.param_env)
.trace(c1, c2)
.eq(a.substs, b.substs)
.eq(DefineOpaqueTypes::No, a.substs, b.substs)
{
let mut obligations = new_obligations.obligations;
self.add_depth(
@ -930,7 +931,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let Ok(new_obligations) = self
.infcx
.at(&obligation.cause, obligation.param_env)
.eq(c1, c2)
.eq(DefineOpaqueTypes::No, c1, c2)
{
let mut obligations = new_obligations.obligations;
self.add_depth(
@ -964,8 +965,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match (evaluate(c1), evaluate(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(
previous_stack,
inf_ok.into_obligations(),
@ -993,7 +997,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
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(
previous_stack,
inf_ok.into_obligations(),
@ -1751,7 +1759,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
});
self.infcx
.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: () }| {
// This method is called within a probe, so we can't have
// inference variables and placeholders escape.
@ -1813,7 +1821,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let is_match = self
.infcx
.at(&obligation.cause, obligation.param_env)
.sup(obligation.predicate, infer_projection)
.sup(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
.map_or(false, |InferOk { obligations, value: () }| {
self.evaluate_predicates_recursively(
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
@ -2534,7 +2542,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
let InferOk { obligations, .. } = self
.infcx
.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| {
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>>, ()> {
self.infcx
.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_err(|_| ())
}

View File

@ -10,6 +10,7 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
pub mod specialization_graph;
use rustc_infer::infer::DefineOpaqueTypes;
use specialization_graph::GraphExt;
use crate::errors::NegativePositiveConflict;
@ -193,7 +194,7 @@ fn fulfill_implication<'tcx>(
// do the impls unify? If not, no specialization.
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 {
debug!(
"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_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 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::*};
///////////////////////////////////////////////////////////////////////////
@ -201,6 +200,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
let subject = selcx.tcx().bound_impl_subject(impl_def_id);
let subject = subject.subst(selcx.tcx(), impl_substs);
let InferOk { value: subject, obligations: normalization_obligations1 } =
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.
///
/// 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),
/// two `Rc`s that point to the same allocation are
/// never unequal.
/// always equal.
///
/// # Examples
///

View File

@ -2475,10 +2475,10 @@ impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
/// 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),
/// 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
///

View File

@ -158,7 +158,7 @@ mod sip;
///
/// Implementations of `hash` should ensure that the data they
/// 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.
///
/// 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.
///
/// # Examples

View File

@ -1110,7 +1110,7 @@ impl<T: Copy> Copy for (T,) {
/// - [NaN (not a number)](#associatedconstant.NAN): this value results from
/// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
/// 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.
/// - It is also neither smaller nor greater than any float, making it
/// 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
/// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
/// 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.
/// - It is also neither smaller nor greater than any float, making it
/// 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
/// 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
/// 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
/// the `owner` field fine in all cases.
pub struct ReentrantMutex<T> {

View File

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

View File

@ -1,6 +1,6 @@
use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_hir as hir;
use rustc_infer::infer::{InferOk, TyCtxtInferExt};
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
use rustc_infer::traits;
use rustc_middle::ty::ToPredicate;
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
// our type, and ignore the impl if there was a mismatch.
let cause = traits::ObligationCause::dummy();
let Ok(eq_result) = infcx.at(&cause, param_env).eq(impl_trait_ref.self_ty(), impl_ty) else {
let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, impl_trait_ref.self_ty(), impl_ty) else {
continue
};
let InferOk { value: (), obligations } = eq_result;

View File

@ -2,18 +2,20 @@
//!
//! On Windows this indirects IO into threads to work around performance issues
//! 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
//! 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
//! abstraction.
use std::cmp::max;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::string::ToString;
use std::sync::mpsc::Sender;
use std::thread::available_parallelism;
use threadpool::ThreadPool;
pub(crate) trait PathError {
fn new<S, P: AsRef<Path>>(e: S, path: P) -> Self
@ -24,11 +26,21 @@ pub(crate) trait PathError {
pub(crate) struct DocFS {
sync_only: bool,
errors: Option<Sender<String>>,
pool: ThreadPool,
}
impl 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) {
@ -54,12 +66,11 @@ impl DocFS {
where
E: PathError,
{
#[cfg(windows)]
if !self.sync_only {
// A possible future enhancement after more detailed profiling would
// be to create the file sync so errors are reported eagerly.
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| {
sender.send(format!("\"{}\": {}", path.display(), e)).unwrap_or_else(|_| {
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))?;
}
#[cfg(not(windows))]
fs::write(&path, contents).map_err(|e| E::new(e, path))?;
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))
else { return String::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 {
write!(buf, "{} ", cx.tcx().def_descr(id));
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".
let arg = if let Some(self_) = self_ {
let mut arg = if let Some(self_) = self_ {
match &*arg {
Type::BorrowedRef { 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
};
// 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
// for its bounds.
if let Type::Generic(arg_s) = *arg {
// 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,
_ => false,
}) {

View File

@ -1,7 +1,18 @@
const QUERY = 'option, fnonce -> option';
const QUERY = [
'option, fnonce -> option',
'option -> default',
];
const EXPECTED = {
'others': [
{ 'path': 'std::option::Option', 'name': 'map' },
],
};
const EXPECTED = [
{
'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 = [
{
@ -16,4 +16,15 @@ const EXPECTED = [
{ '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 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 - '//*[@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"]/@title' 'method 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)]
| ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = MustUseDeprecated::new();
| +++++++
warning: 5 warnings emitted

View File

@ -5,7 +5,7 @@ LL | FooB { x: i32, y: i32 }
| ----------------------- `FooB` defined here
...
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

View File

@ -10,12 +10,21 @@ note: the lint level is defined here
|
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
--> $DIR/fn_must_use.rs:60:5
|
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
--> $DIR/fn_must_use.rs:61:5
@ -24,24 +33,43 @@ LL | m.is_even(); // trait method!
| ^^^^^^^^^^^
|
= 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
--> $DIR/fn_must_use.rs:64:5
|
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
--> $DIR/fn_must_use.rs:70:5
|
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
--> $DIR/fn_must_use.rs:71:5
|
LL | m.eq(&n);
| ^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = m.eq(&n);
| +++++++
warning: unused comparison that must be used
--> $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)]
| ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = Box::from_raw(ptr);
| +++++++
warning: 1 warning emitted

View File

@ -9,12 +9,21 @@ note: the lint level is defined here
|
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
--> $DIR/must_use-unit.rs:15:5
|
LL | bar();
| ^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = bar();
| +++++++
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();
| ^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo();
| +++++++
error: unused output of future returned by `foo` that must be used
--> $DIR/unused-async.rs:33:5
|
LL | foo().await;
| ^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo().await;
| +++++++
error: unused implementer of `Future` that must be used
--> $DIR/unused-async.rs:34:5
@ -36,12 +46,22 @@ error: unused return value of `bar` that must be used
|
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
--> $DIR/unused-async.rs:36:5
|
LL | bar().await;
| ^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = bar().await;
| +++++++
error: unused implementer of `Future` that must be used
--> $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)]
| ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo::<MustUse>();
| +++++++
error: unused `MustUseMsg` that must be used
--> $DIR/unused-result.rs:22:5
@ -17,6 +21,10 @@ LL | foo::<MustUseMsg>();
| ^^^^^^^^^^^^^^^^^^^
|
= note: some message
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo::<MustUseMsg>();
| +++++++
error: unused result of type `isize`
--> $DIR/unused-result.rs:34:5
@ -35,6 +43,11 @@ error: unused `MustUse` that must be used
|
LL | foo::<MustUse>();
| ^^^^^^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo::<MustUse>();
| +++++++
error: unused `MustUseMsg` that must be used
--> $DIR/unused-result.rs:36:5
@ -43,6 +56,10 @@ LL | foo::<MustUseMsg>();
| ^^^^^^^^^^^^^^^^^^^
|
= note: some message
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo::<MustUseMsg>();
| +++++++
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)]
| ^^^^^^^^^^^^^^^
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = X;
| +++++++
error: unused `Y` that must be used
--> $DIR/unused_attributes-must_use.rs:104:5
|
LL | Y::Z;
| ^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = Y::Z;
| +++++++
error: unused `U` that must be used
--> $DIR/unused_attributes-must_use.rs:105:5
|
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
--> $DIR/unused_attributes-must_use.rs:106:5
|
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
--> $DIR/unused_attributes-must_use.rs:107:5
|
LL | foo();
| ^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = foo();
| +++++++
error: unused return value of `foreign_foo` that must be used
--> $DIR/unused_attributes-must_use.rs:110:9
|
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
--> $DIR/unused_attributes-must_use.rs:118:5
|
LL | ().get_four();
| ^^^^^^^^^^^^^
|
help: use `let _ = ...` to ignore the resulting value
|
LL | let _ = ().get_four();
| +++++++
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`.