Auto merge of #127430 - compiler-errors:rollup-76ni16s, r=compiler-errors

Rollup of 4 pull requests

Successful merges:

 - #127386 (Uplift outlives components to `rustc_type_ir`)
 - #127405 (uplift `PredicateEmittingRelation`)
 - #127410 (Correct description of E0502)
 - #127417 (Show fnsig's unit output  explicitly when there is output diff in diagnostics)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-07-06 20:26:50 +00:00
commit ed7e35f349
43 changed files with 515 additions and 392 deletions

View File

@ -4168,6 +4168,7 @@ dependencies = [
"rustc_index", "rustc_index",
"rustc_macros", "rustc_macros",
"rustc_middle", "rustc_middle",
"rustc_next_trait_solver",
"rustc_span", "rustc_span",
"rustc_target", "rustc_target",
"rustc_type_ir", "rustc_type_ir",

View File

@ -1,8 +1,9 @@
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_infer::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; use rustc_infer::infer::relate::{
use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation}; PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
use rustc_infer::infer::NllRegionVariableOrigin; };
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_infer::traits::solve::Goal; use rustc_infer::traits::solve::Goal;
use rustc_infer::traits::Obligation; use rustc_infer::traits::Obligation;
use rustc_middle::mir::ConstraintCategory; use rustc_middle::mir::ConstraintCategory;
@ -522,7 +523,7 @@ impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx
} }
} }
impl<'bccx, 'tcx> PredicateEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { impl<'bccx, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> {
fn span(&self) -> Span { fn span(&self) -> Span {
self.locations.span(self.type_checker.body) self.locations.span(self.type_checker.body)
} }

View File

@ -1,4 +1,5 @@
A variable already borrowed as immutable was borrowed as mutable. A variable already borrowed with a certain mutability (either mutable or
immutable) was borrowed again with a different mutability.
Erroneous code example: Erroneous code example:
@ -13,7 +14,7 @@ fn foo(a: &mut i32) {
``` ```
To fix this error, ensure that you don't have any other references to the To fix this error, ensure that you don't have any other references to the
variable before trying to access it mutably: variable before trying to access it with a different mutability:
``` ```
fn bar(x: &mut i32) {} fn bar(x: &mut i32) {}

View File

@ -1,9 +1,9 @@
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
use rustc_middle::ty::{self, Region, Ty, TyCtxt}; use rustc_middle::ty::{self, Region, Ty, TyCtxt};
use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_middle::ty::{GenericArg, GenericArgKind};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_span::Span; use rustc_span::Span;
use rustc_type_ir::outlives::{push_outlives_components, Component};
use smallvec::smallvec; use smallvec::smallvec;
/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred

View File

@ -16,6 +16,7 @@ rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" } rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" } rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" } rustc_middle = { path = "../rustc_middle" }
rustc_next_trait_solver = { path = "../rustc_next_trait_solver" }
rustc_span = { path = "../rustc_span" } rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" } rustc_target = { path = "../rustc_target" }
rustc_type_ir = { path = "../rustc_type_ir" } rustc_type_ir = { path = "../rustc_type_ir" }

View File

@ -1168,14 +1168,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let output1 = sig1.output(); let output1 = sig1.output();
let output2 = sig2.output(); let output2 = sig2.output();
let (x1, x2) = self.cmp(output1, output2); let (x1, x2) = self.cmp(output1, output2);
if !output1.is_unit() { let output_diff = x1 != x2;
if !output1.is_unit() || output_diff {
values.0.push_normal(" -> "); values.0.push_normal(" -> ");
(values.0).0.extend(x1.0); (values.0).0.extend(x1.0);
} }
if !output2.is_unit() { if !output2.is_unit() || output_diff {
values.1.push_normal(" -> "); values.1.push_normal(" -> ");
(values.1).0.extend(x2.0); (values.1).0.extend(x2.0);
} }
values values
} }

View File

