Auto merge of #121356 - matthiaskrgr:rollup-d80af2s, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #119203 (Correct the simd_masked_{load,store} intrinsic docs)
 - #121277 (Refactor trait implementations in `core::convert::num`.)
 - #121322 (Don't ICE when hitting overflow limit in fulfillment loop in next solver)
 - #121323 (Don't use raw parameter types in `find_builder_fn`)
 - #121344 (Expand weak alias types before collecting constrained/referenced late bound regions + refactorings)
 - #121350 (Fix stray trait mismatch in `resolve_associated_item` for `AsyncFn`)
 - #121352 (docs: add missing "the" to `str::strip_prefix` doc)

Failed merges:

 - #121340 (bootstrap: apply most of clippy's suggestions)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-02-20 22:55:07 +00:00
commit 2dc0170233
40 changed files with 708 additions and 544 deletions

View File

@ -454,9 +454,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
let late_bound_in_projection_ty =
tcx.collect_constrained_late_bound_regions(&projection_ty);
tcx.collect_constrained_late_bound_regions(projection_ty);
let late_bound_in_term =
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(term));
tcx.collect_referenced_late_bound_regions(trait_ref.rebind(term));
debug!(?late_bound_in_projection_ty);
debug!(?late_bound_in_term);

View File

@ -2678,9 +2678,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// for<'a> fn(&'a String) -> &'a str <-- 'a is ok
let inputs = bare_fn_ty.inputs();
let late_bound_in_args =
tcx.collect_constrained_late_bound_regions(&inputs.map_bound(|i| i.to_owned()));
tcx.collect_constrained_late_bound_regions(inputs.map_bound(|i| i.to_owned()));
let output = bare_fn_ty.output();
let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(output);
self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| {
struct_span_code_err!(

View File

@ -144,7 +144,7 @@ impl<'tcx> InherentCollect<'tcx> {
let id = id.owner_id.def_id;
let item_span = self.tcx.def_span(id);
let self_ty = self.tcx.type_of(id).instantiate_identity();
let self_ty = peel_off_weak_aliases(self.tcx, self_ty);
let self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
match *self_ty.kind() {
ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
ty::Foreign(did) => self.check_def_id(id, self_ty, did),
@ -186,30 +186,3 @@ impl<'tcx> InherentCollect<'tcx> {
}
}
}
/// Peel off all weak alias types in this type until there are none left.
///
/// <div class="warning">
///
/// This assumes that `ty` gets normalized later and that any overflows occurring
/// during said normalization get reported.
///
/// </div>
fn peel_off_weak_aliases<'tcx>(tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> {
let ty::Alias(ty::Weak, _) = ty.kind() else { return ty };
let limit = tcx.recursion_limit();
let mut depth = 0;
while let ty::Alias(ty::Weak, alias) = ty.kind() {
if !limit.value_within_limit(depth) {
let guar = tcx.dcx().delayed_bug("overflow expanding weak alias type");
return Ty::new_error(tcx, guar);
}
ty = tcx.type_of(alias.def_id).instantiate(tcx, alias.args);
depth += 1;
}
ty
}

View File

@ -520,7 +520,7 @@ fn get_new_lifetime_name<'tcx>(
generics: &hir::Generics<'tcx>,
) -> String {
let existing_lifetimes = tcx
.collect_referenced_late_bound_regions(&poly_trait_ref)
.collect_referenced_late_bound_regions(poly_trait_ref)
.into_iter()
.filter_map(|lt| {
if let ty::BoundRegionKind::BrNamed(_, name) = lt {

View File

@ -1,8 +1,8 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
use rustc_type_ir::fold::TypeFoldable;
use std::ops::ControlFlow;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
@ -33,62 +33,47 @@ pub fn parameters_for_impl<'tcx>(
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
) -> FxHashSet<Parameter> {
let vec = match impl_trait_ref {
Some(tr) => parameters_for(tcx, &tr, false),
None => parameters_for(tcx, &impl_self_ty, false),
Some(tr) => parameters_for(tcx, tr, false),
None => parameters_for(tcx, impl_self_ty, false),
};
vec.into_iter().collect()
}
/// If `include_nonconstraining` is false, returns the list of parameters that are
/// constrained by `t` - i.e., the value of each parameter in the list is
/// uniquely determined by `t` (see RFC 447). If it is true, return the list
/// of parameters whose values are needed in order to constrain `ty` - these
/// constrained by `value` - i.e., the value of each parameter in the list is
/// uniquely determined by `value` (see RFC 447). If it is true, return the list
/// of parameters whose values are needed in order to constrain `value` - these
/// differ, with the latter being a superset, in the presence of projections.
pub fn parameters_for<'tcx>(
tcx: TyCtxt<'tcx>,
t: &impl TypeVisitable<TyCtxt<'tcx>>,
value: impl TypeFoldable<TyCtxt<'tcx>>,
include_nonconstraining: bool,
) -> Vec<Parameter> {
let mut collector =
ParameterCollector { tcx, parameters: vec![], include_nonconstraining, depth: 0 };
t.visit_with(&mut collector);
let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining };
let value = if !include_nonconstraining { tcx.expand_weak_alias_tys(value) } else { value };
value.visit_with(&mut collector);
collector.parameters
}
struct ParameterCollector<'tcx> {
tcx: TyCtxt<'tcx>,
struct ParameterCollector {
parameters: Vec<Parameter>,
include_nonconstraining: bool,
depth: usize,
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector<'tcx> {
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
// Projections are not injective in general.
ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _)
if !self.include_nonconstraining =>
{
// Projections are not injective in general.
return ControlFlow::Continue(());
}
ty::Alias(ty::Weak, alias) if !self.include_nonconstraining => {
if !self.tcx.recursion_limit().value_within_limit(self.depth) {
// Other constituent types may still constrain some generic params, consider
// `<T> (Overflow, T)` for example. Therefore we want to continue instead of
// breaking. Only affects diagnostics.
return ControlFlow::Continue(());
}
self.depth += 1;
return ensure_sufficient_stack(|| {
self.tcx
.type_of(alias.def_id)
.instantiate(self.tcx, alias.args)
.visit_with(self)
});
}
ty::Param(data) => {
self.parameters.push(Parameter::from(data));
// All weak alias types should've been expanded beforehand.
ty::Alias(ty::Weak, _) if !self.include_nonconstraining => {
bug!("unexpected weak alias type")
}
ty::Param(param) => self.parameters.push(Parameter::from(param)),
_ => {}
}
@ -224,12 +209,12 @@ pub fn setup_constraining_predicates<'tcx>(
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
// Then the projection only applies if `T` is known, but it still
// does not determine `U`.
let inputs = parameters_for(tcx, &projection.projection_ty, true);
let inputs = parameters_for(tcx, projection.projection_ty, true);
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
if !relies_only_on_inputs {
continue;
}
input_parameters.extend(parameters_for(tcx, &projection.term, false));
input_parameters.extend(parameters_for(tcx, projection.term, false));
} else {
continue;
}

View File

