address review comments

This commit is contained in:
Deadbeef 2024-06-26 16:36:42 +00:00
parent 8b2fac9612
commit 65a0bee0b7
18 changed files with 113 additions and 124 deletions

View File

@ -397,8 +397,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
EffectsRuntime, sym::EffectsRuntime, effects_runtime, Target::Struct, GenericRequirement::None;
EffectsNoRuntime, sym::EffectsNoRuntime, effects_no_runtime, Target::Struct, GenericRequirement::None;
EffectsMaybe, sym::EffectsMaybe, effects_maybe, Target::Struct, GenericRequirement::None;
EffectsMin, sym::EffectsMin, effects_min, Target::Trait, GenericRequirement::None;
EffectsMinOutput, sym::EffectsMinOutput, effects_min_output, Target::AssocTy, GenericRequirement::None;
EffectsIntersection, sym::EffectsIntersection, effects_intersection, Target::Trait, GenericRequirement::None;
EffectsIntersectionOutput, sym::EffectsIntersectionOutput, effects_intersection_output, Target::AssocTy, GenericRequirement::None;
EffectsCompat, sym::EffectsCompat, effects_compat, Target::Trait, GenericRequirement::Exact(1);
EffectsTyCompat, sym::EffectsTyCompat, effects_ty_compat, Target::Trait, GenericRequirement::Exact(1);
}

View File