@ -1,266 +0,0 @@
// The outlines relation `T: 'a` or `'a: 'b`. This code frequently
// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
// RFC for reference.
use rustc_data_structures::sso::SsoHashSet;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{GenericArg, GenericArgKind};
use smallvec::{smallvec, SmallVec};
#[derive(Debug)]
pub enum Component<'tcx> {
Region(ty::Region<'tcx>),
Param(ty::ParamTy),
Placeholder(ty::PlaceholderType),
UnresolvedInferenceVariable(ty::InferTy),
// Projections like `T::Foo` are tricky because a constraint like
// `T::Foo: 'a` can be satisfied in so many ways. There may be a
// where-clause that says `T::Foo: 'a`, or the defining trait may
// include a bound like `type Foo: 'static`, or -- in the most
// conservative way -- we can prove that `T: 'a` (more generally,
// that all components in the projection outlive `'a`). This code
// is not in a position to judge which is the best technique, so
// we just product the projection as a component and leave it to
// the consumer to decide (but see `EscapingProjection` below).
Alias(ty::AliasTy<'tcx>),
// In the case where a projection has escaping regions -- meaning
// regions bound within the type itself -- we always use
// the most conservative rule, which requires that all components
// outlive the bound. So for example if we had a type like this:
//
// for<'a> Trait1< <T as Trait2<'a,'b>>::Foo >
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// then the inner projection (underlined) has an escaping region
// `'a`. We consider that outer trait `'c` to meet a bound if `'b`
// outlives `'b: 'c`, and we don't consider whether the trait
// declares that `Foo: 'static` etc. Therefore, we just return the
// free components of such a projection (in this case, `'b`).
//
// However, in the future, we may want to get smarter, and
// actually return a "higher-ranked projection" here. Therefore,
// we mark that these components are part of an escaping
// projection, so that implied bounds code can avoid relying on
// them. This gives us room to improve the regionck reasoning in
// the future without breaking backwards compat.
EscapingAlias(Vec<Component<'tcx>>),
}
/// Push onto `out` all the things that must outlive `'a` for the condition
/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
pub fn push_outlives_components<'tcx>(
tcx: TyCtxt<'tcx>,
ty0: Ty<'tcx>,
out: &mut SmallVec<[Component<'tcx>; 4]>,
) {
let mut visited = SsoHashSet::new();
compute_components(tcx, ty0, out, &mut visited);
debug!("components({:?}) = {:?}", ty0, out);
}
fn compute_components<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
out: &mut SmallVec<[Component<'tcx>; 4]>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) {
// Descend through the types, looking for the various "base"
// components and collecting them into `out`. This is not written
// with `collect()` because of the need to sometimes skip subtrees
// in the `subtys` iterator (e.g., when encountering a
// projection).
match *ty.kind() {
ty::FnDef(_, args) => {
// HACK(eddyb) ignore lifetimes found shallowly in `args`.
// This is inconsistent with `ty::Adt` (including all args)
// and with `ty::Closure` (ignoring all args other than
// upvars, of which a `ty::FnDef` doesn't have any), but
// consistent with previous (accidental) behavior.
// See https://github.com/rust-lang/rust/issues/70917
// for further background and discussion.
for child in args {
match child.unpack() {
GenericArgKind::Type(ty) => {
compute_components(tcx, ty, out, visited);
}
GenericArgKind::Lifetime(_) => {}
GenericArgKind::Const(_) => {
compute_components_recursive(tcx, child, out, visited);
}
}
}
}
ty::Pat(element, _) |
ty::Array(element, _) => {
// Don't look into the len const as it doesn't affect regions
compute_components(tcx, element, out, visited);
}
ty::Closure(_, args) => {
let tupled_ty = args.as_closure().tupled_upvars_ty();
compute_components(tcx, tupled_ty, out, visited);
}
ty::CoroutineClosure(_, args) => {
let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty();
compute_components(tcx, tupled_ty, out, visited);
}
ty::Coroutine(_, args) => {
// Same as the closure case
let tupled_ty = args.as_coroutine().tupled_upvars_ty();
compute_components(tcx, tupled_ty, out, visited);
// We ignore regions in the coroutine interior as we don't
// want these to affect region inference
}
// All regions are bound inside a witness
ty::CoroutineWitness(..) => (),
// OutlivesTypeParameterEnv -- the actual checking that `X:'a`
// is implied by the environment is done in regionck.
ty::Param(p) => {
out.push(Component::Param(p));
}
ty::Placeholder(p) => {
out.push(Component::Placeholder(p));
}
// For projections, we prefer to generate an obligation like
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
// regionck more ways to prove that it holds. However,
// regionck is not (at least currently) prepared to deal with
// higher-ranked regions that may appear in the
// trait-ref. Therefore, if we see any higher-ranked regions,
// we simply fallback to the most restrictive rule, which
// requires that `Pi: 'a` for all `i`.
ty::Alias(_, alias_ty) => {
if !alias_ty.has_escaping_bound_vars() {
// best case: no escaping regions, so push the
// projection and skip the subtree (thus generating no
// constraints for Pi). This defers the choice between
// the rules OutlivesProjectionEnv,
// OutlivesProjectionTraitDef, and
// OutlivesProjectionComponents to regionck.
out.push(Component::Alias(alias_ty));
} else {
// fallback case: hard code
// OutlivesProjectionComponents. Continue walking
// through and constrain Pi.
let mut subcomponents = smallvec![];
let mut subvisited = SsoHashSet::new();
compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited);
out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
}
}
// We assume that inference variables are fully resolved.
// So, if we encounter an inference variable, just record
// the unresolved variable as a component.
ty::Infer(infer_ty) => {
out.push(Component::UnresolvedInferenceVariable(infer_ty));
}
// Most types do not introduce any region binders, nor
// involve any other subtle cases, and so the WF relation
// simply constraints any regions referenced directly by
// the type and then visits the types that are lexically
// contained within. (The comments refer to relevant rules
// from RFC1214.)
ty::Bool | // OutlivesScalar
ty::Char | // OutlivesScalar
ty::Int(..) | // OutlivesScalar
ty::Uint(..) | // OutlivesScalar
ty::Float(..) | // OutlivesScalar
ty::Never | // ...
ty::Adt(..) | // OutlivesNominalType
ty::Foreign(..) | // OutlivesNominalType
ty::Str | // OutlivesScalar (ish)
ty::Slice(..) | // ...
ty::RawPtr(..) | // ...
ty::Ref(..) | // OutlivesReference
ty::Tuple(..) | // ...
ty::FnPtr(_) | // OutlivesFunction (*)
ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*)
ty::Bound(..) |
ty::Error(_) => {
// (*) Function pointers and trait objects are both binders.
// In the RFC, this means we would add the bound regions to
// the "bound regions list". In our representation, no such
// list is maintained explicitly, because bound regions
// themselves can be readily identified.
compute_components_recursive(tcx, ty.into(), out, visited);
}
}
}
/// Collect [Component]s for *all* the args of `parent`.
///
/// This should not be used to get the components of `parent` itself.
/// Use [push_outlives_components] instead.
pub(super) fn compute_alias_components_recursive<'tcx>(
tcx: TyCtxt<'tcx>,
alias_ty: Ty<'tcx>,
out: &mut SmallVec<[Component<'tcx>; 4]>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) {
let ty::Alias(kind, alias_ty) = alias_ty.kind() else {
unreachable!("can only call `compute_alias_components_recursive` on an alias type")
};
let opt_variances = if *kind == ty::Opaque { tcx.variances_of(alias_ty.def_id) } else { &[] };
for (index, child) in alias_ty.args.iter().enumerate() {
if opt_variances.get(index) == Some(&ty::Bivariant) {
continue;
}
if !visited.insert(child) {
continue;
}
match child.unpack() {
GenericArgKind::Type(ty) => {
compute_components(tcx, ty, out, visited);
}
GenericArgKind::Lifetime(lt) => {
// Ignore higher ranked regions.
if !lt.is_bound() {
out.push(Component::Region(lt));
}
}
GenericArgKind::Const(_) => {
compute_components_recursive(tcx, child, out, visited);
}
}
}
}
/// Collect [Component]s for *all* the args of `parent`.
///
/// This should not be used to get the components of `parent` itself.
/// Use [push_outlives_components] instead.
fn compute_components_recursive<'tcx>(
tcx: TyCtxt<'tcx>,
parent: GenericArg<'tcx>,
out: &mut SmallVec<[Component<'tcx>; 4]>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) {
for child in parent.walk_shallow(visited) {
match child.unpack() {
GenericArgKind::Type(ty) => {
compute_components(tcx, ty, out, visited);
}
GenericArgKind::Lifetime(lt) => {
// Ignore higher ranked regions.
if !lt.is_bound() {
out.push(Component::Region(lt));
}
}
GenericArgKind::Const(_) => {
compute_components_recursive(tcx, child, out, visited);
}
}
}
}