@ -111,7 +111,7 @@ fn enforce_impl_params_are_constrained(
match item.kind {
ty::AssocKind::Type => {
if item.defaultness(tcx).has_value() {
cgp::parameters_for(tcx, &tcx.type_of(def_id).instantiate_identity(), true)
cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true)
} else {
vec![]
}

View File

@ -133,7 +133,7 @@ fn check_always_applicable(
res = res.and(check_constness(tcx, impl1_def_id, impl2_node, span));
res = res.and(check_static_lifetimes(tcx, &parent_args, span));
res = res.and(check_duplicate_params(tcx, impl1_args, &parent_args, span));
res = res.and(check_duplicate_params(tcx, impl1_args, parent_args, span));
res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span));
res
@ -266,15 +266,15 @@ fn unconstrained_parent_impl_args<'tcx>(
continue;
}
unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true));
unconstrained_parameters.extend(cgp::parameters_for(tcx, projection_ty, true));
for param in cgp::parameters_for(tcx, &projected_ty, false) {
for param in cgp::parameters_for(tcx, projected_ty, false) {
if !unconstrained_parameters.contains(&param) {
constrained_params.insert(param.0);
}
}
unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true));
unconstrained_parameters.extend(cgp::parameters_for(tcx, projected_ty, true));
}
}
@ -309,7 +309,7 @@ fn unconstrained_parent_impl_args<'tcx>(
fn check_duplicate_params<'tcx>(
tcx: TyCtxt<'tcx>,
impl1_args: GenericArgsRef<'tcx>,
parent_args: &Vec<GenericArg<'tcx>>,
parent_args: Vec<GenericArg<'tcx>>,
span: Span,
) -> Result<(), ErrorGuaranteed> {
let mut base_params = cgp::parameters_for(tcx, parent_args, true);

View File

@ -34,8 +34,8 @@ use rustc_middle::ty::IsSuggestable;
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::def_id::DefIdSet;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{edit_distance, ExpnKind, FileName, MacroKind, Span};
use rustc_span::{Symbol, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
@ -1597,7 +1597,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter)
.filter_map(|item| {
// Only assoc fns that return `Self`, `Option<Self>` or `Result<Self, _>`.
let ret_ty = self.tcx.fn_sig(item.def_id).skip_binder().output();
let ret_ty = self
.tcx
.fn_sig(item.def_id)
.instantiate(self.tcx, self.fresh_args_for_item(DUMMY_SP, item.def_id))
.output();
let ret_ty = self.tcx.instantiate_bound_regions_with_erased(ret_ty);
let ty::Adt(def, args) = ret_ty.kind() else {
return None;

View File

@ -5,7 +5,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::TyCtxt;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::{self, Binder, Region, Ty, TypeVisitable};
use rustc_middle::ty::{self, Binder, Region, Ty, TypeFoldable};
use rustc_span::Span;
/// Information about the anonymous region we are searching for.
@ -142,10 +142,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
fn includes_region(
&self,
ty: Binder<'tcx, impl TypeVisitable<TyCtxt<'tcx>>>,
ty: Binder<'tcx, impl TypeFoldable<TyCtxt<'tcx>>>,
region: ty::BoundRegionKind,
) -> bool {
let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty);
let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(ty);
// We are only checking is any region meets the condition so order doesn't matter
#[allow(rustc::potential_query_instability)]
late_bound_regions.iter().any(|r| *r == region)

View File

@ -47,7 +47,7 @@ macro_rules! arena_types {
rustc_middle::traits::query::DropckOutlivesResult<'tcx>
>
>,
[] normalize_projection_ty:
[] normalize_canonicalized_projection_ty:
rustc_middle::infer::canonical::Canonical<'tcx,
rustc_middle::infer::canonical::QueryResponse<'tcx,
rustc_middle::traits::query::NormalizationResult<'tcx>

View File

@ -31,7 +31,7 @@ use crate::query::plumbing::{
};
use crate::thir;
use crate::traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
CanonicalAliasGoal, CanonicalPredicateGoal, CanonicalTyGoal,
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution,
};
@ -1938,9 +1938,13 @@ rustc_queries! {
arena_cache
}
/// Do not call this query directly: invoke `normalize` instead.
query normalize_projection_ty(
goal: CanonicalProjectionGoal<'tcx>
/// <div class="warning">
///
/// Do not call this query directly: Invoke `normalize` instead.
///
/// </div>
query normalize_canonicalized_projection_ty(
goal: CanonicalAliasGoal<'tcx>
) -> Result<
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
NoSolution,
@ -1948,9 +1952,13 @@ rustc_queries! {
desc { "normalizing `{}`", goal.value.value }
}
/// Do not call this query directly: invoke `normalize` instead.
query normalize_weak_ty(
goal: CanonicalProjectionGoal<'tcx>
/// <div class="warning">
///
/// Do not call this query directly: Invoke `normalize` instead.
///
/// </div>
query normalize_canonicalized_weak_ty(
goal: CanonicalAliasGoal<'tcx>
) -> Result<
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
NoSolution,
@ -1958,9 +1966,13 @@ rustc_queries! {
desc { "normalizing `{}`", goal.value.value }
}
/// Do not call this query directly: invoke `normalize` instead.
query normalize_inherent_projection_ty(
goal: CanonicalProjectionGoal<'tcx>
/// <div class="warning">
///
/// Do not call this query directly: Invoke `normalize` instead.
///
/// </div>
query normalize_canonicalized_inherent_projection_ty(
goal: CanonicalAliasGoal<'tcx>
) -> Result<
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
NoSolution,

View File

@ -67,7 +67,7 @@ pub mod type_op {
}
}
pub type CanonicalProjectionGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>;
pub type CanonicalAliasGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>;
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
@ -177,10 +177,10 @@ pub struct MethodAutoderefBadTy<'tcx> {
pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
}
/// Result from the `normalize_projection_ty` query.
/// Result of the `normalize_canonicalized_{{,inherent_}projection,weak}_ty` queries.
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
pub struct NormalizationResult<'tcx> {
/// Result of normalization.
/// Result of the normalization.
pub normalized_ty: Ty<'tcx>,
}

View File

@ -181,9 +181,10 @@ impl FlagComputation {
&ty::Alias(kind, data) => {
self.add_flags(match kind {
ty::Weak | ty::Projection => TypeFlags::HAS_TY_PROJECTION,
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
ty::Projection => TypeFlags::HAS_TY_PROJECTION,
ty::Weak => TypeFlags::HAS_TY_WEAK,
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
});
self.add_alias_ty(data);

View File

@ -11,6 +11,7 @@ use crate::ty::{GenericArgKind, GenericArgsRef};
use rustc_apfloat::Float as _;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
@ -867,6 +868,63 @@ impl<'tcx> TyCtxt<'tcx> {
self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param))
}
/// Expand any [weak alias types][weak] contained within the given `value`.
///
/// This should be used over other normalization routines in situations where
/// it's important not to normalize other alias types and where the predicates
/// on the corresponding type alias shouldn't be taken into consideration.
///
/// Whenever possible **prefer not to use this function**! Instead, use standard
/// normalization routines or if feasible don't normalize at all.
///
/// This function comes in handy if you want to mimic the behavior of eager
/// type alias expansion in a localized manner.
///
/// <div class="warning">
/// This delays a bug on overflow! Therefore you need to be certain that the
/// contained types get fully normalized at a later stage. Note that even on
/// overflow all well-behaved weak alias types get expanded correctly, so the
/// result is still useful.
/// </div>
///
/// [weak]: ty::Weak
pub fn expand_weak_alias_tys<T: TypeFoldable<TyCtxt<'tcx>>>(self, value: T) -> T {
value.fold_with(&mut WeakAliasTypeExpander { tcx: self, depth: 0 })
}
/// Peel off all [weak alias types] in this type until there are none left.
///
/// This only expands weak alias types in “head” / outermost positions. It can
/// be used over [expand_weak_alias_tys] as an optimization in situations where
/// one only really cares about the *kind* of the final aliased type but not
/// the types the other constituent types alias.
///
/// <div class="warning">
/// This delays a bug on overflow! Therefore you need to be certain that the
/// type gets fully normalized at a later stage.
/// </div>
///
/// [weak]: ty::Weak
/// [expand_weak_alias_tys]: Self::expand_weak_alias_tys
pub fn peel_off_weak_alias_tys(self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
let ty::Alias(ty::Weak, _) = ty.kind() else { return ty };
let limit = self.recursion_limit();
let mut depth = 0;
while let ty::Alias(ty::Weak, alias) = ty.kind() {
if !limit.value_within_limit(depth) {
let guar = self.dcx().delayed_bug("overflow expanding weak alias type");
return Ty::new_error(self, guar);
}
ty = self.type_of(alias.def_id).instantiate(self, alias.args);
depth += 1;
}
ty
}
}
struct OpaqueTypeExpander<'tcx> {
@ -1002,6 +1060,42 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
}
}
struct WeakAliasTypeExpander<'tcx> {
tcx: TyCtxt<'tcx>,
depth: usize,
}
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for WeakAliasTypeExpander<'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if !ty.has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
return ty;
}
let ty::Alias(ty::Weak, alias) = ty.kind() else {
return ty.super_fold_with(self);
};
if !self.tcx.recursion_limit().value_within_limit(self.depth) {
let guar = self.tcx.dcx().delayed_bug("overflow expanding weak alias type");
return Ty::new_error(self.tcx, guar);
}
self.depth += 1;
ensure_sufficient_stack(|| {
self.tcx.type_of(alias.def_id).instantiate(self.tcx, alias.args).fold_with(self)
})
}
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
if !ct.ty().has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
return ct;
}
ct.super_fold_with(self)
}
}
impl<'tcx> Ty<'tcx> {
/// Returns the `Size` for primitive types (bool, uint, int, char, float).
pub fn primitive_size(self, tcx: TyCtxt<'tcx>) -> Size {

View File

@ -2,6 +2,7 @@ use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sso::SsoHashSet;
use rustc_type_ir::fold::TypeFoldable;
use std::ops::ControlFlow;
pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
@ -109,10 +110,10 @@ impl<'tcx> TyCtxt<'tcx> {
/// variables will also be equated.
pub fn collect_constrained_late_bound_regions<T>(
self,
value: &Binder<'tcx, T>,
value: Binder<'tcx, T>,
) -> FxHashSet<ty::BoundRegionKind>
where
T: TypeVisitable<TyCtxt<'tcx>>,
T: TypeFoldable<TyCtxt<'tcx>>,
{
self.collect_late_bound_regions(value, true)
}
@ -120,24 +121,26 @@ impl<'tcx> TyCtxt<'tcx> {
/// Returns a set of all late-bound regions that appear in `value` anywhere.
pub fn collect_referenced_late_bound_regions<T>(
self,
value: &Binder<'tcx, T>,
value: Binder<'tcx, T>,
) -> FxHashSet<ty::BoundRegionKind>
where
T: TypeVisitable<TyCtxt<'tcx>>,
T: TypeFoldable<TyCtxt<'tcx>>,
{
self.collect_late_bound_regions(value, false)
}
fn collect_late_bound_regions<T>(
self,
value: &Binder<'tcx, T>,
just_constraint: bool,
value: Binder<'tcx, T>,
just_constrained: bool,
) -> FxHashSet<ty::BoundRegionKind>
where
T: TypeVisitable<TyCtxt<'tcx>>,
T: TypeFoldable<TyCtxt<'tcx>>,
{
let mut collector = LateBoundRegionsCollector::new(just_constraint);
let result = value.as_ref().skip_binder().visit_with(&mut collector);
let mut collector = LateBoundRegionsCollector::new(just_constrained);
let value = value.skip_binder();
let value = if just_constrained { self.expand_weak_alias_tys(value) } else { value };
let result = value.visit_with(&mut collector);
assert!(result.is_continue()); // should never have stopped early
collector.regions
}
@ -258,11 +261,7 @@ struct LateBoundRegionsCollector {
impl LateBoundRegionsCollector {
fn new(just_constrained: bool) -> Self {
LateBoundRegionsCollector {
current_index: ty::INNERMOST,
regions: Default::default(),
just_constrained,
}
Self { current_index: ty::INNERMOST, regions: Default::default(), just_constrained }
}
}
@ -278,12 +277,16 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
// if we are only looking for "constrained" region, we have to
// ignore the inputs to a projection, as they may not appear
// in the normalized form
if self.just_constrained {
if let ty::Alias(..) = t.kind() {
return ControlFlow::Continue(());
match t.kind() {
// If we are only looking for "constrained" regions, we have to ignore the
// inputs to a projection as they may not appear in the normalized form.
ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) => {
return ControlFlow::Continue(());
}
// All weak alias types should've been expanded beforehand.
ty::Alias(ty::Weak, _) => bug!("unexpected weak alias type"),
_ => {}
}
}

View File

@ -109,7 +109,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
let mut errors = Vec::new();
for i in 0.. {
if !infcx.tcx.recursion_limit().value_within_limit(i) {
unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
// Only return true errors that we have accumulated while processing;
// keep ambiguities around, *including overflows*, because they shouldn't
// be considered true errors.
return errors;
}
let mut has_changed = false;

View File

@ -101,19 +101,17 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
value: &T,
reveal: Reveal,
) -> bool {
let mut flags = ty::TypeFlags::HAS_TY_PROJECTION
| ty::TypeFlags::HAS_TY_WEAK
| ty::TypeFlags::HAS_TY_INHERENT
| ty::TypeFlags::HAS_CT_PROJECTION;
match reveal {
Reveal::UserFacing => value.has_type_flags(
ty::TypeFlags::HAS_TY_PROJECTION
| ty::TypeFlags::HAS_TY_INHERENT
| ty::TypeFlags::HAS_CT_PROJECTION,
),
Reveal::All => value.has_type_flags(
ty::TypeFlags::HAS_TY_PROJECTION
| ty::TypeFlags::HAS_TY_INHERENT
| ty::TypeFlags::HAS_TY_OPAQUE
| ty::TypeFlags::HAS_CT_PROJECTION,
),
Reveal::UserFacing => {}
Reveal::All => flags |= ty::TypeFlags::HAS_TY_OPAQUE,
}
value.has_type_flags(flags)
}
struct AssocTypeNormalizer<'a, 'b, 'tcx> {
@ -355,8 +353,6 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
let data = data.fold_with(self);
// FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement`
// here like `ty::Projection`?
project::normalize_inherent_projection(
self.selcx,
self.param_env,

View File

@ -1,6 +1,6 @@
//! Code for the 'normalization' query. This consists of a wrapper
//! which folds deeply, invoking the underlying
//! `normalize_projection_ty` query when it encounters projections.
//! `normalize_canonicalized_projection_ty` query when it encounters projections.
use crate::infer::at::At;
use crate::infer::canonical::OriginalQueryValues;
@ -271,9 +271,9 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
let result = match kind {
ty::Projection => tcx.normalize_projection_ty(c_data),
ty::Weak => tcx.normalize_weak_ty(c_data),
ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data),
ty::Weak => tcx.normalize_canonicalized_weak_ty(c_data),
ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data),
kind => unreachable!("did not expect {kind:?} due to match arm above"),
}?;
// We don't expect ambiguity.
@ -308,10 +308,10 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
} else {
result.normalized_ty
};
// `tcx.normalize_projection_ty` may normalize to a type that still has
// unevaluated consts, so keep normalizing here if that's the case.
// Similarly, `tcx.normalize_weak_ty` will only unwrap one layer of type
// and we need to continue folding it to reveal the TAIT behind it.
// `tcx.normalize_canonicalized_projection_ty` may normalize to a type that
// still has unevaluated consts, so keep normalizing here if that's the case.
// Similarly, `tcx.normalize_canonicalized_weak_ty` will only unwrap one layer
// of type and we need to continue folding it to reveal the TAIT behind it.
if res != ty
&& (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Weak)
{

View File

@ -5,7 +5,7 @@ use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::query::{
normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution,
normalize::NormalizationResult, CanonicalAliasGoal, NoSolution,
};
use rustc_trait_selection::traits::{
self, FulfillmentErrorCode, ObligationCause, SelectionContext,
@ -13,18 +13,19 @@ use rustc_trait_selection::traits::{
pub(crate) fn provide(p: &mut Providers) {
*p = Providers {
normalize_projection_ty,
normalize_weak_ty,
normalize_inherent_projection_ty,
normalize_canonicalized_projection_ty,
normalize_canonicalized_weak_ty,
normalize_canonicalized_inherent_projection_ty,
..*p
};
}
fn normalize_projection_ty<'tcx>(
fn normalize_canonicalized_projection_ty<'tcx>(
tcx: TyCtxt<'tcx>,
goal: CanonicalProjectionGoal<'tcx>,
goal: CanonicalAliasGoal<'tcx>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
debug!("normalize_provider(goal={:#?})", goal);
debug!("normalize_canonicalized_projection_ty(goal={:#?})", goal);
tcx.infer_ctxt().enter_canonical_trait_query(
&goal,
|ocx, ParamEnvAnd { param_env, value: goal }| {
@ -61,19 +62,19 @@ fn normalize_projection_ty<'tcx>(
return Err(NoSolution);
}
// FIXME(associated_const_equality): All users of normalize_projection_ty expected
// a type, but there is the possibility it could've been a const now. Maybe change
// it to a Term later?
// FIXME(associated_const_equality): All users of normalize_canonicalized_projection_ty
// expected a type, but there is the possibility it could've been a const now.
// Maybe change it to a Term later?
Ok(NormalizationResult { normalized_ty: answer.ty().unwrap() })
},
)
}
fn normalize_weak_ty<'tcx>(
fn normalize_canonicalized_weak_ty<'tcx>(
tcx: TyCtxt<'tcx>,
goal: CanonicalProjectionGoal<'tcx>,
goal: CanonicalAliasGoal<'tcx>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
debug!("normalize_provider(goal={:#?})", goal);
debug!("normalize_canonicalized_weak_ty(goal={:#?})", goal);
tcx.infer_ctxt().enter_canonical_trait_query(
&goal,
@ -95,11 +96,11 @@ fn normalize_weak_ty<'tcx>(
)
}
fn normalize_inherent_projection_ty<'tcx>(
fn normalize_canonicalized_inherent_projection_ty<'tcx>(
tcx: TyCtxt<'tcx>,
goal: CanonicalProjectionGoal<'tcx>,
goal: CanonicalAliasGoal<'tcx>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
debug!("normalize_provider(goal={:#?})", goal);
debug!("normalize_canonicalized_inherent_projection_ty(goal={:#?})", goal);
tcx.infer_ctxt().enter_canonical_trait_query(
&goal,

View File

@ -246,7 +246,7 @@ fn resolve_associated_item<'tcx>(
span: tcx.def_span(trait_item_id),
})
}
} else if tcx.fn_trait_kind_from_def_id(trait_ref.def_id).is_some() {
} else if let Some(target_kind) = tcx.fn_trait_kind_from_def_id(trait_ref.def_id) {
// FIXME: This doesn't check for malformed libcore that defines, e.g.,
// `trait Fn { fn call_once(&self) { .. } }`. This is mostly for extension
// methods.
@ -265,13 +265,7 @@ fn resolve_associated_item<'tcx>(
}
match *rcvr_args.type_at(0).kind() {
ty::Closure(closure_def_id, args) => {
let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
Some(Instance::resolve_closure(
tcx,
closure_def_id,
args,
trait_closure_kind,
))
Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind))
}
ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)),
@ -324,13 +318,7 @@ fn resolve_associated_item<'tcx>(
}
}
ty::Closure(closure_def_id, args) => {
let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
Some(Instance::resolve_closure(
tcx,
closure_def_id,
args,
trait_closure_kind,
))
Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind))
}
ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)),

