Implement ~const opaques

This commit is contained in:
Michael Goulet 2024-11-19 20:29:01 +00:00
parent 588c4c45d5
commit 5eeaf2ec33
11 changed files with 127 additions and 11 deletions

View File

@ -339,6 +339,8 @@ fn check_opaque_meets_bounds<'tcx>(
let misc_cause = ObligationCause::misc(span, def_id); let misc_cause = ObligationCause::misc(span, def_id);
// FIXME: We should just register the item bounds here, rather than equating. // FIXME: We should just register the item bounds here, rather than equating.
// FIXME(const_trait_impl): When we do that, please make sure to also register
// the `~const` bounds.
match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) { match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
Ok(()) => {} Ok(()) => {}
Err(ty_err) => { Err(ty_err) => {

View File

@ -339,6 +339,10 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
self.tcx.ensure().explicit_item_super_predicates(def_id); self.tcx.ensure().explicit_item_super_predicates(def_id);
self.tcx.ensure().item_bounds(def_id); self.tcx.ensure().item_bounds(def_id);
self.tcx.ensure().item_super_predicates(def_id); self.tcx.ensure().item_super_predicates(def_id);
if self.tcx.is_conditionally_const(def_id) {
self.tcx.ensure().explicit_implied_const_bounds(def_id);
self.tcx.ensure().const_conditions(def_id);
}
intravisit::walk_opaque_ty(self, opaque); intravisit::walk_opaque_ty(self, opaque);
} }
@ -681,6 +685,10 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
tcx.ensure().generics_of(item.owner_id); tcx.ensure().generics_of(item.owner_id);
tcx.ensure().type_of(item.owner_id); tcx.ensure().type_of(item.owner_id);
tcx.ensure().predicates_of(item.owner_id); tcx.ensure().predicates_of(item.owner_id);
if tcx.is_conditionally_const(def_id) {
tcx.ensure().explicit_implied_const_bounds(def_id);
tcx.ensure().const_conditions(def_id);
}
match item.kind { match item.kind {
hir::ForeignItemKind::Fn(..) => { hir::ForeignItemKind::Fn(..) => {
tcx.ensure().codegen_fn_attrs(item.owner_id); tcx.ensure().codegen_fn_attrs(item.owner_id);

View File

@ -958,6 +958,12 @@ pub(super) fn const_conditions<'tcx>(
hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false), hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false),
_ => bug!("const_conditions called on wrong item: {def_id:?}"), _ => bug!("const_conditions called on wrong item: {def_id:?}"),
}, },
Node::OpaqueTy(opaque) => match opaque.origin {
hir::OpaqueTyOrigin::FnReturn { parent, .. } => return tcx.const_conditions(parent),
hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::TyAlias { .. } => {
unreachable!()
}
},
// N.B. Tuple ctors are unconditionally constant. // N.B. Tuple ctors are unconditionally constant.
Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(), Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(),
_ => bug!("const_conditions called on wrong item: {def_id:?}"), _ => bug!("const_conditions called on wrong item: {def_id:?}"),
@ -1033,7 +1039,8 @@ pub(super) fn explicit_implied_const_bounds<'tcx>(
PredicateFilter::SelfConstIfConst, PredicateFilter::SelfConstIfConst,
) )
} }
Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) => { Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. })
| Node::OpaqueTy(_) => {
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst) explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)
} }
_ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"), _ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"),

View File

@ -574,9 +574,8 @@ impl<'tcx> InferCtxt<'tcx> {
// unexpected region errors. // unexpected region errors.
goals.push(Goal::new(tcx, param_env, ty::ClauseKind::WellFormed(hidden_ty.into()))); goals.push(Goal::new(tcx, param_env, ty::ClauseKind::WellFormed(hidden_ty.into())));
let item_bounds = tcx.explicit_item_bounds(def_id); let replace_opaques_in = |clause: ty::Clause<'tcx>, goals: &mut Vec<_>| {
for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) { clause.fold_with(&mut BottomUpFolder {
let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx, tcx,
ty_op: |ty| match *ty.kind() { ty_op: |ty| match *ty.kind() {
// We can't normalize associated types from `rustc_infer`, // We can't normalize associated types from `rustc_infer`,
@ -612,11 +611,31 @@ impl<'tcx> InferCtxt<'tcx> {
}, },
lt_op: |lt| lt, lt_op: |lt| lt,
ct_op: |ct| ct, ct_op: |ct| ct,
}); })
};
let item_bounds = tcx.explicit_item_bounds(def_id);
for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
let predicate = replace_opaques_in(predicate, goals);
// Require that the predicate holds for the concrete type.
debug!(?predicate);
goals.push(Goal::new(self.tcx, param_env, predicate));
}
// If this opaque is being defined and it's conditionally const,
if self.tcx.is_conditionally_const(def_id) {
let item_bounds = tcx.explicit_implied_const_bounds(def_id);
for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
let predicate = replace_opaques_in(
predicate.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe),
goals,
);
// Require that the predicate holds for the concrete type. // Require that the predicate holds for the concrete type.
debug!(?predicate); debug!(?predicate);
goals.push(Goal::new(self.tcx, param_env, predicate)); goals.push(Goal::new(self.tcx, param_env, predicate));
} }
} }
}
} }

View File