View File

@ -8,7 +8,6 @@ use crate::infer::lexical_region_resolve;
use rustc_middle::traits::query::{NoSolution, OutlivesBound}; use rustc_middle::traits::query::{NoSolution, OutlivesBound};
use rustc_middle::ty; use rustc_middle::ty;
pub mod components;
pub mod env; pub mod env;
pub mod for_liveness; pub mod for_liveness;
pub mod obligations; pub mod obligations;

View File

@ -59,7 +59,6 @@
//! might later infer `?U` to something like `&'b u32`, which would //! might later infer `?U` to something like `&'b u32`, which would
//! imply that `'b: 'a`. //! imply that `'b: 'a`.
use crate::infer::outlives::components::{push_outlives_components, Component};
use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::outlives::verify::VerifyBoundCx; use crate::infer::outlives::verify::VerifyBoundCx;
use crate::infer::resolve::OpportunisticRegionResolver; use crate::infer::resolve::OpportunisticRegionResolver;
@ -75,6 +74,7 @@ use rustc_middle::ty::{
}; };
use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate}; use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate};
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use rustc_type_ir::outlives::{push_outlives_components, Component};
use smallvec::smallvec; use smallvec::smallvec;
use super::env::OutlivesEnvironment; use super::env::OutlivesEnvironment;
@ -291,7 +291,7 @@ where
fn components_must_outlive( fn components_must_outlive(
&mut self, &mut self,
origin: infer::SubregionOrigin<'tcx>, origin: infer::SubregionOrigin<'tcx>,
components: &[Component<'tcx>], components: &[Component<TyCtxt<'tcx>>],
region: ty::Region<'tcx>, region: ty::Region<'tcx>,
category: ConstraintCategory<'tcx>, category: ConstraintCategory<'tcx>,
) { ) {

View File

@ -1,10 +1,10 @@
use crate::infer::outlives::components::{compute_alias_components_recursive, Component};
use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::region_constraints::VerifyIfEq; use crate::infer::region_constraints::VerifyIfEq;
use crate::infer::{GenericKind, VerifyBound}; use crate::infer::{GenericKind, VerifyBound};
use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::sso::SsoHashSet;
use rustc_middle::ty::GenericArg; use rustc_middle::ty::GenericArg;
use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt}; use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
use rustc_type_ir::outlives::{compute_alias_components_recursive, Component};
use smallvec::smallvec; use smallvec::smallvec;
@ -139,7 +139,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
fn bound_from_components( fn bound_from_components(
&self, &self,
components: &[Component<'tcx>], components: &[Component<TyCtxt<'tcx>>],
visited: &mut SsoHashSet<GenericArg<'tcx>>, visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> { ) -> VerifyBound<'tcx> {
let mut bounds = components let mut bounds = components
@ -158,7 +158,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
fn bound_from_single_component( fn bound_from_single_component(
&self, &self,
component: &Component<'tcx>, component: &Component<TyCtxt<'tcx>>,
visited: &mut SsoHashSet<GenericArg<'tcx>>, visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> { ) -> VerifyBound<'tcx> {
match *component { match *component {

View File

@ -18,11 +18,13 @@
//! On success, the LUB/GLB operations return the appropriate bound. The //! On success, the LUB/GLB operations return the appropriate bound. The
//! return value of `Equate` or `Sub` shouldn't really be used. //! return value of `Equate` or `Sub` shouldn't really be used.
pub use rustc_next_trait_solver::relate::combine::*;
use super::glb::Glb; use super::glb::Glb;
use super::lub::Lub; use super::lub::Lub;
use super::type_relating::TypeRelating; use super::type_relating::TypeRelating;
use super::RelateResult;
use super::StructurallyRelateAliases; use super::StructurallyRelateAliases;
use super::{RelateResult, TypeRelation};
use crate::infer::relate; use crate::infer::relate;
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
use crate::traits::{Obligation, PredicateObligation}; use crate::traits::{Obligation, PredicateObligation};
@ -32,7 +34,6 @@ use rustc_middle::traits::solve::Goal;
use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
use rustc_middle::ty::{IntType, UintType}; use rustc_middle::ty::{IntType, UintType};
use rustc_span::Span;
#[derive(Clone)] #[derive(Clone)]
pub struct CombineFields<'infcx, 'tcx> { pub struct CombineFields<'infcx, 'tcx> {
@ -76,7 +77,7 @@ impl<'tcx> InferCtxt<'tcx> {
b: Ty<'tcx>, b: Ty<'tcx>,
) -> RelateResult<'tcx, Ty<'tcx>> ) -> RelateResult<'tcx, Ty<'tcx>>
where where
R: PredicateEmittingRelation<'tcx>, R: PredicateEmittingRelation<InferCtxt<'tcx>>,
{ {
debug_assert!(!a.has_escaping_bound_vars()); debug_assert!(!a.has_escaping_bound_vars());
debug_assert!(!b.has_escaping_bound_vars()); debug_assert!(!b.has_escaping_bound_vars());
@ -171,7 +172,7 @@ impl<'tcx> InferCtxt<'tcx> {
b: ty::Const<'tcx>, b: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> ) -> RelateResult<'tcx, ty::Const<'tcx>>
where where
R: PredicateEmittingRelation<'tcx>, R: PredicateEmittingRelation<InferCtxt<'tcx>>,
{ {
debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
debug_assert!(!a.has_escaping_bound_vars()); debug_assert!(!a.has_escaping_bound_vars());
@ -323,30 +324,3 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
) )
} }
} }
pub trait PredicateEmittingRelation<'tcx>: TypeRelation<TyCtxt<'tcx>> {
fn span(&self) -> Span;
fn param_env(&self) -> ty::ParamEnv<'tcx>;
/// Whether aliases should be related structurally. This is pretty much
/// always `No` unless you're equating in some specific locations of the
/// new solver. See the comments in these use-cases for more details.
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
/// Register obligations that must hold in order for this relation to hold
fn register_goals(
&mut self,
obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
);
/// Register predicates that must hold in order for this relation to hold.
/// This uses the default `param_env` of the obligation.
fn register_predicates(
&mut self,
obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
);
/// Register `AliasRelate` obligation(s) that both types must be related to each other.
fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>);
}

View File

@ -30,7 +30,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
/// other usecases (i.e. setting the value of a type var). /// other usecases (i.e. setting the value of a type var).
#[instrument(level = "debug", skip(self, relation))] #[instrument(level = "debug", skip(self, relation))]
pub fn instantiate_ty_var<R: PredicateEmittingRelation<'tcx>>( pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
&self, &self,
relation: &mut R, relation: &mut R,
target_is_expected: bool, target_is_expected: bool,
@ -178,7 +178,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// ///
/// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
#[instrument(level = "debug", skip(self, relation))] #[instrument(level = "debug", skip(self, relation))]
pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<'tcx>>( pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
&self, &self,
relation: &mut R, relation: &mut R,
target_is_expected: bool, target_is_expected: bool,

View File

@ -123,7 +123,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
} }
} }
impl<'tcx> PredicateEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> { impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Glb<'_, '_, 'tcx> {
fn span(&self) -> Span { fn span(&self) -> Span {
self.fields.trace.span() self.fields.trace.span()
} }

View File

@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Ty};
/// ///
/// GLB moves "down" the lattice (to smaller values); LUB moves /// GLB moves "down" the lattice (to smaller values); LUB moves
/// "up" the lattice (to bigger values). /// "up" the lattice (to bigger values).
pub trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<'tcx> { pub trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<InferCtxt<'tcx>> {
fn infcx(&self) -> &'f InferCtxt<'tcx>; fn infcx(&self) -> &'f InferCtxt<'tcx>;
fn cause(&self) -> &ObligationCause<'tcx>; fn cause(&self) -> &ObligationCause<'tcx>;

View File

@ -123,7 +123,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
} }
} }
impl<'tcx> PredicateEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> { impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Lub<'_, '_, 'tcx> {
fn span(&self) -> Span { fn span(&self) -> Span {
self.fields.trace.span() self.fields.trace.span()
} }

View File

@ -2,11 +2,13 @@
//! (except for some relations used for diagnostics and heuristics in the compiler). //! (except for some relations used for diagnostics and heuristics in the compiler).
//! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc). //! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc).
pub use rustc_middle::ty::relate::*; pub use rustc_middle::ty::relate::RelateResult;
pub use rustc_next_trait_solver::relate::*;
pub use self::combine::CombineFields; pub use self::combine::CombineFields;
pub use self::combine::PredicateEmittingRelation; pub use self::combine::PredicateEmittingRelation;
#[allow(hidden_glob_reexports)]
pub(super) mod combine; pub(super) mod combine;
mod generalize; mod generalize;
mod glb; mod glb;

View File

@ -1,7 +1,7 @@
use super::combine::CombineFields; use super::combine::CombineFields;
use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
use crate::infer::BoundRegionConversionTime::HigherRankedType; use crate::infer::BoundRegionConversionTime::HigherRankedType;
use crate::infer::{DefineOpaqueTypes, SubregionOrigin}; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
use rustc_middle::traits::solve::Goal; use rustc_middle::traits::solve::Goal;
use rustc_middle::ty::relate::{ use rustc_middle::ty::relate::{
relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation,
@ -296,7 +296,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
} }
} }
impl<'tcx> PredicateEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
fn span(&self) -> Span { fn span(&self) -> Span {
self.fields.trace.span() self.fields.trace.span()
} }

