Rollup merge of #121344 - fmease:lta-constr-by-input, r=oli-obk
Expand weak alias types before collecting constrained/referenced late bound regions + refactorings Fixes #114220. Follow-up to #120780. r? `@oli-obk`
This commit is contained in:
commit
532b3eacb7
@ -454,9 +454,9 @@ pub(super) fn add_predicates_for_ast_type_binding(
|
||||
// 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 @@ pub fn ty_of_fn(
|
||||
// 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 @@ fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
|
||||
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 @@ fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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);
|
||||
|
@ -5,7 +5,7 @@
|
||||
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 @@ pub(super) fn is_return_type_anon(
|
||||
|
||||
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::thir;
|
||||
use crate::traits::query::{
|
||||
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
|
||||
CanonicalAliasGoal, CanonicalPredicateGoal, CanonicalTyGoal,
|
||||
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
|
||||
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution,
|
||||
};
|
||||
@ -1938,9 +1938,13 @@
|
||||
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 @@
|
||||
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 @@
|
||||
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 fn new(value: T) -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
|
||||
|
||||
&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 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 @@ pub fn with_opt_host_effect_param(
|
||||
|
||||
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 @@ fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'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 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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
/// 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 @@ pub fn collect_constrained_late_bound_regions<T>(
|
||||
/// 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 @@ fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||
}
|
||||
|
||||
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"),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'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 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
||||
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 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
||||
} 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_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 @@
|
||||
|
||||
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,
|
||||
|
@ -69,32 +69,35 @@ pub struct TypeFlags: u32 {
|
||||
|
||||
/// 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 @@ pub struct TypeFlags: u32 {
|
||||
| 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;
|
||||
}
|
||||
}
|
||||
|
@ -318,15 +318,14 @@ fn handle_lifetimes<'cx>(
|
||||
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()
|
||||
|
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
|
Loading…
Reference in New Issue
Block a user