View File

@ -69,32 +69,35 @@ bitflags! {
/// Does this have `Projection`?
const HAS_TY_PROJECTION = 1 << 10;
/// Does this have `Inherent`?
const HAS_TY_INHERENT = 1 << 11;
/// Does this have `Weak`?
const HAS_TY_WEAK = 1 << 11;
/// Does this have `Opaque`?
const HAS_TY_OPAQUE = 1 << 12;
/// Does this have `Inherent`?
const HAS_TY_INHERENT = 1 << 13;
/// Does this have `ConstKind::Unevaluated`?
const HAS_CT_PROJECTION = 1 << 13;
const HAS_CT_PROJECTION = 1 << 14;
/// Could this type be normalized further?
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits()
| TypeFlags::HAS_TY_WEAK.bits()
| TypeFlags::HAS_TY_OPAQUE.bits()
| TypeFlags::HAS_TY_INHERENT.bits()
| TypeFlags::HAS_CT_PROJECTION.bits();
/// Is an error type/const reachable?
const HAS_ERROR = 1 << 14;
const HAS_ERROR = 1 << 15;
/// Does this have any region that "appears free" in the type?
/// Basically anything but `ReBound` and `ReErased`.
const HAS_FREE_REGIONS = 1 << 15;
const HAS_FREE_REGIONS = 1 << 16;
/// Does this have any `ReBound` regions?
const HAS_RE_BOUND = 1 << 16;
const HAS_RE_BOUND = 1 << 17;
/// Does this have any `Bound` types?
const HAS_TY_BOUND = 1 << 17;
const HAS_TY_BOUND = 1 << 18;
/// Does this have any `ConstKind::Bound` consts?
const HAS_CT_BOUND = 1 << 18;
const HAS_CT_BOUND = 1 << 19;
/// Does this have any bound variables?
/// Used to check if a global bound is safe to evaluate.
const HAS_BOUND_VARS = TypeFlags::HAS_RE_BOUND.bits()
@ -102,22 +105,22 @@ bitflags! {
| TypeFlags::HAS_CT_BOUND.bits();
/// Does this have any `ReErased` regions?
const HAS_RE_ERASED = 1 << 19;
const HAS_RE_ERASED = 1 << 20;
/// Does this value have parameters/placeholders/inference variables which could be
/// replaced later, in a way that would change the results of `impl` specialization?
const STILL_FURTHER_SPECIALIZABLE = 1 << 20;
const STILL_FURTHER_SPECIALIZABLE = 1 << 21;
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
const HAS_TY_FRESH = 1 << 21;
const HAS_TY_FRESH = 1 << 22;
/// Does this value have `InferConst::Fresh`?
const HAS_CT_FRESH = 1 << 22;
const HAS_CT_FRESH = 1 << 23;
/// Does this have `Coroutine` or `CoroutineWitness`?
const HAS_TY_COROUTINE = 1 << 23;
const HAS_TY_COROUTINE = 1 << 24;
/// Does this have any binders with bound vars (e.g. that need to be anonymized)?
const HAS_BINDER_VARS = 1 << 24;
const HAS_BINDER_VARS = 1 << 25;
}
}