View File

@ -1,12 +1,12 @@
use smallvec::smallvec; use smallvec::smallvec;
use crate::infer::outlives::components::{push_outlives_components, Component};
use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation}; use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::ToPolyTraitRef; use rustc_middle::ty::ToPolyTraitRef;
use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::Span; use rustc_span::Span;
use rustc_type_ir::outlives::{push_outlives_components, Component};
pub fn anonymize_predicate<'tcx>( pub fn anonymize_predicate<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,

View File

@ -54,6 +54,13 @@ pub struct Expr<'tcx> {
pub kind: ExprKind, pub kind: ExprKind,
args: ty::GenericArgsRef<'tcx>, args: ty::GenericArgsRef<'tcx>,
} }
impl<'tcx> rustc_type_ir::inherent::ExprConst<TyCtxt<'tcx>> for Expr<'tcx> {
fn args(self) -> ty::GenericArgsRef<'tcx> {
self.args
}
}
impl<'tcx> Expr<'tcx> { impl<'tcx> Expr<'tcx> {
pub fn new_binop( pub fn new_binop(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,

View File

@ -92,6 +92,8 @@ use std::ops::{Bound, Deref};
impl<'tcx> Interner for TyCtxt<'tcx> { impl<'tcx> Interner for TyCtxt<'tcx> {
type DefId = DefId; type DefId = DefId;
type LocalDefId = LocalDefId; type LocalDefId = LocalDefId;
type Span = Span;
type GenericArgs = ty::GenericArgsRef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>;
type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>]; type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];

View File

@ -10,18 +10,6 @@ use crate::ty::{self as ty, Ty, TyCtxt};
pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>; pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>;
/// Whether aliases should be related structurally or not. Used
/// to adjust the behavior of generalization and combine.
///
/// This should always be `No` unless in a few special-cases when
/// instantiating canonical responses and in the new solver. Each
/// such case should have a comment explaining why it is used.
#[derive(Debug, Copy, Clone)]
pub enum StructurallyRelateAliases {
Yes,
No,
}
impl<'tcx> Relate<TyCtxt<'tcx>> for ty::ImplSubject<'tcx> { impl<'tcx> Relate<TyCtxt<'tcx>> for ty::ImplSubject<'tcx> {
#[inline] #[inline]
fn relate<R: TypeRelation<TyCtxt<'tcx>>>( fn relate<R: TypeRelation<TyCtxt<'tcx>>>(

View File

@ -78,23 +78,6 @@ impl<'tcx> GenericArg<'tcx> {
pub fn walk(self) -> TypeWalker<'tcx> { pub fn walk(self) -> TypeWalker<'tcx> {
TypeWalker::new(self) TypeWalker::new(self)
} }
/// Iterator that walks the immediate children of `self`. Hence
/// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
/// (but not `i32`, like `walk`).
///
/// Iterator only walks items once.
/// It accepts visited set, updates it with all visited types
/// and skips any types that are already there.
pub fn walk_shallow(
self,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> impl Iterator<Item = GenericArg<'tcx>> {
let mut stack = SmallVec::new();
push_inner(&mut stack, self);
stack.retain(|a| visited.insert(*a));
stack.into_iter()
}
} }
impl<'tcx> Ty<'tcx> { impl<'tcx> Ty<'tcx> {

View File

@ -6,5 +6,6 @@
pub mod canonicalizer; pub mod canonicalizer;
pub mod delegate; pub mod delegate;
pub mod relate;
pub mod resolve; pub mod resolve;
pub mod solve; pub mod solve;

View File

@ -0,0 +1,15 @@
pub use rustc_type_ir::relate::*;
pub mod combine;
/// Whether aliases should be related structurally or not. Used
/// to adjust the behavior of generalization and combine.
///
/// This should always be `No` unless in a few special-cases when
/// instantiating canonical responses and in the new solver. Each
/// such case should have a comment explaining why it is used.
#[derive(Debug, Copy, Clone)]
pub enum StructurallyRelateAliases {
Yes,
No,
}

View File

@ -0,0 +1,34 @@
pub use rustc_type_ir::relate::*;
use rustc_type_ir::solve::Goal;
use rustc_type_ir::{InferCtxtLike, Interner, Upcast};
use super::StructurallyRelateAliases;
pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
TypeRelation<I>
where
Infcx: InferCtxtLike<Interner = I>,
I: Interner,
{
fn span(&self) -> I::Span;
fn param_env(&self) -> I::ParamEnv;
/// Whether aliases should be related structurally. This is pretty much
/// always `No` unless you're equating in some specific locations of the
/// new solver. See the comments in these use-cases for more details.
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
/// Register obligations that must hold in order for this relation to hold
fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>);
/// Register predicates that must hold in order for this relation to hold.
/// This uses the default `param_env` of the obligation.
fn register_predicates(
&mut self,
obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>,
);
/// Register `AliasRelate` obligation(s) that both types must be related to each other.
fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty);
}

View File

@ -3,7 +3,6 @@ use crate::traits::wf;
use crate::traits::ObligationCtxt; use crate::traits::ObligationCtxt;
use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::traits::query::OutlivesBound; use rustc_infer::traits::query::OutlivesBound;
use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
@ -12,6 +11,7 @@ use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt}; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use rustc_type_ir::outlives::{push_outlives_components, Component};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
@ -284,7 +284,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
/// those relationships. /// those relationships.
fn implied_bounds_from_components<'tcx>( fn implied_bounds_from_components<'tcx>(
sub_region: ty::Region<'tcx>, sub_region: ty::Region<'tcx>,
sup_components: SmallVec<[Component<'tcx>; 4]>, sup_components: SmallVec<[Component<TyCtxt<'tcx>>; 4]>,
) -> Vec<OutlivesBound<'tcx>> { ) -> Vec<OutlivesBound<'tcx>> {
sup_components sup_components
.into_iter() .into_iter()

View File

@ -232,6 +232,10 @@ pub trait Region<I: Interner<Region = Self>>:
fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
fn new_static(interner: I) -> Self; fn new_static(interner: I) -> Self;
fn is_bound(self) -> bool {
matches!(self.kind(), ty::ReBound(..))
}
} }
pub trait Const<I: Interner<Const = Self>>: pub trait Const<I: Interner<Const = Self>>:
@ -272,6 +276,10 @@ pub trait Const<I: Interner<Const = Self>>:
} }
} }
pub trait ExprConst<I: Interner<ExprConst = Self>>: Copy + Debug + Hash + Eq + Relate<I> {
fn args(self) -> I::GenericArgs;
}
pub trait GenericsOf<I: Interner<GenericsOf = Self>> { pub trait GenericsOf<I: Interner<GenericsOf = Self>> {
fn count(&self) -> usize; fn count(&self) -> usize;
} }