@ -71,16 +71,19 @@ pub fn push_trait_bound(
}
// For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the
// associated type of `<T as Tr>` and make sure that the effect is compatible.
if let Some(compat_val) = match (tcx.def_kind(defining_def_id), constness) {
let compat_val = match (tcx.def_kind(defining_def_id), constness) {
// FIXME(effects): revisit the correctness of this
(_, ty::BoundConstness::Const) => Some(tcx.consts.false_),
(_, ty::BoundConstness::Const) => tcx.consts.false_,
// body owners that can have trait bounds
(DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => {
Some(tcx.expected_host_effect_param_for_body(defining_def_id))
tcx.expected_host_effect_param_for_body(defining_def_id)
}
(_, ty::BoundConstness::NotConst) => {
tcx.has_attr(bound_trait_ref.def_id(), sym::const_trait).then_some(tcx.consts.true_)
if !tcx.has_attr(bound_trait_ref.def_id(), sym::const_trait) {
return;
}
tcx.consts.true_
}
(
@ -97,8 +100,12 @@ pub fn push_trait_bound(
let ty = bound_trait_ref
.map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args));
// Replace the binder with dummy types/lifetimes. This should work for any
// binder as long as they don't have any bounds e.g. `for<T: Trait>`.
// When the user has written `for<'a, T> X<'a, T>: ~const Foo`, replace the
// binders to dummy ones i.e. `X<'static, ()>` so they can be referenced in
// the `Min` associated type properly (which doesn't allow using `for<>`)
// This should work for any bound variables as long as they don't have any
// bounds e.g. `for<T: Trait>`.
// FIXME(effects) reconsider this approach to allow compatibility with `for<T: Tr>`
let ty = tcx.replace_bound_vars_uncached(
ty,
FnMutDelegate {
@ -128,24 +135,23 @@ pub fn push_trait_bound(
tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered");
return;
}
} {
// create a new projection type `<T as Tr>::Effects`
let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
tcx.dcx().span_delayed_bug(
span,
"`~const` trait bound has no effect assoc yet no errors encountered?",
);
return;
};
let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args);
// make `<T as Tr>::Effects: Compat<runtime>`
let new_trait_ref = ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::EffectsCompat, Some(span)),
[ty::GenericArg::from(self_ty), compat_val.into()],
};
// create a new projection type `<T as Tr>::Effects`
let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
tcx.dcx().span_delayed_bug(
span,
"`~const` trait bound has no effect assoc yet no errors encountered?",
);
self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span));
}
return;
};
let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args);
// make `<T as Tr>::Effects: Compat<runtime>`
let new_trait_ref = ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::EffectsCompat, Some(span)),
[ty::GenericArg::from(self_ty), compat_val.into()],
);
self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span));
}
pub fn push_projection_bound(

View File

@ -137,7 +137,7 @@ pub(super) fn explicit_item_bounds_with_filter(
let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys));
// FIXME(effects) span
let span = tcx.def_span(def_id);
let assoc = tcx.require_lang_item(hir::LangItem::EffectsMinOutput, Some(span));
let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span));
let proj = Ty::new_projection(tcx, assoc, [tup]);
let self_proj = Ty::new_projection(
tcx,

View File

@ -599,8 +599,8 @@ fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem {
TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind,
TraitSolverLangItem::DynMetadata => LangItem::DynMetadata,
TraitSolverLangItem::EffectsMaybe => LangItem::EffectsMaybe,
TraitSolverLangItem::EffectsMin => LangItem::EffectsMin,
TraitSolverLangItem::EffectsMinOutput => LangItem::EffectsMinOutput,
TraitSolverLangItem::EffectsIntersection => LangItem::EffectsIntersection,
TraitSolverLangItem::EffectsIntersectionOutput => LangItem::EffectsIntersectionOutput,
TraitSolverLangItem::EffectsNoRuntime => LangItem::EffectsNoRuntime,
TraitSolverLangItem::EffectsRuntime => LangItem::EffectsRuntime,
TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait,

View File

@ -270,7 +270,7 @@ fn consider_structural_builtin_unsize_candidates(
goal: Goal<I, Self>,
) -> Vec<Candidate<I>>;
fn consider_builtin_effects_min_candidate(
fn consider_builtin_effects_intersection_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
@ -425,8 +425,8 @@ fn assemble_builtin_impl_candidates<G: GoalKind<D>>(
G::consider_builtin_destruct_candidate(self, goal)
} else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) {
G::consider_builtin_transmute_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::EffectsMin) {
G::consider_builtin_effects_min_candidate(self, goal)
} else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::EffectsIntersection) {
G::consider_builtin_effects_intersection_candidate(self, goal)
} else {
Err(NoSolution)
};

View File

@ -865,7 +865,7 @@ fn consider_builtin_transmute_candidate(
panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
}
fn consider_builtin_effects_min_candidate(
fn consider_builtin_effects_intersection_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
@ -903,11 +903,15 @@ fn consider_builtin_effects_min_candidate(
let mut min = ty::EffectKind::Maybe;
for ty in types.iter() {
// We can't find the intersection if the types used are generic.
//
// FIXME(effects) do we want to look at where clauses to get some
// clue for the case where generic types are being used?
let Some(kind) = ty::EffectKind::try_from_ty(cx, ty) else {
return Err(NoSolution);
};
let Some(result) = ty::EffectKind::min(min, kind) else {
let Some(result) = ty::EffectKind::intersection(min, kind) else {
return Err(NoSolution);
};

View File

@ -703,7 +703,7 @@ fn consider_structural_builtin_unsize_candidates(
})
}
fn consider_builtin_effects_min_candidate(
fn consider_builtin_effects_intersection_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
@ -732,7 +732,7 @@ fn consider_builtin_effects_min_candidate(
return Err(NoSolution);
};
let Some(result) = ty::EffectKind::min(min, kind) else {
let Some(result) = ty::EffectKind::intersection(min, kind) else {
return Err(NoSolution);
};

View File

@ -195,9 +195,9 @@
DoubleEndedIterator,
Duration,
EffectsCompat,
EffectsIntersection,
EffectsIntersectionOutput,
EffectsMaybe,
EffectsMin,
EffectsMinOutput,
EffectsNoRuntime,
EffectsRuntime,
EffectsTyCompat,

View File

@ -184,12 +184,10 @@ fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<De
if !tcx.features().effects {
return None;
}
match tcx.def_kind(def_id) {
let (feed, parent_did) = match tcx.def_kind(def_id) {
DefKind::Trait => {
let trait_def_id = def_id;
let Some(attr) = tcx.get_attr(def_id, sym::const_trait) else {
return None;
};
let attr = tcx.get_attr(def_id, sym::const_trait)?;
let span = attr.span;
let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy);
@ -197,8 +195,6 @@ fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<De
let local_def_id = trait_assoc_ty.def_id();
let def_id = local_def_id.to_def_id();
trait_assoc_ty.feed_hir();
// Copy span of the attribute.
trait_assoc_ty.def_ident_span(Some(span));
@ -213,47 +209,20 @@ fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<De
is_effects_desugaring: true,
});
// visibility is public.
trait_assoc_ty.visibility(ty::Visibility::Public);
// No default type
trait_assoc_ty.defaultness(hir::Defaultness::Default { has_value: false });
trait_assoc_ty.is_type_alias_impl_trait(false);
// Copy generics_of of the trait, making the trait as parent.
trait_assoc_ty.generics_of({
let parent_generics = tcx.generics_of(trait_def_id);
let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
ty::Generics {
parent: Some(trait_def_id.to_def_id()),
parent_count,
own_params: vec![],
param_def_id_to_index: parent_generics.param_def_id_to_index.clone(),
has_self: false,
has_late_bound_regions: None,
host_effect_index: parent_generics.host_effect_index,
}
});
trait_assoc_ty.explicit_item_bounds(ty::EarlyBinder::bind(&[]));
trait_assoc_ty.explicit_item_super_predicates(ty::EarlyBinder::bind(&[]));
// There are no inferred outlives for the synthesized associated type.
trait_assoc_ty.inferred_outlives_of(&[]);
Some(def_id)
(trait_assoc_ty, trait_def_id)
}
DefKind::Impl { .. } => {
let impl_def_id = def_id;
let Some(trait_id) = tcx.trait_id_of_impl(def_id.to_def_id()) else { return None };
let trait_id = tcx.trait_id_of_impl(def_id.to_def_id())?;
// first get the DefId of the assoc type on the trait, if there is not,
// then we don't need to generate it on the impl.
let Some(trait_assoc_id) = tcx.associated_type_for_effects(trait_id) else {
return None;
};
let trait_assoc_id = tcx.associated_type_for_effects(trait_id)?;
// FIXME(effects): span
let span = tcx.def_ident_span(def_id).unwrap();
@ -263,8 +232,6 @@ fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<De
let local_def_id = impl_assoc_ty.def_id();
let def_id = local_def_id.to_def_id();
impl_assoc_ty.feed_hir();
impl_assoc_ty.def_ident_span(Some(span));
impl_assoc_ty.associated_item(ty::AssocItem {
@ -278,9 +245,6 @@ fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<De
is_effects_desugaring: true,
});
// visibility is public.
impl_assoc_ty.visibility(ty::Visibility::Public);
// no default value.
impl_assoc_ty.defaultness(hir::Defaultness::Final);
@ -298,36 +262,41 @@ fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<De
ty::GenericArgs::empty(),
)));
// Copy generics_of of the impl, making the impl as parent.
impl_assoc_ty.generics_of({
let parent_generics = tcx.generics_of(impl_def_id);
let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
ty::Generics {
parent: Some(impl_def_id.to_def_id()),
parent_count,
own_params: vec![],
param_def_id_to_index: parent_generics.param_def_id_to_index.clone(),
has_self: false,
has_late_bound_regions: None,
host_effect_index: parent_generics.host_effect_index,
}
});
// impl_assoc_ty.explicit_item_bounds(ty::EarlyBinder::bind(&[]));
impl_assoc_ty.explicit_item_super_predicates(ty::EarlyBinder::bind(&[]));
// There are no inferred outlives for the synthesized associated type.
impl_assoc_ty.inferred_outlives_of(&[]);
Some(def_id)
(impl_assoc_ty, impl_def_id)
}
def_kind => bug!(
"associated_type_for_effects: {:?} should be Trait or Impl but is {:?}",
def_id,
def_kind
),
}
};
feed.feed_hir();
// visibility is public.
feed.visibility(ty::Visibility::Public);
// Copy generics_of of the trait/impl, making the trait/impl as parent.
feed.generics_of({
let parent_generics = tcx.generics_of(parent_did);
let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
ty::Generics {
parent: Some(parent_did.to_def_id()),
parent_count,
own_params: vec![],
param_def_id_to_index: parent_generics.param_def_id_to_index.clone(),
has_self: false,
has_late_bound_regions: None,
host_effect_index: parent_generics.host_effect_index,
}
});
feed.explicit_item_super_predicates(ty::EarlyBinder::bind(&[]));
// There are no inferred outlives for the synthesized associated type.
feed.inferred_outlives_of(&[]);
Some(feed.def_id().to_def_id())
}
/// Given an `fn_def_id` of a trait or a trait implementation:

