Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reimplement ~const Trait bounds via a fourth kind of generic param #101900

Closed
wants to merge 13 commits into from
Closed
Prev Previous commit
Next Next commit
Add TypeFoldable impls for effects
  • Loading branch information
oli-obk committed Jan 9, 2023
commit 1cd3a645bd1e1638a683ee0af8e7367d2b40e6bb
7 changes: 7 additions & 0 deletions compiler/rustc_const_eval/src/interpret/util.rs
Original file line number Diff line number Diff line change
@@ -61,6 +61,13 @@ where
_ => c.super_visit_with(self),
}
}

fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow<Self::BreakTy> {
match e.val {
ty::EffectValue::Param { .. } => ControlFlow::Break(FoundParam),
_ => e.super_visit_with(self),
}
}
}

let mut vis = UsedParamsNeedSubstVisitor { tcx };
7 changes: 7 additions & 0 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -1425,6 +1425,13 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
}
c.super_visit_with(self)
}

fn visit_effect(&mut self, c: ty::Effect<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::EffectValue::Param { index } = c.val {
self.params.insert(index);
}
c.super_visit_with(self)
}
}
let mut param_count = CountParams::default();
let has_region = pred.visit_with(&mut param_count).is_break();
7 changes: 7 additions & 0 deletions compiler/rustc_hir_analysis/src/constrained_generic_params.rs
Original file line number Diff line number Diff line change
@@ -93,6 +93,13 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {

c.super_visit_with(self)
}

fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::EffectValue::Param { index } = e.val {
self.parameters.push(Parameter(index));
}
ControlFlow::CONTINUE
}
}

pub fn identify_constrained_generic_params<'tcx>(
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/ty/effect.rs
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ pub struct EffectData<'tcx> {
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, Debug, TyEncodable, TyDecodable)]
#[derive(Copy)]
pub enum EffectValue<'tcx> {
Rigid {
on: bool,
@@ -52,7 +53,7 @@ pub enum EffectValue<'tcx> {
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, Debug, TyEncodable, TyDecodable)]
#[derive(Copy)]
#[derive(Copy, TypeFoldable, TypeVisitable)]
pub enum EffectKind {
/// The opposite of `const`. This effect enables access to `static` variables, the file system,
/// threads, networking, ...
33 changes: 33 additions & 0 deletions compiler/rustc_middle/src/ty/flags.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@ use crate::ty::subst::{GenericArg, GenericArgKind};
use crate::ty::{self, InferConst, Ty, TypeFlags};
use std::slice;

use super::InferEffect;

#[derive(Debug)]
pub struct FlagComputation {
pub flags: TypeFlags,
@@ -34,6 +36,12 @@ impl FlagComputation {
result.flags
}

pub fn for_effect(e: ty::Effect<'_>) -> TypeFlags {
let mut result = FlagComputation::new();
result.add_effect(e);
result.flags
}

fn add_flags(&mut self, flags: TypeFlags) {
self.flags = self.flags | flags;
}
@@ -298,6 +306,31 @@ impl FlagComputation {
}
}

fn add_effect(&mut self, e: ty::Effect<'_>) {
match e.val {
ty::EffectValue::Rigid { .. } => {}
ty::EffectValue::Param { .. } => {
self.add_flags(TypeFlags::HAS_EFFECT_PARAM);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
ty::EffectValue::Infer(infer) => {
match infer {
InferEffect::Fresh(_) => self.add_flags(TypeFlags::HAS_EFFECT_FRESH),
InferEffect::Var(_) => self.add_flags(TypeFlags::HAS_EFFECT_INFER),
}
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
ty::EffectValue::Bound(debruijn, _) => {
self.add_bound_var(debruijn);
}
ty::EffectValue::Placeholder(_) => {
self.add_flags(TypeFlags::HAS_EFFECT_PLACEHOLDER);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
ty::EffectValue::Err(_) => self.add_flags(TypeFlags::HAS_ERROR),
}
}

fn add_const(&mut self, c: ty::Const<'_>) {
self.add_ty(c.ty());
match c.kind() {
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/fold.rs
Original file line number Diff line number Diff line change
@@ -162,6 +162,10 @@ pub trait FallibleTypeFolder<'tcx>: Sized {
c.try_super_fold_with(self)
}

fn try_fold_effect(&mut self, e: ty::Effect<'tcx>) -> Result<ty::Effect<'tcx>, Self::Error> {
e.try_super_fold_with(self)
}

fn try_fold_predicate(
&mut self,
p: ty::Predicate<'tcx>,
53 changes: 53 additions & 0 deletions compiler/rustc_middle/src/ty/structural_impls.rs
Original file line number Diff line number Diff line change
@@ -843,3 +843,56 @@ impl<'tcx> TypeSuperVisitable<'tcx> for ty::UnevaluatedConst<'tcx> {
self.substs.visit_with(visitor)
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::Effect<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.try_fold_effect(self)
}
}

impl<'tcx> TypeVisitable<'tcx> for ty::Effect<'tcx> {
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
visitor.visit_effect(*self)
}
}

impl<'tcx> TypeSuperFoldable<'tcx> for ty::Effect<'tcx> {
fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
let ty::EffectData { val, kind } = *self;
let val = val.try_fold_with(folder)?;
if val != self.val { Ok(folder.tcx().mk_effect(val, kind)) } else { Ok(self) }
}
}

impl<'tcx> TypeSuperVisitable<'tcx> for ty::Effect<'tcx> {
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
let ty::EffectData { val, kind } = &**self;
match kind {
ty::EffectKind::Host => {}
}
val.visit_with(visitor)
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::EffectValue<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
Ok(self)
}
}