View File

@ -32,6 +32,7 @@ pub trait Interner:
{ {
type DefId: DefId<Self>; type DefId: DefId<Self>;
type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>; type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
type Span: Copy + Debug + Hash + Eq;
type GenericArgs: GenericArgs<Self>; type GenericArgs: GenericArgs<Self>;
type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike<Item = Self::GenericArg>; type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike<Item = Self::GenericArg>;
@ -109,7 +110,7 @@ pub trait Interner:
type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>; type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
type ValueConst: Copy + Debug + Hash + Eq; type ValueConst: Copy + Debug + Hash + Eq;
type ExprConst: Copy + Debug + Hash + Eq + Relate<Self>; type ExprConst: ExprConst<Self>;
// Kinds of regions // Kinds of regions
type Region: Region<Self>; type Region: Region<Self>;

View File

@ -27,6 +27,7 @@ pub mod inherent;
pub mod ir_print; pub mod ir_print;
pub mod lang_items; pub mod lang_items;
pub mod lift; pub mod lift;
pub mod outlives;
pub mod relate; pub mod relate;
pub mod solve; pub mod solve;

View File

@ -0,0 +1,335 @@
//! The outlives relation `T: 'a` or `'a: 'b`. This code frequently
//! refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
//! RFC for reference.
use smallvec::{smallvec, SmallVec};
use tracing::debug;
use crate::data_structures::SsoHashSet;
use crate::inherent::*;
use crate::visit::TypeVisitableExt as _;
use crate::{self as ty, Interner};
#[derive(derivative::Derivative)]
#[derivative(Debug(bound = ""))]
pub enum Component<I: Interner> {
Region(I::Region),
Param(I::ParamTy),
Placeholder(I::PlaceholderTy),
UnresolvedInferenceVariable(ty::InferTy),
// Projections like `T::Foo` are tricky because a constraint like
// `T::Foo: 'a` can be satisfied in so many ways. There may be a
// where-clause that says `T::Foo: 'a`, or the defining trait may
// include a bound like `type Foo: 'static`, or -- in the most
// conservative way -- we can prove that `T: 'a` (more generally,
// that all components in the projection outlive `'a`). This code
// is not in a position to judge which is the best technique, so
// we just product the projection as a component and leave it to
// the consumer to decide (but see `EscapingProjection` below).
Alias(ty::AliasTy<I>),
// In the case where a projection has escaping regions -- meaning
// regions bound within the type itself -- we always use
// the most conservative rule, which requires that all components
// outlive the bound. So for example if we had a type like this:
//
// for<'a> Trait1< <T as Trait2<'a,'b>>::Foo >
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// then the inner projection (underlined) has an escaping region
// `'a`. We consider that outer trait `'c` to meet a bound if `'b`
// outlives `'b: 'c`, and we don't consider whether the trait
// declares that `Foo: 'static` etc. Therefore, we just return the
// free components of such a projection (in this case, `'b`).
//
// However, in the future, we may want to get smarter, and
// actually return a "higher-ranked projection" here. Therefore,
// we mark that these components are part of an escaping
// projection, so that implied bounds code can avoid relying on
// them. This gives us room to improve the regionck reasoning in
// the future without breaking backwards compat.
EscapingAlias(Vec<Component<I>>),
}
/// Push onto `out` all the things that must outlive `'a` for the condition
/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
pub fn push_outlives_components<I: Interner>(
tcx: I,
ty0: I::Ty,
out: &mut SmallVec<[Component<I>; 4]>,
) {
let mut visited = SsoHashSet::new();
compute_components_for_ty(tcx, ty0, out, &mut visited);
debug!("components({:?}) = {:?}", ty0, out);
}
fn compute_components_for_arg<I: Interner>(
tcx: I,
arg: I::GenericArg,
out: &mut SmallVec<[Component<I>; 4]>,
visited: &mut SsoHashSet<I::GenericArg>,
) {
match arg.kind() {
ty::GenericArgKind::Type(ty) => {
compute_components_for_ty(tcx, ty, out, visited);
}
ty::GenericArgKind::Lifetime(lt) => {
compute_components_for_lt(lt, out);
}
ty::GenericArgKind::Const(ct) => {
compute_components_for_const(tcx, ct, out, visited);
}
}
}
fn compute_components_for_ty<I: Interner>(
tcx: I,
ty: I::Ty,
out: &mut SmallVec<[Component<I>; 4]>,
visited: &mut SsoHashSet<I::GenericArg>,
) {
if !visited.insert(ty.into()) {
return;
}
// Descend through the types, looking for the various "base"
// components and collecting them into `out`. This is not written
// with `collect()` because of the need to sometimes skip subtrees
// in the `subtys` iterator (e.g., when encountering a
// projection).
match ty.kind() {
ty::FnDef(_, args) => {
// HACK(eddyb) ignore lifetimes found shallowly in `args`.
// This is inconsistent with `ty::Adt` (including all args)
// and with `ty::Closure` (ignoring all args other than
// upvars, of which a `ty::FnDef` doesn't have any), but
// consistent with previous (accidental) behavior.
// See https://github.com/rust-lang/rust/issues/70917
// for further background and discussion.
for child in args.iter() {
match child.kind() {
ty::GenericArgKind::Type(ty) => {
compute_components_for_ty(tcx, ty, out, visited);
}
ty::GenericArgKind::Lifetime(_) => {}
ty::GenericArgKind::Const(ct) => {
compute_components_for_const(tcx, ct, out, visited);
}
}
}
}
ty::Pat(element, _) | ty::Array(element, _) => {
compute_components_for_ty(tcx, element, out, visited);
}
ty::Closure(_, args) => {
let tupled_ty = args.as_closure().tupled_upvars_ty();
compute_components_for_ty(tcx, tupled_ty, out, visited);
}
ty::CoroutineClosure(_, args) => {
let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty();
compute_components_for_ty(tcx, tupled_ty, out, visited);
}
ty::Coroutine(_, args) => {
// Same as the closure case
let tupled_ty = args.as_coroutine().tupled_upvars_ty();
compute_components_for_ty(tcx, tupled_ty, out, visited);
// We ignore regions in the coroutine interior as we don't
// want these to affect region inference
}
// All regions are bound inside a witness, and we don't emit
// higher-ranked outlives components currently.
ty::CoroutineWitness(..) => {},
// OutlivesTypeParameterEnv -- the actual checking that `X:'a`
// is implied by the environment is done in regionck.
ty::Param(p) => {
out.push(Component::Param(p));
}
ty::Placeholder(p) => {
out.push(Component::Placeholder(p));
}
// For projections, we prefer to generate an obligation like
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
// regionck more ways to prove that it holds. However,
// regionck is not (at least currently) prepared to deal with
// higher-ranked regions that may appear in the
// trait-ref. Therefore, if we see any higher-ranked regions,
// we simply fallback to the most restrictive rule, which
// requires that `Pi: 'a` for all `i`.
ty::Alias(_, alias_ty) => {
if !alias_ty.has_escaping_bound_vars() {
// best case: no escaping regions, so push the
// projection and skip the subtree (thus generating no
// constraints for Pi). This defers the choice between
// the rules OutlivesProjectionEnv,
// OutlivesProjectionTraitDef, and
// OutlivesProjectionComponents to regionck.
out.push(Component::Alias(alias_ty));
} else {
// fallback case: hard code
// OutlivesProjectionComponents. Continue walking
// through and constrain Pi.
let mut subcomponents = smallvec![];
let mut subvisited = SsoHashSet::new();
compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited);
out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
}
}
// We assume that inference variables are fully resolved.
// So, if we encounter an inference variable, just record
// the unresolved variable as a component.
ty::Infer(infer_ty) => {
out.push(Component::UnresolvedInferenceVariable(infer_ty));
}
// Most types do not introduce any region binders, nor
// involve any other subtle cases, and so the WF relation
// simply constraints any regions referenced directly by
// the type and then visits the types that are lexically
// contained within. (The comments refer to relevant rules
// from RFC1214.)
ty::Bool | // OutlivesScalar
ty::Char | // OutlivesScalar
ty::Int(..) | // OutlivesScalar
ty::Uint(..) | // OutlivesScalar
ty::Float(..) | // OutlivesScalar
ty::Never | // OutlivesScalar
ty::Foreign(..) | // OutlivesNominalType
ty::Str | // OutlivesScalar (ish)
ty::Bound(..) |
ty::Error(_) => {
// Trivial.
}
// OutlivesNominalType
ty::Adt(_, args) => {
for arg in args.iter() {
compute_components_for_arg(tcx, arg, out, visited);
}
}
// OutlivesNominalType
ty::Slice(ty) |
ty::RawPtr(ty, _) => {
compute_components_for_ty(tcx, ty, out, visited);
}
ty::Tuple(tys) => {
for ty in tys.iter() {
compute_components_for_ty(tcx, ty, out, visited);
}
}
// OutlivesReference
ty::Ref(lt, ty, _) => {
compute_components_for_lt(lt, out);
compute_components_for_ty(tcx, ty, out, visited);
}
ty::Dynamic(preds, lt, _) => {
compute_components_for_lt(lt, out);
for pred in preds.iter() {
match pred.skip_binder() {
ty::ExistentialPredicate::Trait(tr) => {
for arg in tr.args.iter() {
compute_components_for_arg(tcx, arg, out, visited);
}
}
ty::ExistentialPredicate::Projection(proj) => {
for arg in proj.args.iter() {
compute_components_for_arg(tcx, arg, out, visited);
}
match proj.term.kind() {
ty::TermKind::Ty(ty) => {
compute_components_for_ty(tcx, ty, out, visited)
}
ty::TermKind::Const(ct) => {
compute_components_for_const(tcx, ct, out, visited)
}
}
}
ty::ExistentialPredicate::AutoTrait(..) => {}
}
}
}
ty::FnPtr(sig) => {
for ty in sig.skip_binder().inputs_and_output.iter() {
compute_components_for_ty(tcx, ty, out, visited);
}
}
}
}
/// Collect [Component]s for *all* the args of `parent`.
///
/// This should not be used to get the components of `parent` itself.
/// Use [push_outlives_components] instead.
pub fn compute_alias_components_recursive<I: Interner>(
tcx: I,
alias_ty: I::Ty,
out: &mut SmallVec<[Component<I>; 4]>,
visited: &mut SsoHashSet<I::GenericArg>,
) {
let ty::Alias(kind, alias_ty) = alias_ty.kind() else {
unreachable!("can only call `compute_alias_components_recursive` on an alias type")
};
let opt_variances =
if kind == ty::Opaque { Some(tcx.variances_of(alias_ty.def_id)) } else { None };
for (index, child) in alias_ty.args.iter().enumerate() {
if opt_variances.and_then(|variances| variances.get(index)) == Some(ty::Bivariant) {
continue;
}
compute_components_for_arg(tcx, child, out, visited);
}
}
fn compute_components_for_lt<I: Interner>(lt: I::Region, out: &mut SmallVec<[Component<I>; 4]>) {
if !lt.is_bound() {
out.push(Component::Region(lt));
}
}
fn compute_components_for_const<I: Interner>(
tcx: I,
ct: I::Const,
out: &mut SmallVec<[Component<I>; 4]>,
visited: &mut SsoHashSet<I::GenericArg>,
) {
if !visited.insert(ct.into()) {
return;
}
match ct.kind() {
ty::ConstKind::Param(_)
| ty::ConstKind::Bound(_, _)
| ty::ConstKind::Infer(_)
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Error(_) => {
// Trivial
}
ty::ConstKind::Expr(e) => {
for arg in e.args().iter() {
compute_components_for_arg(tcx, arg, out, visited);
}
}
ty::ConstKind::Value(ty, _) => {
compute_components_for_ty(tcx, ty, out, visited);
}
ty::ConstKind::Unevaluated(uv) => {
for arg in uv.args.iter() {
compute_components_for_arg(tcx, arg, out, visited);
}
}
}
}

View File

@ -1,17 +1,3 @@
error[E0311]: the parameter type `U` may not live long enough
--> $DIR/async-generics-and-bounds.rs:9:5
|
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
| ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | the parameter type `U` must be valid for the anonymous lifetime as defined here...
| ...so that the reference type `&(T, U)` does not outlive the data it points at
|
help: consider adding an explicit lifetime bound
|
LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, U: 'a;
| ++++ ++ ++ +++++++
error[E0311]: the parameter type `T` may not live long enough error[E0311]: the parameter type `T` may not live long enough
--> $DIR/async-generics-and-bounds.rs:9:5 --> $DIR/async-generics-and-bounds.rs:9:5
| |
@ -26,6 +12,20 @@ help: consider adding an explicit lifetime bound
LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, T: 'a; LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, T: 'a;
| ++++ ++ ++ +++++++ | ++++ ++ ++ +++++++
error[E0311]: the parameter type `U` may not live long enough
--> $DIR/async-generics-and-bounds.rs:9:5
|
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
| ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | the parameter type `U` must be valid for the anonymous lifetime as defined here...
| ...so that the reference type `&(T, U)` does not outlive the data it points at
|
help: consider adding an explicit lifetime bound
|
LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, U: 'a;
| ++++ ++ ++ +++++++
error: aborting due to 2 previous errors error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0311`. For more information about this error, try `rustc --explain E0311`.

View File

@ -1,17 +1,3 @@
error[E0311]: the parameter type `U` may not live long enough
--> $DIR/async-generics.rs:6:5
|
LL | async fn foo(&self) -> &(T, U);
| ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^
| | |
| | the parameter type `U` must be valid for the anonymous lifetime as defined here...
| ...so that the reference type `&(T, U)` does not outlive the data it points at
|
help: consider adding an explicit lifetime bound
|
LL | async fn foo<'a>(&'a self) -> &'a (T, U) where U: 'a;
| ++++ ++ ++ +++++++++++
error[E0311]: the parameter type `T` may not live long enough error[E0311]: the parameter type `T` may not live long enough
--> $DIR/async-generics.rs:6:5 --> $DIR/async-generics.rs:6:5
| |
@ -26,6 +12,20 @@ help: consider adding an explicit lifetime bound
LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: 'a; LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: 'a;
| ++++ ++ ++ +++++++++++ | ++++ ++ ++ +++++++++++
error[E0311]: the parameter type `U` may not live long enough
--> $DIR/async-generics.rs:6:5
|
LL | async fn foo(&self) -> &(T, U);
| ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^
| | |
| | the parameter type `U` must be valid for the anonymous lifetime as defined here...
| ...so that the reference type `&(T, U)` does not outlive the data it points at
|
help: consider adding an explicit lifetime bound
|
LL | async fn foo<'a>(&'a self) -> &'a (T, U) where U: 'a;
| ++++ ++ ++ +++++++++++
error: aborting due to 2 previous errors error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0311`. For more information about this error, try `rustc --explain E0311`.

View File

@ -41,7 +41,7 @@ note: type in trait
LL | fn bar(self) -> Option<()>; LL | fn bar(self) -> Option<()>;
| ^^^^^^^^^^ | ^^^^^^^^^^
= note: expected signature `fn(MyFuture) -> Option<()>` = note: expected signature `fn(MyFuture) -> Option<()>`
found signature `fn(MyFuture)` found signature `fn(MyFuture) -> ()`
help: change the output type to match the trait help: change the output type to match the trait
| |
LL | fn bar(self) -> Option<()> {} LL | fn bar(self) -> Option<()> {}

View File

@ -5,7 +5,7 @@ LL | fn size_of<T>();
| ^ expected `usize`, found `()` | ^ expected `usize`, found `()`
| |
= note: expected signature `extern "rust-intrinsic" fn() -> usize` = note: expected signature `extern "rust-intrinsic" fn() -> usize`
found signature `extern "rust-intrinsic" fn()` found signature `extern "rust-intrinsic" fn() -> ()`
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -92,7 +92,7 @@ LL | extern "rust-call" fn call(self, args: ()) -> () {}
| ^^^^ expected `&Foo`, found `Foo` | ^^^^ expected `&Foo`, found `Foo`
| |
= note: expected signature `extern "rust-call" fn(&Foo, ()) -> _` = note: expected signature `extern "rust-call" fn(&Foo, ()) -> _`
found signature `extern "rust-call" fn(Foo, ())` found signature `extern "rust-call" fn(Foo, ()) -> ()`
help: change the self-receiver type to match the trait help: change the self-receiver type to match the trait
| |
LL | extern "rust-call" fn call(&self, args: ()) -> () {} LL | extern "rust-call" fn call(&self, args: ()) -> () {}
@ -162,7 +162,7 @@ LL | extern "rust-call" fn call_mut(&self, args: ()) -> () {}
| ^^^^^ types differ in mutability | ^^^^^ types differ in mutability
| |
= note: expected signature `extern "rust-call" fn(&mut Bar, ()) -> _` = note: expected signature `extern "rust-call" fn(&mut Bar, ()) -> _`
found signature `extern "rust-call" fn(&Bar, ())` found signature `extern "rust-call" fn(&Bar, ()) -> ()`
help: change the self-receiver type to match the trait help: change the self-receiver type to match the trait
| |
LL | extern "rust-call" fn call_mut(&mut self, args: ()) -> () {} LL | extern "rust-call" fn call_mut(&mut self, args: ()) -> () {}

View File

@ -10,7 +10,7 @@ LL | x = foo::<()>;
| ^^^^^^^^^ expected fn item, found a different fn item | ^^^^^^^^^ expected fn item, found a different fn item
| |
= note: expected fn item `fn(F) -> F {bar::<F>}` = note: expected fn item `fn(F) -> F {bar::<F>}`
found fn item `fn(()) {foo::<()>}` found fn item `fn(()) -> () {foo::<()>}`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:27:9 --> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:27:9
@ -26,7 +26,7 @@ LL | let mut x = bar::<()>;
LL | x = foo::<I>; LL | x = foo::<I>;
| ^^^^^^^^ expected fn item, found a different fn item | ^^^^^^^^ expected fn item, found a different fn item
| |
= note: expected fn item `fn(()) {bar::<()>}` = note: expected fn item `fn(()) -> () {bar::<()>}`
found fn item `fn(I) -> I {foo::<I>}` found fn item `fn(I) -> I {foo::<I>}`
help: use parentheses to call this function help: use parentheses to call this function
| |

View File

@ -35,7 +35,7 @@ note: type in trait
LL | fn method() -> Self::Ty; LL | fn method() -> Self::Ty;
| ^^^^^^^^ | ^^^^^^^^
= note: expected signature `fn() -> <() as compare_method::Trait>::Ty` = note: expected signature `fn() -> <() as compare_method::Trait>::Ty`
found signature `fn()` found signature `fn() -> ()`
note: this item must have the opaque type in its signature in order to be able to register hidden types note: this item must have the opaque type in its signature in order to be able to register hidden types
--> $DIR/in-assoc-type-unconstrained.rs:22:12 --> $DIR/in-assoc-type-unconstrained.rs:22:12
| |

View File

@ -5,7 +5,7 @@ LL | fn fmt(&self, x: &str) -> () { }
| ^^^^ types differ in mutability | ^^^^ types differ in mutability
| |
= note: expected signature `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>` = note: expected signature `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
found signature `fn(&MyType, &str)` found signature `fn(&MyType, &str) -> ()`
help: change the parameter type to match the trait help: change the parameter type to match the trait
| |
LL | fn fmt(&self, x: &mut Formatter<'_>) -> () { } LL | fn fmt(&self, x: &mut Formatter<'_>) -> () { }

View File

@ -5,7 +5,7 @@ LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpi
| ^ expected `isize`, found `()` | ^ expected `isize`, found `()`
| |
= note: expected signature `fn(fn() -> _, _, _, _) -> isize` = note: expected signature `fn(fn() -> _, _, _, _) -> isize`
found signature `fn(fn() -> _, _, _, _)` found signature `fn(fn() -> _, _, _, _) -> ()`
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -0,0 +1,8 @@
fn bar() {}
fn foo(x: i32) -> u32 {
0
}
fn main() {
let b: fn() -> u32 = bar; //~ ERROR mismatched types [E0308]
let f: fn(i32) = foo; //~ ERROR mismatched types [E0308]
}

View File

@ -0,0 +1,25 @@
error[E0308]: mismatched types
--> $DIR/method-output-diff-issue-127263.rs:6:26
|
LL | let b: fn() -> u32 = bar;
| ----------- ^^^ expected fn pointer, found fn item
| |
| expected due to this
|
= note: expected fn pointer `fn() -> u32`
found fn item `fn() -> () {bar}`
error[E0308]: mismatched types
--> $DIR/method-output-diff-issue-127263.rs:7:22
|
LL | let f: fn(i32) = foo;
| ------- ^^^ expected fn pointer, found fn item
| |
| expected due to this
|
= note: expected fn pointer `fn(_) -> ()`
found fn item `fn(_) -> u32 {foo}`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -5,7 +5,7 @@ LL | fn panic(info: PanicInfo) -> () {}
| ^^^^^^^^^ expected `&PanicInfo<'_>`, found `PanicInfo<'_>` | ^^^^^^^^^ expected `&PanicInfo<'_>`, found `PanicInfo<'_>`
| |
= note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !`
found signature `for<'a> fn(PanicInfo<'a>)` found signature `for<'a> fn(PanicInfo<'a>) -> ()`
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -10,7 +10,7 @@ note: type in trait
LL | fn jumbo(&self, x: &usize) -> usize; LL | fn jumbo(&self, x: &usize) -> usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature `fn(&_, &_) -> usize` = note: expected signature `fn(&_, &_) -> usize`
found signature `unsafe fn(&_, &_)` found signature `unsafe fn(&_, &_) -> ()`
error: aborting due to 1 previous error error: aborting due to 1 previous error