@ -1532,6 +1532,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
self.encode_explicit_item_super_predicates(def_id); self.encode_explicit_item_super_predicates(def_id);
record!(self.tables.opaque_ty_origin[def_id] <- self.tcx.opaque_ty_origin(def_id)); record!(self.tables.opaque_ty_origin[def_id] <- self.tcx.opaque_ty_origin(def_id));
self.encode_precise_capturing_args(def_id); self.encode_precise_capturing_args(def_id);
if tcx.is_conditionally_const(def_id) {
record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
<- tcx.explicit_implied_const_bounds(def_id).skip_binder());
}
} }
if tcx.impl_method_has_trait_impl_trait_tys(def_id) if tcx.impl_method_has_trait_impl_trait_tys(def_id)
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)

View File

@ -2117,7 +2117,13 @@ impl<'tcx> TyCtxt<'tcx> {
_ => bug!("unexpected parent item of associated item: {parent_def_id:?}"), _ => bug!("unexpected parent item of associated item: {parent_def_id:?}"),
} }
} }
DefKind::Closure | DefKind::OpaqueTy => { DefKind::OpaqueTy => match self.opaque_ty_origin(def_id) {
hir::OpaqueTyOrigin::FnReturn { parent, .. } => self.is_conditionally_const(parent),
hir::OpaqueTyOrigin::AsyncFn { .. } => false,
// FIXME(const_trait_impl): ATPITs could be conditionally const?
hir::OpaqueTyOrigin::TyAlias { .. } => false,
},
DefKind::Closure => {
// Closures and RPITs will eventually have const conditions // Closures and RPITs will eventually have const conditions
// for `~const` bounds. // for `~const` bounds.
false false

View File

@ -12,5 +12,13 @@ LL | const fn test() -> impl ~const Fn() {
| |
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 2 previous errors error: `~const` can only be applied to `#[const_trait]` traits
--> $DIR/const-closure-parse-not-item.rs:7:25
|
LL | const fn test() -> impl ~const Fn() {
| ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 3 previous errors

View File

@ -0,0 +1,15 @@
error[E0277]: the trait bound `(): const Foo` is not satisfied
--> $DIR/const-opaque.rs:31:18
|
LL | let opaque = bar(());
| ^^^^^^^
error[E0277]: the trait bound `(): const Foo` is not satisfied
--> $DIR/const-opaque.rs:33:5
|
LL | opaque.method();
| ^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,38 @@
//@ revisions: yes no
//@ compile-flags: -Znext-solver
//@[yes] check-pass
#![feature(const_trait_impl)]
#[const_trait]
trait Foo {
fn method(&self);
}
impl<T: ~const Foo> const Foo for (T,) {
fn method(&self) {}
}
#[cfg(yes)]
impl const Foo for () {
fn method(&self) {}
}
#[cfg(no)]
impl Foo for () {
fn method(&self) {}
}
const fn bar<T: ~const Foo>(t: T) -> impl ~const Foo {
(t,)
}
const _: () = {
let opaque = bar(());
//[no]~^ ERROR the trait bound `(): const Foo` is not satisfied
opaque.method();
//[no]~^ ERROR the trait bound `(): const Foo` is not satisfied
std::mem::forget(opaque);
};
fn main() {}

View File

@ -3,6 +3,7 @@
const fn test() -> impl ~const Fn() { const fn test() -> impl ~const Fn() {
//~^ ERROR `~const` can only be applied to `#[const_trait]` traits //~^ ERROR `~const` can only be applied to `#[const_trait]` traits
//~| ERROR `~const` can only be applied to `#[const_trait]` traits //~| ERROR `~const` can only be applied to `#[const_trait]` traits
//~| ERROR `~const` can only be applied to `#[const_trait]` traits
const move || { //~ ERROR const closures are experimental const move || { //~ ERROR const closures are experimental
let sl: &[u8] = b"foo"; let sl: &[u8] = b"foo";

View File

@ -1,5 +1,5 @@
error[E0658]: const closures are experimental error[E0658]: const closures are experimental
--> $DIR/ice-112822-expected-type-for-param.rs:6:5 --> $DIR/ice-112822-expected-type-for-param.rs:7:5
| |
LL | const move || { LL | const move || {
| ^^^^^ | ^^^^^
@ -22,8 +22,16 @@ LL | const fn test() -> impl ~const Fn() {
| |
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `~const` can only be applied to `#[const_trait]` traits
--> $DIR/ice-112822-expected-type-for-param.rs:3:25
|
LL | const fn test() -> impl ~const Fn() {
| ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0015]: cannot call non-const operator in constant functions error[E0015]: cannot call non-const operator in constant functions
--> $DIR/ice-112822-expected-type-for-param.rs:11:17 --> $DIR/ice-112822-expected-type-for-param.rs:12:17
| |
LL | assert_eq!(first, &b'f'); LL | assert_eq!(first, &b'f');
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^
@ -32,7 +40,7 @@ LL | assert_eq!(first, &b'f');
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0015]: cannot call non-const fn `core::panicking::assert_failed::<&u8, &u8>` in constant functions error[E0015]: cannot call non-const fn `core::panicking::assert_failed::<&u8, &u8>` in constant functions
--> $DIR/ice-112822-expected-type-for-param.rs:11:17 --> $DIR/ice-112822-expected-type-for-param.rs:12:17
| |
LL | assert_eq!(first, &b'f'); LL | assert_eq!(first, &b'f');
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^
@ -40,7 +48,7 @@ LL | assert_eq!(first, &b'f');
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 5 previous errors error: aborting due to 6 previous errors
Some errors have detailed explanations: E0015, E0658. Some errors have detailed explanations: E0015, E0658.
For more information about an error, try `rustc --explain E0015`. For more information about an error, try `rustc --explain E0015`.