mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
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:
commit
2dc0170233
@ -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);
|
||||
|
||||
|
@ -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!(
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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![]
|
||||
}
|
||||
|
@ -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(¶m) {
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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>,
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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"),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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)),
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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`.
|
||||
///
|
||||
|
@ -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()
|
||||
|
20
tests/ui/async-await/async-fn/auxiliary/block-on.rs
Normal file
20
tests/ui/async-await/async-fn/auxiliary/block-on.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
@ -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>`
|
||||
|
||||
|
15
tests/ui/lazy-type-alias/constrained-late-bound-regions.rs
Normal file
15
tests/ui/lazy-type-alias/constrained-late-bound-regions.rs
Normal 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() {}
|
23
tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs
Normal file
23
tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs
Normal 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() {}
|
@ -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`.
|
@ -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
|
@ -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
|
15
tests/ui/traits/next-solver/coherence-fulfill-overflow.rs
Normal file
15
tests/ui/traits/next-solver/coherence-fulfill-overflow.rs
Normal 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() {}
|
@ -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`.
|
6
tests/ui/ufcs/bad-builder.rs
Normal file
6
tests/ui/ufcs/bad-builder.rs
Normal 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() {}
|
20
tests/ui/ufcs/bad-builder.stderr
Normal file
20
tests/ui/ufcs/bad-builder.stderr
Normal 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`.
|
Loading…
Reference in New Issue
Block a user