View File

@ -44,7 +44,10 @@ pub fn to_ty<I: Interner>(self, tcx: I) -> I::Ty {
I::Ty::new_adt(tcx, tcx.adt_def(self.to_def_id(tcx)), Default::default())
}
pub fn min(a: Self, b: Self) -> Option<Self> {
/// Returns an intersection between two effect kinds. If one effect kind
/// is more permissive than the other (e.g. `Maybe` vs `Runtime`), this
/// returns the less permissive effect kind (`Runtime`).
pub fn intersection(a: Self, b: Self) -> Option<Self> {
use EffectKind::*;
match (a, b) {
(Maybe, x) | (x, Maybe) => Some(x),

View File

@ -17,9 +17,9 @@ pub enum TraitSolverLangItem {
Destruct,
DiscriminantKind,
DynMetadata,
EffectsIntersection,
EffectsIntersectionOutput,
EffectsMaybe,
EffectsMin,
EffectsMinOutput,
EffectsNoRuntime,
EffectsRuntime,
FnPtrTrait,

View File

@ -1062,9 +1062,14 @@ impl<T: ?Sized> TyCompat<T> for T {}
impl<T: ?Sized> TyCompat<T> for Maybe {}
impl<T: ?Sized> TyCompat<Maybe> for T {}
#[lang = "EffectsMin"]
pub trait Min {
#[lang = "EffectsMinOutput"]
#[lang = "EffectsIntersection"]
pub trait Intersection {
#[lang = "EffectsIntersectionOutput"]
type Output: ?Sized;
}
// FIXME(effects): remove this after next trait solver lands
impl Intersection for () {
type Output = Maybe;
}
}

View File

@ -104,15 +104,18 @@ fn main() {}
struct D;
/* FIXME(effects)
impl const Drop for D {
fn drop(&mut self) {
todo!();
}
}
*/
// Lint this, since it can be dropped in const contexts
// FIXME(effects)
fn d(this: D) {}
const fn d(this: D) {}
//~^ ERROR: this could be a `const fn`
mod msrv {
struct Foo(*const u8, &'static u8);

View File

@ -161,6 +161,11 @@ error: this could be a `const fn`
|
LL | fn d(this: D) {}
| ^^^^^^^^^^^^^^^^
|
help: make the function `const`
|
LL | const fn d(this: D) {}
| +++++
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const.rs:125:9

View File

@ -126,10 +126,10 @@ impl<T: ?Sized> TyCompat<T> for Maybe {}
#[stable(feature = "minicore", since = "1.0.0")]
impl<T: ?Sized> TyCompat<Maybe> for T {}
#[lang = "EffectsMin"]
#[lang = "EffectsIntersection"]
#[stable(feature = "minicore", since = "1.0.0")]
pub trait Min {
#[lang = "EffectsMinOutput"]
pub trait Intersection {
#[lang = "EffectsIntersectionOutput"]
#[stable(feature = "minicore", since = "1.0.0")]
type Output: ?Sized;
}

View File

@ -1,4 +1,5 @@
//@ check-pass
//@ compile-flags: -Znext-solver
#![allow(incomplete_features)]
#![feature(const_trait_impl, effects)]

View File

@ -1,5 +1,7 @@
// FIXME(effects) check-pass
//@ known-bug: #110395
//@ compile-flags: -Znext-solver
#![allow(incomplete_features)]
#![feature(const_trait_impl, effects)]
#[const_trait]

View File

@ -1,20 +1,11 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/super-traits.rs:3:30
|
LL | #![feature(const_trait_impl, effects)]
| ^^^^^^^
|
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied
--> $DIR/super-traits.rs:21:7
--> $DIR/super-traits.rs:23:7
|
LL | t.a();
| ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}`
|
note: required by a bound in `Foo::a`
--> $DIR/super-traits.rs:5:1
--> $DIR/super-traits.rs:7:1
|
LL | #[const_trait]
| ^^^^^^^^^^^^^^ required by this bound in `Foo::a`
@ -26,6 +17,6 @@ help: consider further restricting the associated type
LL | const fn foo<T: ~const Bar>(t: &T) where Foo::{synthetic#0}: ~const Compat {
| +++++++++++++++++++++++++++++++++++++++
error: aborting due to 1 previous error; 1 warning emitted
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.