impl<'tcx> TypeVisitable<'tcx> for ty::EffectValue<'tcx> {
fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
match self {
ty::EffectValue::Rigid { on: _ }
| ty::EffectValue::Param { .. }
| ty::EffectValue::Infer(_)
| ty::EffectValue::Bound(_, _)
| ty::EffectValue::Placeholder(_)
| ty::EffectValue::Err(_) => {}
}
ControlFlow::CONTINUE
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
}
}
38 changes: 38 additions & 0 deletions compiler/rustc_middle/src/ty/visit.rs
Original file line number Diff line number Diff line change
@@ -217,6 +217,10 @@ pub trait TypeVisitor<'tcx>: Sized {
c.super_visit_with(self)
}

fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow<Self::BreakTy> {
e.super_visit_with(self)
}

fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
p.super_visit_with(self)
}
@@ -542,6 +546,20 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
}
}

fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow<Self::BreakTy> {
// we don't have a `visit_infer_effect` callback, so we have to
// hook in here to catch this case (annoying...), but
// otherwise we do want to remember to visit the rest of the
// effect, as it has types/regions embedded in a lot of other
// places.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't understand that comment 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I copy pasted it from constants without looking at the details

match e.val {
ty::EffectValue::Bound(debruijn, _) if debruijn >= self.outer_index => {
ControlFlow::Break(FoundEscapingVars)
}
_ => e.super_visit_with(self),
}
}

#[inline]
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
if predicate.outer_exclusive_binder() > self.outer_index {
@@ -600,6 +618,16 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
}
}

#[inline]
fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = FlagComputation::for_effect(e);
if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::CONTINUE
}
}

#[inline]
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
if predicate.flags().intersects(self.flags) {
@@ -719,6 +747,16 @@ impl<'tcx> TypeVisitor<'tcx> for MaxUniverse {
c.super_visit_with(self)
}

fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::EffectValue::Placeholder(placeholder) = e.val {
self.max_universe = ty::UniverseIndex::from_u32(
self.max_universe.as_u32().max(placeholder.universe.as_u32()),
);
}

e.super_visit_with(self)
}

fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::RePlaceholder(placeholder) = *r {
self.max_universe = ty::UniverseIndex::from_u32(
32 changes: 32 additions & 0 deletions compiler/rustc_monomorphize/src/polymorphize.rs
Original file line number Diff line number Diff line change
@@ -321,6 +321,21 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
}
}

fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow<Self::BreakTy> {
if !e.has_non_region_param() {
return ControlFlow::CONTINUE;
}

match e.val {
ty::EffectValue::Param { index } => {
debug!(?index);
self.unused_parameters.clear(index);
ControlFlow::CONTINUE
}
_ => e.super_visit_with(self),
}
}

#[instrument(level = "debug", skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if !ty.has_non_region_param() {
@@ -376,6 +391,23 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
}
}

fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow<Self::BreakTy> {
if !e.has_non_region_param() {
return ControlFlow::CONTINUE;
}

match e.val {
ty::EffectValue::Param { index } => {
if self.unused_parameters.contains(index).unwrap_or(false) {
ControlFlow::CONTINUE
} else {
ControlFlow::BREAK
}
}
_ => e.super_visit_with(self),
}
}

#[instrument(level = "debug", skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if !ty.has_non_region_param() {
11 changes: 11 additions & 0 deletions compiler/rustc_trait_selection/src/traits/query/normalize.rs
Original file line number Diff line number Diff line change
@@ -158,6 +158,17 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
_ => ct.super_visit_with(self),
}
}

fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow<Self::BreakTy> {
match e.val {
ty::EffectValue::Bound(debruijn, _) if debruijn >= self.outer_index => {
self.escaping =
self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
ControlFlow::CONTINUE
}
_ => e.super_visit_with(self),
}
}
}

struct QueryNormalizer<'cx, 'tcx> {
18 changes: 18 additions & 0 deletions compiler/rustc_type_ir/src/lib.rs
Original file line number Diff line number Diff line change
@@ -177,6 +177,7 @@ bitflags! {

const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits
| TypeFlags::HAS_RE_PARAM.bits
| TypeFlags::HAS_EFFECT_PARAM.bits
| TypeFlags::HAS_CT_PARAM.bits;

/// Does this have `Infer`?
@@ -190,6 +191,7 @@ bitflags! {
/// inference is required.
const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits
| TypeFlags::HAS_RE_INFER.bits
| TypeFlags::HAS_EFFECT_INFER.bits
| TypeFlags::HAS_CT_INFER.bits;

/// Does this have `Placeholder`?
@@ -207,10 +209,13 @@ bitflags! {
/// that are local to a particular fn
const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits
| TypeFlags::HAS_CT_PARAM.bits
| TypeFlags::HAS_EFFECT_PARAM.bits
| TypeFlags::HAS_TY_INFER.bits
| TypeFlags::HAS_CT_INFER.bits
| TypeFlags::HAS_EFFECT_INFER.bits
| TypeFlags::HAS_TY_PLACEHOLDER.bits
| TypeFlags::HAS_CT_PLACEHOLDER.bits
| TypeFlags::HAS_EFFECT_PLACEHOLDER.bits
// We consider 'freshened' types and constants
// to depend on a particular fn.
// The freshening process throws away information,
@@ -220,6 +225,7 @@ bitflags! {
// which is different from how types/const are freshened.
| TypeFlags::HAS_TY_FRESH.bits
| TypeFlags::HAS_CT_FRESH.bits
| TypeFlags::HAS_EFFECT_FRESH.bits
| TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;

/// Does this have `Projection`?
@@ -265,6 +271,18 @@ bitflags! {

/// Does this value have `InferConst::Fresh`?
const HAS_CT_FRESH = 1 << 21;

/// Does this have `Effect::Param`?
const HAS_EFFECT_PARAM = 1 << 22;

/// Does this have `InferEffect::Fresh`?
const HAS_EFFECT_FRESH = 1 << 23;

/// Does this have `InferEffect::Var`?
const HAS_EFFECT_INFER = 1 << 24;

/// Does this have `Effect::Placeholder`?
const HAS_EFFECT_PLACEHOLDER = 1 << 25;
}
}