View File

@ -19,7 +19,7 @@ pub trait FloatToInt<Int>: private::Sealed + Sized {
}
macro_rules! impl_float_to_int {
( $Float: ident => $( $Int: ident )+ ) => {
($Float:ty => $($Int:ty),+) => {
#[unstable(feature = "convert_float_to_int", issue = "67057")]
impl private::Sealed for $Float {}
$(
@ -35,14 +35,38 @@ macro_rules! impl_float_to_int {
}
}
impl_float_to_int!(f32 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
impl_float_to_int!(f32 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
impl_float_to_int!(f64 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
// Conversion traits for primitive integer and float types
// Conversions T -> T are covered by a blanket impl and therefore excluded
// Some conversions from and to usize/isize are not implemented due to portability concerns
macro_rules! impl_from {
($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
(bool => $Int:ty $(,)?) => {
impl_from!(
bool => $Int,
#[stable(feature = "from_bool", since = "1.28.0")],
concat!(
"Converts a [`bool`] to [`", stringify!($Int), "`] losslessly.\n",
"The resulting value is `0` for `false` and `1` for `true` values.\n",
"\n",
"# Examples\n",
"\n",
"```\n",
"assert_eq!(", stringify!($Int), "::from(true), 1);\n",
"assert_eq!(", stringify!($Int), "::from(false), 0);\n",
"```\n",
),
);
};
($Small:ty => $Large:ty, #[$attr:meta] $(,)?) => {
impl_from!(
$Small => $Large,
#[$attr],
concat!("Converts [`", stringify!($Small), "`] to [`", stringify!($Large), "`] losslessly."),
);
};
($Small:ty => $Large:ty, #[$attr:meta], $doc:expr $(,)?) => {
#[$attr]
impl From<$Small> for $Large {
// Rustdocs on the impl block show a "[+] show undocumented items" toggle.
@ -54,91 +78,66 @@ macro_rules! impl_from {
}
}
};
($Small: ty, $Large: ty, #[$attr:meta]) => {
impl_from!($Small,
$Large,
#[$attr],
concat!("Converts `",
stringify!($Small),
"` to `",
stringify!($Large),
"` losslessly."));
}
}
macro_rules! impl_from_bool {
($target: ty, #[$attr:meta]) => {
impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `",
stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true`
values.
// boolean -> integer
impl_from!(bool => u8);
impl_from!(bool => u16);
impl_from!(bool => u32);
impl_from!(bool => u64);
impl_from!(bool => u128);
impl_from!(bool => usize);
impl_from!(bool => i8);
impl_from!(bool => i16);
impl_from!(bool => i32);
impl_from!(bool => i64);
impl_from!(bool => i128);
impl_from!(bool => isize);
# Examples
// unsigned integer -> unsigned integer
impl_from!(u8 => u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u8 => u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u8 => u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u8 => u128, #[stable(feature = "i128", since = "1.26.0")]);
impl_from!(u8 => usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u16 => u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u16 => u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u16 => u128, #[stable(feature = "i128", since = "1.26.0")]);
impl_from!(u32 => u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u32 => u128, #[stable(feature = "i128", since = "1.26.0")]);
impl_from!(u64 => u128, #[stable(feature = "i128", since = "1.26.0")]);
```
assert_eq!(", stringify!($target), "::from(true), 1);
assert_eq!(", stringify!($target), "::from(false), 0);
```"));
};
}
// signed integer -> signed integer
impl_from!(i8 => i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(i8 => i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(i8 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(i8 => i128, #[stable(feature = "i128", since = "1.26.0")]);
impl_from!(i8 => isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(i16 => i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(i16 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(i16 => i128, #[stable(feature = "i128", since = "1.26.0")]);
impl_from!(i32 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(i32 => i128, #[stable(feature = "i128", since = "1.26.0")]);
impl_from!(i64 => i128, #[stable(feature = "i128", since = "1.26.0")]);
// Bool -> Any
impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] }
// Unsigned -> Unsigned
impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] }
// Signed -> Signed
impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] }
// Unsigned -> Signed
impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] }
// unsigned integer -> signed integer
impl_from!(u8 => i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u8 => i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u8 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u8 => i128, #[stable(feature = "i128", since = "1.26.0")]);
impl_from!(u16 => i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u16 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u16 => i128, #[stable(feature = "i128", since = "1.26.0")]);
impl_from!(u32 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u32 => i128, #[stable(feature = "i128", since = "1.26.0")]);
impl_from!(u64 => i128, #[stable(feature = "i128", since = "1.26.0")]);
// The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX
// which imply that pointer-sized integers must be at least 16 bits:
// https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4
impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
impl_from!(u16 => usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")]);
impl_from!(u8 => isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")]);
impl_from!(i16 => isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")]);
// RISC-V defines the possibility of a 128-bit address space (RV128).
@ -150,66 +149,54 @@ impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.2
// they fit in the significand, which is 24 bits in f32 and 53 bits in f64.
// Lossy float conversions are not implemented at this time.
// Signed -> Float
impl_from! { i8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
impl_from! { i8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
impl_from! { i16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
impl_from! { i16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
impl_from! { i32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
// signed integer -> float
impl_from!(i8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(i8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(i16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(i16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(i32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
// Unsigned -> Float
impl_from! { u8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
impl_from! { u8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
impl_from! { u16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
impl_from! { u16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
// unsigned integer -> float
impl_from!(u8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(u8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(u16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
// Float -> Float
impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
// float -> float
impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
// bool -> Float
#[stable(feature = "float_from_bool", since = "1.68.0")]
impl From<bool> for f32 {
/// Converts `bool` to `f32` losslessly. The resulting value is positive
/// `0.0` for `false` and `1.0` for `true` values.
///
/// # Examples
/// ```
/// let x: f32 = false.into();
/// assert_eq!(x, 0.0);
/// assert!(x.is_sign_positive());
///
/// let y: f32 = true.into();
/// assert_eq!(y, 1.0);
/// ```
#[inline]
fn from(small: bool) -> Self {
small as u8 as Self
}
}
#[stable(feature = "float_from_bool", since = "1.68.0")]
impl From<bool> for f64 {
/// Converts `bool` to `f64` losslessly. The resulting value is positive
/// `0.0` for `false` and `1.0` for `true` values.
///
/// # Examples
/// ```
/// let x: f64 = false.into();
/// assert_eq!(x, 0.0);
/// assert!(x.is_sign_positive());
///
/// let y: f64 = true.into();
/// assert_eq!(y, 1.0);
/// ```
#[inline]
fn from(small: bool) -> Self {
small as u8 as Self
}
macro_rules! impl_float_from_bool {
($float:ty) => {
#[stable(feature = "float_from_bool", since = "1.68.0")]
impl From<bool> for $float {
#[doc = concat!("Converts a [`bool`] to [`", stringify!($float),"`] losslessly.")]
/// The resulting value is positive `0.0` for `false` and `1.0` for `true` values.
///
/// # Examples
/// ```
#[doc = concat!("let x: ", stringify!($float)," = false.into();")]
/// assert_eq!(x, 0.0);
/// assert!(x.is_sign_positive());
///
#[doc = concat!("let y: ", stringify!($float)," = true.into();")]
/// assert_eq!(y, 1.0);
/// ```
#[inline]
fn from(small: bool) -> Self {
small as u8 as Self
}
}
};
}
// boolean -> float
impl_float_from_bool!(f32);
impl_float_from_bool!(f64);
// no possible bounds violation
macro_rules! try_from_unbounded {
($source:ty, $($target:ty),*) => {$(
macro_rules! impl_try_from_unbounded {
($source:ty => $($target:ty),+) => {$(
#[stable(feature = "try_from", since = "1.34.0")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
@ -226,8 +213,8 @@ macro_rules! try_from_unbounded {
}
// only negative bounds
macro_rules! try_from_lower_bounded {
($source:ty, $($target:ty),*) => {$(
macro_rules! impl_try_from_lower_bounded {
($source:ty => $($target:ty),+) => {$(
#[stable(feature = "try_from", since = "1.34.0")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
@ -248,8 +235,8 @@ macro_rules! try_from_lower_bounded {
}
// unsigned to signed (only positive bound)
macro_rules! try_from_upper_bounded {
($source:ty, $($target:ty),*) => {$(
macro_rules! impl_try_from_upper_bounded {
($source:ty => $($target:ty),+) => {$(
#[stable(feature = "try_from", since = "1.34.0")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
@ -270,8 +257,8 @@ macro_rules! try_from_upper_bounded {
}
// all other cases
macro_rules! try_from_both_bounded {
($source:ty, $($target:ty),*) => {$(
macro_rules! impl_try_from_both_bounded {
($source:ty => $($target:ty),+) => {$(
#[stable(feature = "try_from", since = "1.34.0")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
@ -294,65 +281,66 @@ macro_rules! try_from_both_bounded {
}
macro_rules! rev {
($mac:ident, $source:ty, $($target:ty),*) => {$(
$mac!($target, $source);
($mac:ident, $source:ty => $($target:ty),+) => {$(
$mac!($target => $source);
)*}
}
// intra-sign conversions
try_from_upper_bounded!(u16, u8);
try_from_upper_bounded!(u32, u16, u8);
try_from_upper_bounded!(u64, u32, u16, u8);
try_from_upper_bounded!(u128, u64, u32, u16, u8);
// unsigned integer -> unsigned integer
impl_try_from_upper_bounded!(u16 => u8);
impl_try_from_upper_bounded!(u32 => u8, u16);
impl_try_from_upper_bounded!(u64 => u8, u16, u32);
impl_try_from_upper_bounded!(u128 => u8, u16, u32, u64);
try_from_both_bounded!(i16, i8);
try_from_both_bounded!(i32, i16, i8);
try_from_both_bounded!(i64, i32, i16, i8);
try_from_both_bounded!(i128, i64, i32, i16, i8);
// signed integer -> signed integer
impl_try_from_both_bounded!(i16 => i8);
impl_try_from_both_bounded!(i32 => i8, i16);
impl_try_from_both_bounded!(i64 => i8, i16, i32);
impl_try_from_both_bounded!(i128 => i8, i16, i32, i64);
// unsigned-to-signed
try_from_upper_bounded!(u8, i8);
try_from_upper_bounded!(u16, i8, i16);
try_from_upper_bounded!(u32, i8, i16, i32);
try_from_upper_bounded!(u64, i8, i16, i32, i64);
try_from_upper_bounded!(u128, i8, i16, i32, i64, i128);
// unsigned integer -> signed integer
impl_try_from_upper_bounded!(u8 => i8);
impl_try_from_upper_bounded!(u16 => i8, i16);
impl_try_from_upper_bounded!(u32 => i8, i16, i32);
impl_try_from_upper_bounded!(u64 => i8, i16, i32, i64);
impl_try_from_upper_bounded!(u128 => i8, i16, i32, i64, i128);
// signed-to-unsigned
try_from_lower_bounded!(i8, u8, u16, u32, u64, u128);
try_from_lower_bounded!(i16, u16, u32, u64, u128);
try_from_lower_bounded!(i32, u32, u64, u128);
try_from_lower_bounded!(i64, u64, u128);
try_from_lower_bounded!(i128, u128);
try_from_both_bounded!(i16, u8);
try_from_both_bounded!(i32, u16, u8);
try_from_both_bounded!(i64, u32, u16, u8);
try_from_both_bounded!(i128, u64, u32, u16, u8);
// signed integer -> unsigned integer
impl_try_from_lower_bounded!(i8 => u8, u16, u32, u64, u128);
impl_try_from_both_bounded!(i16 => u8);
impl_try_from_lower_bounded!(i16 => u16, u32, u64, u128);
impl_try_from_both_bounded!(i32 => u8, u16);
impl_try_from_lower_bounded!(i32 => u32, u64, u128);
impl_try_from_both_bounded!(i64 => u8, u16, u32);
impl_try_from_lower_bounded!(i64 => u64, u128);
impl_try_from_both_bounded!(i128 => u8, u16, u32, u64);
impl_try_from_lower_bounded!(i128 => u128);
// usize/isize
try_from_upper_bounded!(usize, isize);
try_from_lower_bounded!(isize, usize);
impl_try_from_upper_bounded!(usize => isize);
impl_try_from_lower_bounded!(isize => usize);
#[cfg(target_pointer_width = "16")]
mod ptr_try_from_impls {
use super::TryFromIntError;
use crate::convert::TryFrom;
try_from_upper_bounded!(usize, u8);
try_from_unbounded!(usize, u16, u32, u64, u128);
try_from_upper_bounded!(usize, i8, i16);
try_from_unbounded!(usize, i32, i64, i128);
impl_try_from_upper_bounded!(usize => u8);
impl_try_from_unbounded!(usize => u16, u32, u64, u128);
impl_try_from_upper_bounded!(usize => i8, i16);
impl_try_from_unbounded!(usize => i32, i64, i128);
try_from_both_bounded!(isize, u8);
try_from_lower_bounded!(isize, u16, u32, u64, u128);
try_from_both_bounded!(isize, i8);
try_from_unbounded!(isize, i16, i32, i64, i128);
impl_try_from_both_bounded!(isize => u8);
impl_try_from_lower_bounded!(isize => u16, u32, u64, u128);
impl_try_from_both_bounded!(isize => i8);
impl_try_from_unbounded!(isize => i16, i32, i64, i128);
rev!(try_from_upper_bounded, usize, u32, u64, u128);
rev!(try_from_lower_bounded, usize, i8, i16);
rev!(try_from_both_bounded, usize, i32, i64, i128);
rev!(impl_try_from_upper_bounded, usize => u32, u64, u128);
rev!(impl_try_from_lower_bounded, usize => i8, i16);
rev!(impl_try_from_both_bounded, usize => i32, i64, i128);
rev!(try_from_upper_bounded, isize, u16, u32, u64, u128);
rev!(try_from_both_bounded, isize, i32, i64, i128);
rev!(impl_try_from_upper_bounded, isize => u16, u32, u64, u128);
rev!(impl_try_from_both_bounded, isize => i32, i64, i128);
}
#[cfg(target_pointer_width = "32")]
@ -360,25 +348,25 @@ mod ptr_try_from_impls {
use super::TryFromIntError;
use crate::convert::TryFrom;
try_from_upper_bounded!(usize, u8, u16);
try_from_unbounded!(usize, u32, u64, u128);
try_from_upper_bounded!(usize, i8, i16, i32);
try_from_unbounded!(usize, i64, i128);
impl_try_from_upper_bounded!(usize => u8, u16);
impl_try_from_unbounded!(usize => u32, u64, u128);
impl_try_from_upper_bounded!(usize => i8, i16, i32);
impl_try_from_unbounded!(usize => i64, i128);
try_from_both_bounded!(isize, u8, u16);
try_from_lower_bounded!(isize, u32, u64, u128);
try_from_both_bounded!(isize, i8, i16);
try_from_unbounded!(isize, i32, i64, i128);
impl_try_from_both_bounded!(isize => u8, u16);
impl_try_from_lower_bounded!(isize => u32, u64, u128);
impl_try_from_both_bounded!(isize => i8, i16);
impl_try_from_unbounded!(isize => i32, i64, i128);
rev!(try_from_unbounded, usize, u32);
rev!(try_from_upper_bounded, usize, u64, u128);
rev!(try_from_lower_bounded, usize, i8, i16, i32);
rev!(try_from_both_bounded, usize, i64, i128);
rev!(impl_try_from_unbounded, usize => u32);
rev!(impl_try_from_upper_bounded, usize => u64, u128);
rev!(impl_try_from_lower_bounded, usize => i8, i16, i32);
rev!(impl_try_from_both_bounded, usize => i64, i128);
rev!(try_from_unbounded, isize, u16);
rev!(try_from_upper_bounded, isize, u32, u64, u128);
rev!(try_from_unbounded, isize, i32);
rev!(try_from_both_bounded, isize, i64, i128);
rev!(impl_try_from_unbounded, isize => u16);
rev!(impl_try_from_upper_bounded, isize => u32, u64, u128);
rev!(impl_try_from_unbounded, isize => i32);
rev!(impl_try_from_both_bounded, isize => i64, i128);
}
#[cfg(target_pointer_width = "64")]
@ -386,195 +374,165 @@ mod ptr_try_from_impls {
use super::TryFromIntError;
use crate::convert::TryFrom;
try_from_upper_bounded!(usize, u8, u16, u32);
try_from_unbounded!(usize, u64, u128);
try_from_upper_bounded!(usize, i8, i16, i32, i64);
try_from_unbounded!(usize, i128);
impl_try_from_upper_bounded!(usize => u8, u16, u32);
impl_try_from_unbounded!(usize => u64, u128);
impl_try_from_upper_bounded!(usize => i8, i16, i32, i64);
impl_try_from_unbounded!(usize => i128);
try_from_both_bounded!(isize, u8, u16, u32);
try_from_lower_bounded!(isize, u64, u128);
try_from_both_bounded!(isize, i8, i16, i32);
try_from_unbounded!(isize, i64, i128);
impl_try_from_both_bounded!(isize => u8, u16, u32);
impl_try_from_lower_bounded!(isize => u64, u128);
impl_try_from_both_bounded!(isize => i8, i16, i32);
impl_try_from_unbounded!(isize => i64, i128);
rev!(try_from_unbounded, usize, u32, u64);
rev!(try_from_upper_bounded, usize, u128);
rev!(try_from_lower_bounded, usize, i8, i16, i32, i64);
rev!(try_from_both_bounded, usize, i128);
rev!(impl_try_from_unbounded, usize => u32, u64);
rev!(impl_try_from_upper_bounded, usize => u128);
rev!(impl_try_from_lower_bounded, usize => i8, i16, i32, i64);
rev!(impl_try_from_both_bounded, usize => i128);
rev!(try_from_unbounded, isize, u16, u32);
rev!(try_from_upper_bounded, isize, u64, u128);
rev!(try_from_unbounded, isize, i32, i64);
rev!(try_from_both_bounded, isize, i128);
rev!(impl_try_from_unbounded, isize => u16, u32);
rev!(impl_try_from_upper_bounded, isize => u64, u128);
rev!(impl_try_from_unbounded, isize => i32, i64);
rev!(impl_try_from_both_bounded, isize => i128);
}
// Conversion traits for non-zero integer types
use crate::num::NonZeroI128;
use crate::num::NonZeroI16;
use crate::num::NonZeroI32;
use crate::num::NonZeroI64;
use crate::num::NonZeroI8;
use crate::num::NonZeroIsize;
use crate::num::NonZeroU128;
use crate::num::NonZeroU16;
use crate::num::NonZeroU32;
use crate::num::NonZeroU64;
use crate::num::NonZeroU8;
use crate::num::NonZeroUsize;
use crate::num::NonZero;
macro_rules! nzint_impl_from {
($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
#[$attr]
impl From<$Small> for $Large {
macro_rules! impl_nonzero_int_from_nonzero_int {
($Small:ty => $Large:ty) => {
#[stable(feature = "nz_int_conv", since = "1.41.0")]
impl From<NonZero<$Small>> for NonZero<$Large> {
// Rustdocs on the impl block show a "[+] show undocumented items" toggle.
// Rustdocs on functions do not.
#[doc = $doc]
#[doc = concat!("Converts <code>[NonZero]\\<[", stringify!($Small), "]></code> ")]
#[doc = concat!("to <code>[NonZero]\\<[", stringify!($Large), "]></code> losslessly.")]
#[inline]
fn from(small: $Small) -> Self {
fn from(small: NonZero<$Small>) -> Self {
// SAFETY: input type guarantees the value is non-zero
unsafe {
Self::new_unchecked(From::from(small.get()))
}
unsafe { Self::new_unchecked(From::from(small.get())) }
}
}
};
($Small: ty, $Large: ty, #[$attr:meta]) => {
nzint_impl_from!($Small,
$Large,
#[$attr],
concat!("Converts `",
stringify!($Small),
"` to `",
stringify!($Large),
"` losslessly."));
}
}
// Non-zero Unsigned -> Non-zero Unsigned
nzint_impl_from! { NonZeroU8, NonZeroU16, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroU32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroUsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU16, NonZeroU32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU16, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU16, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU16, NonZeroUsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU32, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU32, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU64, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
// non-zero unsigned integer -> non-zero unsigned integer
impl_nonzero_int_from_nonzero_int!(u8 => u16);
impl_nonzero_int_from_nonzero_int!(u8 => u32);
impl_nonzero_int_from_nonzero_int!(u8 => u64);
impl_nonzero_int_from_nonzero_int!(u8 => u128);
impl_nonzero_int_from_nonzero_int!(u8 => usize);
impl_nonzero_int_from_nonzero_int!(u16 => u32);
impl_nonzero_int_from_nonzero_int!(u16 => u64);
impl_nonzero_int_from_nonzero_int!(u16 => u128);
impl_nonzero_int_from_nonzero_int!(u16 => usize);
impl_nonzero_int_from_nonzero_int!(u32 => u64);
impl_nonzero_int_from_nonzero_int!(u32 => u128);
impl_nonzero_int_from_nonzero_int!(u64 => u128);
// Non-zero Signed -> Non-zero Signed
nzint_impl_from! { NonZeroI8, NonZeroI16, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI8, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI8, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI8, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI8, NonZeroIsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI16, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI16, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI16, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI16, NonZeroIsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI32, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI32, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI64, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
// non-zero signed integer -> non-zero signed integer
impl_nonzero_int_from_nonzero_int!(i8 => i16);
impl_nonzero_int_from_nonzero_int!(i8 => i32);
impl_nonzero_int_from_nonzero_int!(i8 => i64);
impl_nonzero_int_from_nonzero_int!(i8 => i128);
impl_nonzero_int_from_nonzero_int!(i8 => isize);
impl_nonzero_int_from_nonzero_int!(i16 => i32);
impl_nonzero_int_from_nonzero_int!(i16 => i64);
impl_nonzero_int_from_nonzero_int!(i16 => i128);
impl_nonzero_int_from_nonzero_int!(i16 => isize);
impl_nonzero_int_from_nonzero_int!(i32 => i64);
impl_nonzero_int_from_nonzero_int!(i32 => i128);
impl_nonzero_int_from_nonzero_int!(i64 => i128);
// NonZero UnSigned -> Non-zero Signed
nzint_impl_from! { NonZeroU8, NonZeroI16, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroIsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU16, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU16, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU16, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU32, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU32, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU64, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
// non-zero unsigned -> non-zero signed integer
impl_nonzero_int_from_nonzero_int!(u8 => i16);
impl_nonzero_int_from_nonzero_int!(u8 => i32);
impl_nonzero_int_from_nonzero_int!(u8 => i64);
impl_nonzero_int_from_nonzero_int!(u8 => i128);
impl_nonzero_int_from_nonzero_int!(u8 => isize);
impl_nonzero_int_from_nonzero_int!(u16 => i32);
impl_nonzero_int_from_nonzero_int!(u16 => i64);
impl_nonzero_int_from_nonzero_int!(u16 => i128);
impl_nonzero_int_from_nonzero_int!(u32 => i64);
impl_nonzero_int_from_nonzero_int!(u32 => i128);
impl_nonzero_int_from_nonzero_int!(u64 => i128);
macro_rules! nzint_impl_try_from_int {
($Int: ty, $NonZeroInt: ty, #[$attr:meta], $doc: expr) => {
#[$attr]
impl TryFrom<$Int> for $NonZeroInt {
macro_rules! impl_nonzero_int_try_from_int {
($Int:ty) => {
#[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")]
impl TryFrom<$Int> for NonZero<$Int> {
type Error = TryFromIntError;
// Rustdocs on the impl block show a "[+] show undocumented items" toggle.
// Rustdocs on functions do not.
#[doc = $doc]
#[doc = concat!("Attempts to convert [`", stringify!($Int), "`] ")]
#[doc = concat!("to <code>[NonZero]\\<[", stringify!($Int), "]></code>.")]
#[inline]
fn try_from(value: $Int) -> Result<Self, Self::Error> {
Self::new(value).ok_or(TryFromIntError(()))
}
}
};
($Int: ty, $NonZeroInt: ty, #[$attr:meta]) => {
nzint_impl_try_from_int!($Int,
$NonZeroInt,
#[$attr],
concat!("Attempts to convert `",
stringify!($Int),
"` to `",
stringify!($NonZeroInt),
"`."));
}
}
// Int -> Non-zero Int
nzint_impl_try_from_int! { u8, NonZeroU8, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
nzint_impl_try_from_int! { u16, NonZeroU16, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
nzint_impl_try_from_int! { u32, NonZeroU32, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
nzint_impl_try_from_int! { u64, NonZeroU64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
nzint_impl_try_from_int! { u128, NonZeroU128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
nzint_impl_try_from_int! { usize, NonZeroUsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
nzint_impl_try_from_int! { i8, NonZeroI8, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
nzint_impl_try_from_int! { i16, NonZeroI16, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
nzint_impl_try_from_int! { i32, NonZeroI32, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
nzint_impl_try_from_int! { i64, NonZeroI64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
nzint_impl_try_from_int! { i128, NonZeroI128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
nzint_impl_try_from_int! { isize, NonZeroIsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
// integer -> non-zero integer
impl_nonzero_int_try_from_int!(u8);
impl_nonzero_int_try_from_int!(u16);
impl_nonzero_int_try_from_int!(u32);
impl_nonzero_int_try_from_int!(u64);
impl_nonzero_int_try_from_int!(u128);
impl_nonzero_int_try_from_int!(usize);
impl_nonzero_int_try_from_int!(i8);
impl_nonzero_int_try_from_int!(i16);
impl_nonzero_int_try_from_int!(i32);
impl_nonzero_int_try_from_int!(i64);
impl_nonzero_int_try_from_int!(i128);
impl_nonzero_int_try_from_int!(isize);
macro_rules! nzint_impl_try_from_nzint {
($From:ty => $To:ty, $doc: expr) => {
macro_rules! impl_nonzero_int_try_from_nonzero_int {
($source:ty => $($target:ty),+) => {$(
#[stable(feature = "nzint_try_from_nzint_conv", since = "1.49.0")]
impl TryFrom<$From> for $To {
impl TryFrom<NonZero<$source>> for NonZero<$target> {
type Error = TryFromIntError;
// Rustdocs on the impl block show a "[+] show undocumented items" toggle.
// Rustdocs on functions do not.
#[doc = $doc]
#[doc = concat!("Attempts to convert <code>[NonZero]\\<[", stringify!($source), "]></code> ")]
#[doc = concat!("to <code>[NonZero]\\<[", stringify!($target), "]></code>.")]
#[inline]
fn try_from(value: $From) -> Result<Self, Self::Error> {
TryFrom::try_from(value.get()).map(|v| {
// SAFETY: $From is a NonZero type, so v is not zero.
unsafe { Self::new_unchecked(v) }
})
fn try_from(value: NonZero<$source>) -> Result<Self, Self::Error> {
// SAFETY: Input is guaranteed to be non-zero.
Ok(unsafe { Self::new_unchecked(<$target>::try_from(value.get())?) })
}
}
};
($To:ty: $($From: ty),*) => {$(
nzint_impl_try_from_nzint!(
$From => $To,
concat!(
"Attempts to convert `",
stringify!($From),
"` to `",
stringify!($To),
"`.",
)
);
)*};
}
// Non-zero int -> non-zero unsigned int
nzint_impl_try_from_nzint! { NonZeroU8: NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
nzint_impl_try_from_nzint! { NonZeroU16: NonZeroI8, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
nzint_impl_try_from_nzint! { NonZeroU32: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
nzint_impl_try_from_nzint! { NonZeroU64: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
nzint_impl_try_from_nzint! { NonZeroU128: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroUsize, NonZeroIsize }
nzint_impl_try_from_nzint! { NonZeroUsize: NonZeroI8, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroIsize }
// unsigned non-zero integer -> unsigned non-zero integer
impl_nonzero_int_try_from_nonzero_int!(u16 => u8);
impl_nonzero_int_try_from_nonzero_int!(u32 => u8, u16, usize);
impl_nonzero_int_try_from_nonzero_int!(u64 => u8, u16, u32, usize);
impl_nonzero_int_try_from_nonzero_int!(u128 => u8, u16, u32, u64, usize);
impl_nonzero_int_try_from_nonzero_int!(usize => u8, u16, u32, u64, u128);
// Non-zero int -> non-zero signed int
nzint_impl_try_from_nzint! { NonZeroI8: NonZeroU8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
nzint_impl_try_from_nzint! { NonZeroI16: NonZeroU16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
nzint_impl_try_from_nzint! { NonZeroI32: NonZeroU32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
nzint_impl_try_from_nzint! { NonZeroI64: NonZeroU64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
nzint_impl_try_from_nzint! { NonZeroI128: NonZeroU128, NonZeroUsize, NonZeroIsize }
nzint_impl_try_from_nzint! { NonZeroIsize: NonZeroU16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize }
// signed non-zero integer -> signed non-zero integer
impl_nonzero_int_try_from_nonzero_int!(i16 => i8);
impl_nonzero_int_try_from_nonzero_int!(i32 => i8, i16, isize);
impl_nonzero_int_try_from_nonzero_int!(i64 => i8, i16, i32, isize);
impl_nonzero_int_try_from_nonzero_int!(i128 => i8, i16, i32, i64, isize);
impl_nonzero_int_try_from_nonzero_int!(isize => i8, i16, i32, i64, i128);
// unsigned non-zero integer -> signed non-zero integer
impl_nonzero_int_try_from_nonzero_int!(u8 => i8);
impl_nonzero_int_try_from_nonzero_int!(u16 => i8, i16, isize);
impl_nonzero_int_try_from_nonzero_int!(u32 => i8, i16, i32, isize);
impl_nonzero_int_try_from_nonzero_int!(u64 => i8, i16, i32, i64, isize);
impl_nonzero_int_try_from_nonzero_int!(u128 => i8, i16, i32, i64, i128, isize);
impl_nonzero_int_try_from_nonzero_int!(usize => i8, i16, i32, i64, i128, isize);
// signed non-zero integer -> unsigned non-zero integer
impl_nonzero_int_try_from_nonzero_int!(i8 => u8, u16, u32, u64, u128, usize);
impl_nonzero_int_try_from_nonzero_int!(i16 => u8, u16, u32, u64, u128, usize);
impl_nonzero_int_try_from_nonzero_int!(i32 => u8, u16, u32, u64, u128, usize);
impl_nonzero_int_try_from_nonzero_int!(i64 => u8, u16, u32, u64, u128, usize);
impl_nonzero_int_try_from_nonzero_int!(i128 => u8, u16, u32, u64, u128, usize);
impl_nonzero_int_try_from_nonzero_int!(isize => u8, u16, u32, u64, u128, usize);

View File

@ -259,12 +259,13 @@ extern "platform-intrinsic" {
///
/// `T` must be a vector.
///
/// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`.
/// `U` must be a pointer to the element type of `T`
///
/// `V` must be a vector of integers with the same length as `T` (but any element size).
///
/// For each element, if the corresponding value in `mask` is `!0`, read the corresponding
/// pointer from `ptr`.
/// pointer offset from `ptr`.
/// The first element is loaded from `ptr`, the second from `ptr.wrapping_offset(1)` and so on.
/// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from
/// `val`.
///
@ -279,12 +280,13 @@ extern "platform-intrinsic" {
///
/// `T` must be a vector.
///
/// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`.
/// `U` must be a pointer to the element type of `T`
///
/// `V` must be a vector of integers with the same length as `T` (but any element size).
///
/// For each element, if the corresponding value in `mask` is `!0`, write the corresponding
/// value in `val` to the pointer.
/// value in `val` to the pointer offset from `ptr`.
/// The first element is written to `ptr`, the second to `ptr.wrapping_offset(1)` and so on.
/// Otherwise if the corresponding value in `mask` is `0`, do nothing.
///
/// # Safety

View File

@ -2192,8 +2192,8 @@ impl str {
/// Returns a string slice with the prefix removed.
///
/// If the string starts with the pattern `prefix`, returns substring after the prefix, wrapped
/// in `Some`. Unlike `trim_start_matches`, this method removes the prefix exactly once.
/// If the string starts with the pattern `prefix`, returns the substring after the prefix,
/// wrapped in `Some`. Unlike `trim_start_matches`, this method removes the prefix exactly once.
///
/// If the string does not start with `prefix`, returns `None`.
///

View File

@ -318,15 +318,14 @@ where
fn extract_for_generics(&self, pred: ty::Clause<'tcx>) -> FxHashSet<GenericParamDef> {
let bound_predicate = pred.kind();
let tcx = self.cx.tcx;
let regions = match bound_predicate.skip_binder() {
ty::ClauseKind::Trait(poly_trait_pred) => {
tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_trait_pred))
}
ty::ClauseKind::Projection(poly_proj_pred) => {
tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_proj_pred))
}
_ => return FxHashSet::default(),
};
let regions =
match bound_predicate.skip_binder() {
ty::ClauseKind::Trait(poly_trait_pred) => tcx
.collect_referenced_late_bound_regions(bound_predicate.rebind(poly_trait_pred)),
ty::ClauseKind::Projection(poly_proj_pred) => tcx
.collect_referenced_late_bound_regions(bound_predicate.rebind(poly_proj_pred)),
_ => return FxHashSet::default(),
};
regions
.into_iter()

View File

@ -0,0 +1,20 @@
//@ edition: 2021
#![feature(async_closure, noop_waker)]
use std::future::Future;
use std::pin::pin;
use std::task::*;
pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
let mut fut = pin!(fut);
// Poll loop, just to test the future...
let ctx = &mut Context::from_waker(Waker::noop());
loop {
match unsafe { fut.as_mut().poll(ctx) } {
Poll::Pending => {}
Poll::Ready(t) => break t,
}
}
}

View File

@ -1,8 +1,11 @@
//@ aux-build:block-on.rs
//@ edition: 2021
//@ build-pass
#![feature(async_fn_traits)]
extern crate block_on;
use std::ops::AsyncFn;
async fn foo() {}
@ -12,5 +15,7 @@ async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 {
}
fn main() {
let fut = call_asyncly(|x| async move { x + 1 });
block_on::block_on(async {
call_asyncly(|x| async move { x + 1 }).await;
});
}

View File

@ -4,6 +4,11 @@ error[E0599]: no function or associated item named `new_undirected` found for st
LL | let ug = Graph::<i32, i32>::new_undirected();
| ^^^^^^^^^^^^^^ function or associated item not found in `Graph<i32, i32>`
|
note: if you're trying to build a new `issue_30123_aux::Graph<i32, i32>`, consider using `issue_30123_aux::Graph::<N, E>::new` which returns `issue_30123_aux::Graph<_, _>`
--> $DIR/auxiliary/issue-30123-aux.rs:14:5
|
LL | pub fn new() -> Self {
| ^^^^^^^^^^^^^^^^^^^^
= note: the function or associated item was found for
- `issue_30123_aux::Graph<N, E, Undirected>`

View File

@ -0,0 +1,15 @@
//@ check-pass
// Weak alias types constrain late-bound regions if their normalized form constrains them.
#![feature(lazy_type_alias)]
#![allow(incomplete_features)]
type Ref<'a> = &'a ();
type FnPtr = for<'a> fn(Ref<'a>) -> &'a (); // OK
type DynCl = dyn for<'a> Fn(Ref<'a>) -> &'a (); // OK
fn map0(_: Ref) -> Ref { &() } // OK
fn map1(_: Ref<'_>) -> Ref<'_> { &() } // OK
fn main() {}

View File

@ -0,0 +1,23 @@
// Weak alias types only constrain late-bound regions if their normalized form constrains them.
#![feature(lazy_type_alias)]
#![allow(incomplete_features)]
type NotInjective<'a> = <() as Discard>::Output<'a>;
type FnPtr0 = for<'a> fn(NotInjective<'a>) -> &'a ();
//~^ ERROR references lifetime `'a`, which is not constrained by the fn input types
type FnPtr1 = for<'a> fn(NotInjectiveEither<'a, ()>) -> NotInjectiveEither<'a, ()>;
//~^ ERROR references lifetime `'a`, which is not constrained by the fn input types
type DynCl = dyn for<'a> Fn(NotInjective<'a>) -> &'a ();
//~^ ERROR references lifetime `'a`, which does not appear in the trait input types
trait Discard { type Output<'a>; }
impl Discard for () { type Output<'_a> = (); }
type NotInjectiveEither<'a, Linchpin> = Linchpin
where
Linchpin: Fn() -> &'a ();
fn main() {}

View File

@ -0,0 +1,22 @@
error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
--> $DIR/unconstrained-late-bound-regions.rs:8:47
|
LL | type FnPtr0 = for<'a> fn(NotInjective<'a>) -> &'a ();
| ^^^^^^
error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
--> $DIR/unconstrained-late-bound-regions.rs:10:57
|
LL | type FnPtr1 = for<'a> fn(NotInjectiveEither<'a, ()>) -> NotInjectiveEither<'a, ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types
--> $DIR/unconstrained-late-bound-regions.rs:12:50
|
LL | type DynCl = dyn for<'a> Fn(NotInjective<'a>) -> &'a ();
| ^^^^^^
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0581, E0582.
For more information about an error, try `rustc --explain E0581`.

View File

@ -1,5 +1,5 @@
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
--> $DIR/unconstrained-param-due-to-overflow.rs:4:6
--> $DIR/unconstrained-params-in-impl-due-to-overflow.rs:4:6
|
LL | impl<T> Loop<T> {}
| ^ unconstrained type parameter

View File

@ -1,5 +1,5 @@
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
--> $DIR/unconstrained-params.rs:4:6
--> $DIR/unconstrained-params-in-impl.rs:4:6
|
LL | impl<T> NotInjective<T> {}
| ^ unconstrained type parameter

View File

@ -0,0 +1,15 @@
//@ compile-flags: -Znext-solver=coherence
#![recursion_limit = "10"]
trait Trait {}
struct W<T: ?Sized>(*const T);
trait TwoW {}
impl<T: ?Sized + TwoW> TwoW for W<W<T>> {}
impl<T: ?Sized + TwoW> Trait for W<T> {}
impl<T: ?Sized + TwoW> Trait for T {}
//~^ ERROR conflicting implementations of trait `Trait` for type `W
fn main() {}

View File

@ -0,0 +1,11 @@
error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
--> $DIR/coherence-fulfill-overflow.rs:12:1
|
LL | impl<T: ?Sized + TwoW> Trait for W<T> {}
| ------------------------------------- first implementation here
LL | impl<T: ?Sized + TwoW> Trait for T {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`.

View File

@ -0,0 +1,6 @@
fn hello<Q>() -> Vec<Q> {
Vec::<Q>::mew()
//~^ ERROR no function or associated item named `mew` found for struct `Vec<Q>` in the current scope
}
fn main() {}

View File

@ -0,0 +1,20 @@
error[E0599]: no function or associated item named `mew` found for struct `Vec<Q>` in the current scope
--> $DIR/bad-builder.rs:2:15
|
LL | Vec::<Q>::mew()
| ^^^
| |
| function or associated item not found in `Vec<Q>`
| help: there is an associated function with a similar name: `new`
|
note: if you're trying to build a new `Vec<Q>` consider using one of the following associated functions:
Vec::<T>::new
Vec::<T>::with_capacity
Vec::<T>::from_raw_parts
Vec::<T, A>::new_in
and 2 others
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.