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_macros",
"rustc_middle",
"rustc_next_trait_solver",
"rustc_span",
"rustc_target",
"rustc_type_ir",

View File

@ -1,8 +1,9 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
use rustc_infer::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation};
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_infer::infer::relate::{
PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_infer::traits::solve::Goal;
use rustc_infer::traits::Obligation;
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 {
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:
@ -13,7 +14,7 @@ fn foo(a: &mut i32) {
```
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) {}

View File

@ -1,9 +1,9 @@
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::{GenericArg, GenericArgKind};
use rustc_middle::{bug, span_bug};
use rustc_span::Span;
use rustc_type_ir::outlives::{push_outlives_components, Component};
use smallvec::smallvec;
/// 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_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_next_trait_solver = { path = "../rustc_next_trait_solver" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_type_ir = { path = "../rustc_type_ir" }

View File

@ -1168,14 +1168,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let output1 = sig1.output();
let output2 = sig2.output();
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).0.extend(x1.0);
}
if !output2.is_unit() {
if !output2.is_unit() || output_diff {
values.1.push_normal(" -> ");
(values.1).0.extend(x2.0);
}
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::ty;
pub mod components;
pub mod env;
pub mod for_liveness;
pub mod obligations;

View File

@ -59,7 +59,6 @@
//! might later infer `?U` to something like `&'b u32`, which would
//! imply that `'b: 'a`.
use crate::infer::outlives::components::{push_outlives_components, Component};
use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::outlives::verify::VerifyBoundCx;
use crate::infer::resolve::OpportunisticRegionResolver;
@ -75,6 +74,7 @@ use rustc_middle::ty::{
};
use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate};
use rustc_span::DUMMY_SP;
use rustc_type_ir::outlives::{push_outlives_components, Component};
use smallvec::smallvec;
use super::env::OutlivesEnvironment;
@ -291,7 +291,7 @@ where
fn components_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,
components: &[Component<'tcx>],
components: &[Component<TyCtxt<'tcx>>],
region: ty::Region<'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::region_constraints::VerifyIfEq;
use crate::infer::{GenericKind, VerifyBound};
use rustc_data_structures::sso::SsoHashSet;
use rustc_middle::ty::GenericArg;
use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
use rustc_type_ir::outlives::{compute_alias_components_recursive, Component};
use smallvec::smallvec;
@ -139,7 +139,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
fn bound_from_components(
&self,
components: &[Component<'tcx>],
components: &[Component<TyCtxt<'tcx>>],
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> {
let mut bounds = components
@ -158,7 +158,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
fn bound_from_single_component(
&self,
component: &Component<'tcx>,
component: &Component<TyCtxt<'tcx>>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> {
match *component {

View File

@ -18,11 +18,13 @@
//! On success, the LUB/GLB operations return the appropriate bound. The
//! 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::lub::Lub;
use super::type_relating::TypeRelating;
use super::RelateResult;
use super::StructurallyRelateAliases;
use super::{RelateResult, TypeRelation};
use crate::infer::relate;
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
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::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
use rustc_middle::ty::{IntType, UintType};
use rustc_span::Span;
#[derive(Clone)]
pub struct CombineFields<'infcx, 'tcx> {
@ -76,7 +77,7 @@ impl<'tcx> InferCtxt<'tcx> {
b: Ty<'tcx>,
) -> RelateResult<'tcx, Ty<'tcx>>
where
R: PredicateEmittingRelation<'tcx>,
R: PredicateEmittingRelation<InferCtxt<'tcx>>,
{
debug_assert!(!a.has_escaping_bound_vars());
debug_assert!(!b.has_escaping_bound_vars());
@ -171,7 +172,7 @@ impl<'tcx> InferCtxt<'tcx> {
b: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>>
where
R: PredicateEmittingRelation<'tcx>,
R: PredicateEmittingRelation<InferCtxt<'tcx>>,
{
debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
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
/// other usecases (i.e. setting the value of a type var).
#[instrument(level = "debug", skip(self, relation))]
pub fn instantiate_ty_var<R: PredicateEmittingRelation<'tcx>>(
pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
&self,
relation: &mut R,
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.
#[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,
relation: &mut R,
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 {
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
/// "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 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 {
self.fields.trace.span()
}

View File

@ -2,11 +2,13 @@
//! (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).
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::PredicateEmittingRelation;
#[allow(hidden_glob_reexports)]
pub(super) mod combine;
mod generalize;
mod glb;

View File

@ -1,7 +1,7 @@
use super::combine::CombineFields;
use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
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::ty::relate::{
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 {
self.fields.trace.span()
}

View File

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

View File

@ -54,6 +54,13 @@ pub struct Expr<'tcx> {
pub kind: ExprKind,
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> {
pub fn new_binop(
tcx: TyCtxt<'tcx>,

View File

@ -92,6 +92,8 @@ use std::ops::{Bound, Deref};
impl<'tcx> Interner for TyCtxt<'tcx> {
type DefId = DefId;
type LocalDefId = LocalDefId;
type Span = Span;
type GenericArgs = ty::GenericArgsRef<'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>;
/// 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> {
#[inline]
fn relate<R: TypeRelation<TyCtxt<'tcx>>>(

View File

@ -78,23 +78,6 @@ impl<'tcx> GenericArg<'tcx> {
pub fn walk(self) -> TypeWalker<'tcx> {
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> {

View File

@ -6,5 +6,6 @@
pub mod canonicalizer;
pub mod delegate;
pub mod relate;
pub mod resolve;
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 rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::traits::query::OutlivesBound;
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_span::def_id::CRATE_DEF_ID;
use rustc_span::DUMMY_SP;
use rustc_type_ir::outlives::{push_outlives_components, Component};
use smallvec::{smallvec, SmallVec};
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
@ -284,7 +284,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
/// those relationships.
fn implied_bounds_from_components<'tcx>(
sub_region: ty::Region<'tcx>,
sup_components: SmallVec<[Component<'tcx>; 4]>,
sup_components: SmallVec<[Component<TyCtxt<'tcx>>; 4]>,
) -> Vec<OutlivesBound<'tcx>> {
sup_components
.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_static(interner: I) -> Self;
fn is_bound(self) -> bool {
matches!(self.kind(), ty::ReBound(..))
}
}
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>> {
fn count(&self) -> usize;
}

View File

@ -32,6 +32,7 @@ pub trait Interner:
{
type DefId: DefId<Self>;
type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
type Span: Copy + Debug + Hash + Eq;
type GenericArgs: GenericArgs<Self>;
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 BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
type ValueConst: Copy + Debug + Hash + Eq;
type ExprConst: Copy + Debug + Hash + Eq + Relate<Self>;
type ExprConst: ExprConst<Self>;
// Kinds of regions
type Region: Region<Self>;

View File

@ -27,6 +27,7 @@ pub mod inherent;
pub mod ir_print;
pub mod lang_items;
pub mod lift;
pub mod outlives;
pub mod relate;
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
--> $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;
| ++++ ++ ++ +++++++
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
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
--> $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;
| ++++ ++ ++ +++++++++++
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
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<()>;
| ^^^^^^^^^^
= note: expected signature `fn(MyFuture) -> Option<()>`
found signature `fn(MyFuture)`
found signature `fn(MyFuture) -> ()`
help: change the output type to match the trait
|
LL | fn bar(self) -> Option<()> {}

View File

@ -5,7 +5,7 @@ LL | fn size_of<T>();
| ^ expected `usize`, found `()`
|
= 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

View File

@ -92,7 +92,7 @@ LL | extern "rust-call" fn call(self, args: ()) -> () {}
| ^^^^ expected `&Foo`, found `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
|
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
|
= 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
|
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
|
= note: expected fn item `fn(F) -> F {bar::<F>}`
found fn item `fn(()) {foo::<()>}`
found fn item `fn(()) -> () {foo::<()>}`
error[E0308]: mismatched types
--> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:27:9
@ -26,7 +26,7 @@ LL | let mut x = bar::<()>;
LL | x = foo::<I>;
| ^^^^^^^^ 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>}`
help: use parentheses to call this function
|

View File

@ -35,7 +35,7 @@ note: type in trait
LL | fn method() -> Self::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
--> $DIR/in-assoc-type-unconstrained.rs:22:12
|

View File

@ -5,7 +5,7 @@ LL | fn fmt(&self, x: &str) -> () { }
| ^^^^ types differ in mutability
|
= 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
|
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 `()`
|
= note: expected signature `fn(fn() -> _, _, _, _) -> isize`
found signature `fn(fn() -> _, _, _, _)`
found signature `fn(fn() -> _, _, _, _) -> ()`
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<'_>`
|
= 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

View File

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