From 37f6e29e0428be0bd8510fd7eec4b6456df3e0fc Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 28 Sep 2022 19:15:04 +0000 Subject: [PATCH 01/13] Introduce effect datastructure --- .../rustc_const_eval/src/util/type_name.rs | 5 ++ .../src/infer/error_reporting/mod.rs | 5 ++ compiler/rustc_lint/src/context.rs | 5 ++ compiler/rustc_middle/src/arena.rs | 1 + compiler/rustc_middle/src/ty/codec.rs | 12 +++ compiler/rustc_middle/src/ty/context.rs | 54 +++++++++++-- compiler/rustc_middle/src/ty/effect.rs | 80 +++++++++++++++++++ compiler/rustc_middle/src/ty/mod.rs | 4 + compiler/rustc_middle/src/ty/print/mod.rs | 10 +++ compiler/rustc_middle/src/ty/print/pretty.rs | 35 ++++++++ compiler/rustc_symbol_mangling/src/legacy.rs | 6 ++ compiler/rustc_symbol_mangling/src/v0.rs | 5 ++ 12 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 compiler/rustc_middle/src/ty/effect.rs diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index c4122f6649814..4c3c93c95e5e4 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -22,6 +22,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { type Type = Self; type DynExistential = Self; type Const = Self; + type Effect = Self; fn tcx(&self) -> TyCtxt<'tcx> { self.tcx @@ -71,6 +72,10 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { self.pretty_print_const(ct, false) } + fn print_effect(self, _: ty::Effect<'tcx>) -> Result { + unimplemented!() + } + fn print_dyn_existential( self, predicates: &'tcx ty::List>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 5c3e9a2d5cccd..5abc19d9b0c53 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -531,6 +531,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { type Type = !; type DynExistential = !; type Const = !; + type Effect = !; fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { self.tcx @@ -555,6 +556,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Err(NonTrivialPath) } + fn print_effect(self, _: ty::Effect<'tcx>) -> Result { + Err(NonTrivialPath) + } + fn path_crate(self, cnum: CrateNum) -> Result { Ok(vec![self.tcx.crate_name(cnum).to_string()]) } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index a16bb7f1a5f47..b7bda58de0936 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1151,6 +1151,7 @@ impl<'tcx> LateContext<'tcx> { type Type = (); type DynExistential = (); type Const = (); + type Effect = (); fn tcx(&self) -> TyCtxt<'tcx> { self.tcx @@ -1175,6 +1176,10 @@ impl<'tcx> LateContext<'tcx> { Ok(()) } + fn print_effect(self, _: ty::Effect<'tcx>) -> Result { + Ok(()) + } + fn path_crate(self, cnum: CrateNum) -> Result { Ok(vec![self.tcx.crate_name(cnum)]) } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 75282f958b53b..2077ba724efe7 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -94,6 +94,7 @@ macro_rules! arena_types { [] tys: rustc_type_ir::WithCachedTypeInfo>, [] predicates: rustc_type_ir::WithCachedTypeInfo>, [] consts: rustc_middle::ty::ConstData<'tcx>, + [] effects: rustc_middle::ty::EffectData<'tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 8cc8286c1dbe6..426cfdde6b1f8 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -139,6 +139,12 @@ impl<'tcx, E: TyEncoder>> Encodable for ty::Const<'tcx> { } } +impl<'tcx, E: TyEncoder>> Encodable for ty::Effect<'tcx> { + fn encode(&self, e: &mut E) { + self.0.0.encode(e); + } +} + impl<'tcx, E: TyEncoder>> Encodable for ConstAllocation<'tcx> { fn encode(&self, e: &mut E) { self.inner().encode(e) @@ -315,6 +321,12 @@ impl<'tcx, D: TyDecoder>> Decodable for ty::Const<'tcx> { } } +impl<'tcx, D: TyDecoder>> Decodable for ty::Effect<'tcx> { + fn decode(decoder: &mut D) -> Self { + decoder.interner().mk_effect_internal(Decodable::decode(decoder)) + } +} + impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] { fn decode(decoder: &mut D) -> &'tcx Self { decoder.interner().arena.alloc_from_iter( diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5de414077a2b1..fef60a08e7568 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -17,11 +17,11 @@ use crate::thir::Thir; use crate::traits; use crate::ty::query::{self, TyCtxtAt}; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, DefIdTree, FloatTy, FloatVar, - FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, - ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, - ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, - Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, DefIdTree, Effect, EffectData, + FloatTy, FloatVar, FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, + List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, + Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, + TypeckResults, UintTy, Visibility, }; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; use rustc_ast as ast; @@ -141,6 +141,7 @@ pub struct CtxtInterners<'tcx> { projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, ConstData<'tcx>>, + effect: InternedSet<'tcx, EffectData<'tcx>>, const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List>, layout: InternedSet<'tcx, LayoutS>, @@ -162,6 +163,7 @@ impl<'tcx> CtxtInterners<'tcx> { projs: Default::default(), place_elems: Default::default(), const_: Default::default(), + effect: Default::default(), const_allocation: Default::default(), bound_variable_kinds: Default::default(), layout: Default::default(), @@ -263,6 +265,12 @@ pub struct CommonTypes<'tcx> { pub trait_object_dummy_self: Ty<'tcx>, } +pub struct CommonEffects<'tcx> { + pub host: ty::Effect<'tcx>, + /// The opposite of `host`. + pub always_const: ty::Effect<'tcx>, +} + pub struct CommonLifetimes<'tcx> { /// `ReStatic` pub re_static: Region<'tcx>, @@ -310,6 +318,26 @@ impl<'tcx> CommonTypes<'tcx> { } } +impl<'tcx> CommonEffects<'tcx> { + fn new(interners: &CtxtInterners<'tcx>) -> Self { + let mk = |val, kind| { + ty::Effect(Interned::new_unchecked( + interners + .effect + .intern(ty::EffectData { val, kind }, |e| { + InternedInSet(interners.arena.alloc(e)) + }) + .0, + )) + }; + + CommonEffects { + host: mk(ty::EffectValue::Rigid { on: true }, ty::EffectKind::Host), + always_const: mk(ty::EffectValue::Rigid { on: false }, ty::EffectKind::Host), + } + } +} + impl<'tcx> CommonLifetimes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonLifetimes<'tcx> { let mk = |r| { @@ -421,6 +449,9 @@ pub struct GlobalCtxt<'tcx> { /// Common types, pre-interned for your convenience. pub types: CommonTypes<'tcx>, + /// Common effects, pre-interned for your convenience. + pub effects: CommonEffects<'tcx>, + /// Common lifetimes, pre-interned for your convenience. pub lifetimes: CommonLifetimes<'tcx>, @@ -609,6 +640,7 @@ impl<'tcx> TyCtxt<'tcx> { let common_types = CommonTypes::new(&interners, s, &untracked); let common_lifetimes = CommonLifetimes::new(&interners); let common_consts = CommonConsts::new(&interners, &common_types); + let common_effects = CommonEffects::new(&interners); GlobalCtxt { sess: s, @@ -620,6 +652,7 @@ impl<'tcx> TyCtxt<'tcx> { prof: s.prof.clone(), types: common_types, lifetimes: common_lifetimes, + effects: common_effects, consts: common_consts, untracked, untracked_resolutions, @@ -1189,6 +1222,7 @@ macro_rules! nop_list_lift { nop_lift! {type_; Ty<'a> => Ty<'tcx>} nop_lift! {region; Region<'a> => Region<'tcx>} nop_lift! {const_; Const<'a> => Const<'tcx>} +nop_lift! {effect; Effect<'a> => Effect<'tcx>} nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>} nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>} @@ -1602,6 +1636,7 @@ macro_rules! direct_interners { direct_interners! { region: mk_region(RegionKind<'tcx>): Region -> Region<'tcx>, const_: mk_const_internal(ConstData<'tcx>): Const -> Const<'tcx>, + effect: mk_effect_internal(EffectData<'tcx>): Effect -> Effect<'tcx>, const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: intern_layout(LayoutS): Layout -> Layout<'tcx>, adt_def: intern_adt_def(AdtDefData): AdtDef -> AdtDef<'tcx>, @@ -1979,6 +2014,15 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_const_internal(ty::ConstData { kind: kind.into(), ty }) } + #[inline] + pub fn mk_effect( + self, + val: impl Into>, + kind: ty::EffectKind, + ) -> Effect<'tcx> { + self.mk_effect_internal(ty::EffectData { val: val.into(), kind }) + } + #[inline] pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> { self.mk_ty_infer(IntVar(v)) diff --git a/compiler/rustc_middle/src/ty/effect.rs b/compiler/rustc_middle/src/ty/effect.rs new file mode 100644 index 0000000000000..f4b5931116ed9 --- /dev/null +++ b/compiler/rustc_middle/src/ty/effect.rs @@ -0,0 +1,80 @@ +use super::Placeholder; +use crate::ty; +use rustc_data_structures::intern::Interned; +use rustc_errors::ErrorGuaranteed; +use rustc_macros::HashStable; +use std::{fmt, marker::PhantomData}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] +#[rustc_pass_by_value] +pub struct Effect<'tcx>(pub Interned<'tcx, EffectData<'tcx>>); + +impl<'tcx> std::ops::Deref for Effect<'tcx> { + type Target = EffectData<'tcx>; + + fn deref(&self) -> &Self::Target { + &self.0.0 + } +} + +impl<'tcx> fmt::Debug for Effect<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.0.fmt(f) + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, Debug, TyEncodable, TyDecodable)] +pub struct EffectData<'tcx> { + pub val: EffectValue<'tcx>, + pub kind: EffectKind, +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, Debug, TyEncodable, TyDecodable)] +pub enum EffectValue<'tcx> { + Rigid { + on: bool, + }, + /// Effect is forwarded from parent generics + Param { + index: u32, + }, + /// Only used during type inference to decide on one of `On`/`Off`/`Param` + Infer(InferEffect<'tcx>), + + /// Bound effect variable, used only when preparing a trait query. + Bound(ty::DebruijnIndex, ty::BoundVar), + + /// A placeholder effect - universally quantified higher-ranked effect. + Placeholder(PlaceholderEffect), + + /// An error occurred. + Err(ErrorGuaranteed), +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, Debug, TyEncodable, TyDecodable)] +#[derive(Copy)] +pub enum EffectKind { + /// The opposite of `const`. This effect enables access to `static` variables, the file system, + /// threads, networking, ... + Host, +} + +/// An inference variable for an effect, for use in effect generics. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] +#[derive(HashStable)] +pub enum InferEffect<'tcx> { + /// Infer the value of the const. + Var(EffectVid<'tcx>), + /// A fresh effect variable. See `infer::freshen` for more details. + Fresh(u32), +} + +/// An **effect** **v**ariable **ID**. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(HashStable, TyEncodable, TyDecodable)] +pub struct EffectVid<'tcx> { + pub index: u32, + pub phantom: PhantomData<&'tcx ()>, +} + +pub type PlaceholderEffect = Placeholder; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f01d74539a12e..57c810a512034 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -86,6 +86,9 @@ pub use self::context::{ tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TyCtxtFeed, }; +pub use self::effect::{ + Effect, EffectData, EffectKind, EffectValue, EffectVid, InferEffect, PlaceholderEffect, +}; pub use self::instance::{Instance, InstanceDef, ShortInstance}; pub use self::list::List; pub use self::parameterized::ParameterizedOverTcx; @@ -136,6 +139,7 @@ mod closure; mod consts; mod context; mod diagnostics; +mod effect; mod erase_regions; mod generics; mod impls_ty; diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 29bad33e4bc0f..456fdaad46fdb 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -36,6 +36,7 @@ pub trait Printer<'tcx>: Sized { type Type; type DynExistential; type Const; + type Effect; fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; @@ -67,6 +68,7 @@ pub trait Printer<'tcx>: Sized { ) -> Result; fn print_const(self, ct: ty::Const<'tcx>) -> Result; + fn print_effect(self, ct: ty::Effect<'tcx>) -> Result; fn path_crate(self, cnum: CrateNum) -> Result; @@ -329,3 +331,11 @@ pub fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { format!("module `{}`", tcx.def_path_str(def_id.to_def_id())) } } + +impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Effect<'tcx> { + type Output = P::Effect; + type Error = P::Error; + fn print(&self, cx: P) -> Result { + cx.print_effect(*self) + } +} diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index c49e75d68ad32..da42eee38dd35 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -213,6 +213,7 @@ pub trait PrettyPrinter<'tcx>: Type = Self, DynExistential = Self, Const = Self, + Effect = Self, > + fmt::Write { /// Like `print_def_path` but for value paths. @@ -1269,6 +1270,34 @@ pub trait PrettyPrinter<'tcx>: Ok(self) } + fn pretty_print_effect(mut self, e: ty::Effect<'tcx>) -> Result { + define_scoped_cx!(self); + + let verbose = self.tcx().sess.verbose(); + + use ty::EffectKind::*; + + match (&e.val, e.kind) { + (ty::EffectValue::Rigid { on: true }, Host) => p!(write("!const")), + (ty::EffectValue::Rigid { on: false }, Host) => p!(write("const")), + + (ty::EffectValue::Param { index }, _) if verbose => p!(write("E/{index}")), + (ty::EffectValue::Param { .. }, Host) => p!(write("~const")), + + (ty::EffectValue::Infer(infer), _) if verbose => match infer { + ty::InferEffect::Var(var) => p!(write("#_{}e", var.index)), + ty::InferEffect::Fresh(fresh) => p!(write("#_fresh{fresh}e")), + }, + (ty::EffectValue::Infer(_), _) => p!(write("_")), + + (ty::EffectValue::Bound(di, bv), _) => p!(write("Bound({di:?}, {bv:?})")), + (ty::EffectValue::Placeholder(ph), _) => p!(write("Placeholder({ph:?})")), + (ty::EffectValue::Err(_), Host) => p!(write("[error effect: host]")), + } + + Ok(self) + } + fn pretty_print_const( mut self, ct: ty::Const<'tcx>, @@ -1787,6 +1816,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { type Type = Self; type DynExistential = Self; type Const = Self; + type Effect = Self; fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { self.tcx @@ -1877,6 +1907,10 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { self.pretty_print_const(ct, false) } + fn print_effect(self, e: ty::Effect<'tcx>) -> Result { + self.pretty_print_effect(e) + } + fn path_crate(mut self, cnum: CrateNum) -> Result { self.empty_path = true; if cnum == LOCAL_CRATE { @@ -2622,6 +2656,7 @@ forward_display_to_print! { Ty<'tcx>, &'tcx ty::List>, ty::Const<'tcx>, + ty::Effect<'tcx>, // HACK(eddyb) these are exhaustive instead of generic, // because `for<'tcx>` isn't possible yet. diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 23ff6b333f0dd..cf1f2cccf9314 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -203,6 +203,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { type Type = Self; type DynExistential = Self; type Const = Self; + type Effect = Self; fn tcx(&self) -> TyCtxt<'tcx> { self.tcx @@ -274,6 +275,11 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { Ok(self) } + fn print_effect(self, _: ty::Effect<'tcx>) -> Result { + self.write_str("_")?; + Ok(self) + } + fn path_crate(self, cnum: CrateNum) -> Result { self.write_str(self.tcx.crate_name(cnum).as_str())?; Ok(self) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 0d446d654dc5c..037753623c25e 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -244,6 +244,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { type Type = Self; type DynExistential = Self; type Const = Self; + type Effect = Self; fn tcx(&self) -> TyCtxt<'tcx> { self.tcx @@ -564,6 +565,10 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { Ok(self) } + fn print_effect(self, _: ty::Effect<'tcx>) -> Result { + unimplemented!() + } + fn print_const(mut self, ct: ty::Const<'tcx>) -> Result { // We only mangle a typed value if the const can be evaluated. let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all()); From 8f57f7ab1af7b23abe81a863ce8cecb2efd8723c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sun, 2 Oct 2022 12:50:15 +0000 Subject: [PATCH 02/13] In the transition period where not all operator traits are const_trait yet (including using keyword generics) reinstate the ICE on malformed operator trait declarations. --- compiler/rustc_hir_typeck/src/lib.rs | 11 --------- compiler/rustc_hir_typeck/src/op.rs | 22 +---------------- compiler/rustc_hir_typeck/src/place_op.rs | 30 +---------------------- 3 files changed, 2 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 99e09b86a2323..26a465ffbf064 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -459,17 +459,6 @@ fn fatally_break_rust(sess: &Session) { )); } -fn has_expected_num_generic_args( - tcx: TyCtxt<'_>, - trait_did: Option, - expected: usize, -) -> bool { - trait_did.map_or(true, |trait_did| { - let generics = tcx.generics_of(trait_did); - generics.count() == expected + if generics.has_self { 1 } else { 0 } - }) -} - pub fn provide(providers: &mut Providers) { method::provide(providers); *providers = Providers { diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 78cea1f4d8d3e..e4837ee60bd37 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -1,7 +1,7 @@ //! Code related to processing overloaded binary and unary operators. use super::method::MethodCallee; -use super::{has_expected_num_generic_args, FnCtxt}; +use super::FnCtxt; use crate::Expectation; use rustc_ast as ast; use rustc_errors::{self, struct_span_err, Applicability, Diagnostic}; @@ -724,26 +724,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, op, opname, trait_did ); - // Catches cases like #83893, where a lang item is declared with the - // wrong number of generic arguments. Should have yielded an error - // elsewhere by now, but we have to catch it here so that we do not - // index `other_tys` out of bounds (if the lang item has too many - // generic arguments, `other_tys` is too short). - if !has_expected_num_generic_args( - self.tcx, - trait_did, - match op { - // Binary ops have a generic right-hand side, unary ops don't - Op::Binary(..) => 1, - Op::Unary(..) => 0, - }, - ) { - self.tcx - .sess - .delay_span_bug(span, "operator didn't have the right number of generic args"); - return Err(vec![]); - } - let opname = Ident::with_dummy_span(opname); let input_types = opt_rhs.as_ref().map(|(_, ty)| std::slice::from_ref(ty)).unwrap_or_default(); diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index a0f048fc09b9b..f3927988095f9 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -1,5 +1,5 @@ use crate::method::MethodCallee; -use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp}; +use crate::{FnCtxt, PlaceOp}; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir as hir; @@ -209,20 +209,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index), }; - // If the lang item was declared incorrectly, stop here so that we don't - // run into an ICE (#83893). The error is reported where the lang item is - // declared. - if !has_expected_num_generic_args( - self.tcx, - imm_tr, - match op { - PlaceOp::Deref => 0, - PlaceOp::Index => 1, - }, - ) { - return None; - } - imm_tr.and_then(|trait_did| { self.lookup_method_in_trait( self.misc(span), @@ -248,20 +234,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut), }; - // If the lang item was declared incorrectly, stop here so that we don't - // run into an ICE (#83893). The error is reported where the lang item is - // declared. - if !has_expected_num_generic_args( - self.tcx, - mut_tr, - match op { - PlaceOp::Deref => 0, - PlaceOp::Index => 1, - }, - ) { - return None; - } - mut_tr.and_then(|trait_did| { self.lookup_method_in_trait( self.misc(span), From 1cd3a645bd1e1638a683ee0af8e7367d2b40e6bb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 8 Sep 2022 08:11:17 +0000 Subject: [PATCH 03/13] Add TypeFoldable impls for effects --- .../rustc_const_eval/src/interpret/util.rs | 7 +++ .../rustc_hir_analysis/src/check/wfcheck.rs | 7 +++ .../src/constrained_generic_params.rs | 7 +++ compiler/rustc_middle/src/ty/effect.rs | 3 +- compiler/rustc_middle/src/ty/flags.rs | 33 ++++++++++++ compiler/rustc_middle/src/ty/fold.rs | 4 ++ .../rustc_middle/src/ty/structural_impls.rs | 53 +++++++++++++++++++ compiler/rustc_middle/src/ty/visit.rs | 38 +++++++++++++ .../rustc_monomorphize/src/polymorphize.rs | 32 +++++++++++ .../src/traits/query/normalize.rs | 11 ++++ compiler/rustc_type_ir/src/lib.rs | 18 +++++++ 11 files changed, 212 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index e4f716c31945c..befc4d43f7522 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -61,6 +61,13 @@ where _ => c.super_visit_with(self), } } + + fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow { + match e.val { + ty::EffectValue::Param { .. } => ControlFlow::Break(FoundParam), + _ => e.super_visit_with(self), + } + } } let mut vis = UsedParamsNeedSubstVisitor { tcx }; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 969f7de51cebd..d70d0ddcca6ff 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -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 { + 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(); diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 95c971c0d7845..2a6be7729793f 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -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 { + if let ty::EffectValue::Param { index } = e.val { + self.parameters.push(Parameter(index)); + } + ControlFlow::CONTINUE + } } pub fn identify_constrained_generic_params<'tcx>( diff --git a/compiler/rustc_middle/src/ty/effect.rs b/compiler/rustc_middle/src/ty/effect.rs index f4b5931116ed9..25a4f5664ab15 100644 --- a/compiler/rustc_middle/src/ty/effect.rs +++ b/compiler/rustc_middle/src/ty/effect.rs @@ -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, ... diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index b7eafc4b43738..bf815f50993f2 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -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() { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 09fee0c3f7c30..b223dd9a6044e 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -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, Self::Error> { + e.try_super_fold_with(self) + } + fn try_fold_predicate( &mut self, p: ty::Predicate<'tcx>, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 30073b541ecbd..9b4dde267d794 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -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>(self, folder: &mut F) -> Result { + folder.try_fold_effect(self) + } +} + +impl<'tcx> TypeVisitable<'tcx> for ty::Effect<'tcx> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { + visitor.visit_effect(*self) + } +} + +impl<'tcx> TypeSuperFoldable<'tcx> for ty::Effect<'tcx> { + fn try_super_fold_with>( + self, + folder: &mut F, + ) -> Result { + 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>(&self, visitor: &mut V) -> ControlFlow { + 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>(self, _folder: &mut F) -> Result { + Ok(self) + } +} + +impl<'tcx> TypeVisitable<'tcx> for ty::EffectValue<'tcx> { + fn visit_with>(&self, _visitor: &mut V) -> ControlFlow { + match self { + ty::EffectValue::Rigid { on: _ } + | ty::EffectValue::Param { .. } + | ty::EffectValue::Infer(_) + | ty::EffectValue::Bound(_, _) + | ty::EffectValue::Placeholder(_) + | ty::EffectValue::Err(_) => {} + } + ControlFlow::CONTINUE + } +} diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index ca44555813138..bcbee1f322619 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -217,6 +217,10 @@ pub trait TypeVisitor<'tcx>: Sized { c.super_visit_with(self) } + fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow { + e.super_visit_with(self) + } + fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow { 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 { + // 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. + 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 { 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 { + 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 { 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 { + 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 { if let ty::RePlaceholder(placeholder) = *r { self.max_universe = ty::UniverseIndex::from_u32( diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 703ed09a254a9..5146fe9878fbe 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -321,6 +321,21 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } } + fn visit_effect(&mut self, e: ty::Effect<'tcx>) -> ControlFlow { + 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 { 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 { + 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 { if !ty.has_non_region_param() { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index c6ef13e185b2d..2a67d44f0e312 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -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 { + 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> { diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 44004cb0be1e9..f1c0fc66f38d8 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -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; } } From 57ec9439c494c6264f2c996ab38cacf4c0574f96 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 15 Sep 2022 15:44:44 +0000 Subject: [PATCH 04/13] Add Lift impls for `Effect` --- compiler/rustc_middle/src/ty/effect.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/effect.rs b/compiler/rustc_middle/src/ty/effect.rs index 25a4f5664ab15..a2452a1bceca5 100644 --- a/compiler/rustc_middle/src/ty/effect.rs +++ b/compiler/rustc_middle/src/ty/effect.rs @@ -1,4 +1,4 @@ -use super::Placeholder; +use super::{Lift, Placeholder, TyCtxt}; use crate::ty; use rustc_data_structures::intern::Interned; use rustc_errors::ErrorGuaranteed; @@ -52,6 +52,20 @@ pub enum EffectValue<'tcx> { Err(ErrorGuaranteed), } +impl<'a, 'tcx> Lift<'tcx> for EffectValue<'a> { + type Lifted = EffectValue<'tcx>; + fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { + Some(match self { + Self::Rigid { on } => EffectValue::Rigid { on }, + Self::Param { index } => EffectValue::Param { index }, + Self::Infer(infer) => EffectValue::Infer(infer.lift_to_tcx(tcx)?), + Self::Bound(di, bv) => EffectValue::Bound(di, bv), + Self::Placeholder(ph) => EffectValue::Placeholder(ph), + Self::Err(e) => EffectValue::Err(e), + }) + } +} + #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, Debug, TyEncodable, TyDecodable)] #[derive(Copy, TypeFoldable, TypeVisitable)] pub enum EffectKind { @@ -61,7 +75,7 @@ pub enum EffectKind { } /// An inference variable for an effect, for use in effect generics. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash, Lift)] #[derive(HashStable)] pub enum InferEffect<'tcx> { /// Infer the value of the const. @@ -78,4 +92,11 @@ pub struct EffectVid<'tcx> { pub phantom: PhantomData<&'tcx ()>, } +impl<'a, 'tcx> Lift<'tcx> for EffectVid<'a> { + type Lifted = EffectVid<'tcx>; + fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option> { + Some(EffectVid { index: self.index, phantom: PhantomData }) + } +} + pub type PlaceholderEffect = Placeholder; From 230f0ad67c6ae14353f8ef0a3e8d7c6968a9ac48 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 8 Sep 2022 10:24:04 +0000 Subject: [PATCH 05/13] Add effect inference var unification table --- compiler/rustc_infer/src/infer/fudge.rs | 25 +++++- compiler/rustc_infer/src/infer/mod.rs | 17 ++++ compiler/rustc_infer/src/infer/undo_log.rs | 3 + compiler/rustc_middle/src/infer/unify_key.rs | 88 ++++++++++++++++++++ compiler/rustc_middle/src/ty/fast_reject.rs | 33 ++++++++ 5 files changed, 165 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index 6dd6c4e1f5ee8..488b2409b1cc8 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -1,5 +1,6 @@ +use rustc_middle::infer::unify_key::EffectVariableOrigin; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; +use rustc_middle::ty::{self, ConstVid, EffectVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; use super::type_variable::TypeVariableOrigin; use super::InferCtxt; @@ -35,9 +36,23 @@ fn const_vars_since_snapshot<'tcx>( ) } +fn effect_vars_since_snapshot<'tcx>( + table: &mut UnificationTable<'_, 'tcx, EffectVid<'tcx>>, + snapshot_var_len: usize, +) -> (Range>, Vec) { + let range = vars_since_snapshot(table, snapshot_var_len); + ( + range.start..range.end, + (range.start.index..range.end.index) + .map(|index| table.probe_value(EffectVid::from_index(index)).origin) + .collect(), + ) +} + struct VariableLengths { type_var_len: usize, const_var_len: usize, + effect_var_len: usize, int_var_len: usize, float_var_len: usize, region_constraints_len: usize, @@ -49,6 +64,7 @@ impl<'tcx> InferCtxt<'tcx> { VariableLengths { type_var_len: inner.type_variables().num_vars(), const_var_len: inner.const_unification_table().len(), + effect_var_len: inner.effect_unification_table().len(), int_var_len: inner.int_unification_table().len(), float_var_len: inner.float_unification_table().len(), region_constraints_len: inner.unwrap_region_constraints().num_region_vars(), @@ -130,6 +146,10 @@ impl<'tcx> InferCtxt<'tcx> { &mut inner.const_unification_table(), variable_lengths.const_var_len, ); + let effect_vars = effect_vars_since_snapshot( + &mut inner.effect_unification_table(), + variable_lengths.effect_var_len, + ); let fudger = InferenceFudger { infcx: self, @@ -138,6 +158,7 @@ impl<'tcx> InferCtxt<'tcx> { float_vars, region_vars, const_vars, + effect_vars, }; Ok((fudger, value)) @@ -158,6 +179,7 @@ impl<'tcx> InferCtxt<'tcx> { && fudger.float_vars.is_empty() && fudger.region_vars.0.is_empty() && fudger.const_vars.0.is_empty() + && fudger.effect_vars.0.is_empty() { Ok(value) } else { @@ -173,6 +195,7 @@ pub struct InferenceFudger<'a, 'tcx> { float_vars: Range, region_vars: (Range, Vec), const_vars: (Range>, Vec), + effect_vars: (Range>, Vec), } impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index a9de74d78cb61..839757c4590ad 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -106,6 +106,9 @@ pub struct InferCtxtInner<'tcx> { /// Map from const parameter variable to the kind of const it represents. const_unification_storage: ut::UnificationTableStorage>, + /// Map from effect parameter variable to the kind of effect it represents. + effect_unification_storage: ut::UnificationTableStorage>, + /// Map from integral variable to the kind of integer it represents. int_unification_storage: ut::UnificationTableStorage, @@ -165,6 +168,7 @@ impl<'tcx> InferCtxtInner<'tcx> { type_variable_storage: type_variable::TypeVariableStorage::new(), undo_log: InferCtxtUndoLogs::default(), const_unification_storage: ut::UnificationTableStorage::new(), + effect_unification_storage: ut::UnificationTableStorage::new(), int_unification_storage: ut::UnificationTableStorage::new(), float_unification_storage: ut::UnificationTableStorage::new(), region_constraint_storage: Some(RegionConstraintStorage::new()), @@ -232,6 +236,19 @@ impl<'tcx> InferCtxtInner<'tcx> { self.const_unification_storage.with_log(&mut self.undo_log) } + #[inline] + fn effect_unification_table( + &mut self, + ) -> ut::UnificationTable< + ut::InPlace< + ty::EffectVid<'tcx>, + &mut ut::UnificationStorage>, + &mut InferCtxtUndoLogs<'tcx>, + >, + > { + self.effect_unification_storage.with_log(&mut self.undo_log) + } + #[inline] pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> { self.region_constraint_storage diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 955c54e85157e..fa586ee34f661 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -22,6 +22,7 @@ pub(crate) enum UndoLog<'tcx> { OpaqueTypes(OpaqueTypeKey<'tcx>, Option>), TypeVariables(type_variable::UndoLog<'tcx>), ConstUnificationTable(sv::UndoLog>>), + EffectUnificationTable(sv::UndoLog>>), IntUnificationTable(sv::UndoLog>), FloatUnificationTable(sv::UndoLog>), RegionConstraintCollector(region_constraints::UndoLog<'tcx>), @@ -57,6 +58,7 @@ impl_from! { FloatUnificationTable(sv::UndoLog>), ConstUnificationTable(sv::UndoLog>>), + EffectUnificationTable(sv::UndoLog>>), RegionUnificationTable(sv::UndoLog>>), ProjectionCache(traits::UndoLog<'tcx>), @@ -69,6 +71,7 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx), UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo), UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), + UndoLog::EffectUnificationTable(undo) => self.effect_unification_storage.reverse(undo), UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo), UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo), UndoLog::RegionConstraintCollector(undo) => { diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 41d8c7ffdb945..1f0fbea91d939 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -160,3 +160,91 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { }) } } + +// Generic effects. + +#[derive(Copy, Clone, Debug)] +pub struct EffectVariableOrigin { + pub kind: EffectVariableOriginKind, + pub span: Span, +} + +/// Reasons to create a effect inference variable +#[derive(Copy, Clone, Debug)] +pub enum EffectVariableOriginKind { + MiscVariable, + EffectInference, + EffectParameterDefinition(Symbol, DefId), + SubstitutionPlaceholder, +} + +#[derive(Copy, Clone, Debug)] +pub enum EffectVariableValue<'tcx> { + Known { value: ty::Effect<'tcx> }, + Unknown { universe: ty::UniverseIndex }, +} + +impl<'tcx> EffectVariableValue<'tcx> { + /// If this value is known, returns the effect it is known to be. + /// Otherwise, `None`. + pub fn known(&self) -> Option> { + match *self { + EffectVariableValue::Unknown { .. } => None, + EffectVariableValue::Known { value } => Some(value), + } + } +} + +#[derive(Copy, Clone, Debug)] +pub struct EffectVarValue<'tcx> { + pub origin: EffectVariableOrigin, + pub val: EffectVariableValue<'tcx>, +} + +impl<'tcx> UnifyKey for ty::EffectVid<'tcx> { + type Value = EffectVarValue<'tcx>; + #[inline] + fn index(&self) -> u32 { + self.index + } + #[inline] + fn from_index(i: u32) -> Self { + ty::EffectVid { index: i, phantom: PhantomData } + } + fn tag() -> &'static str { + "EffectVid" + } +} + +impl<'tcx> UnifyValue for EffectVarValue<'tcx> { + type Error = NoError; + + fn unify_values(&value1: &Self, &value2: &Self) -> Result { + Ok(match (value1.val, value2.val) { + (EffectVariableValue::Known { .. }, EffectVariableValue::Known { .. }) => { + bug!("equating two effect variables, both of which have known values") + } + + // If one side is known, prefer that one. + (EffectVariableValue::Known { .. }, EffectVariableValue::Unknown { .. }) => value1, + (EffectVariableValue::Unknown { .. }, EffectVariableValue::Known { .. }) => value2, + + // If both sides are *unknown*, it hardly matters, does it? + ( + EffectVariableValue::Unknown { universe: universe1 }, + EffectVariableValue::Unknown { universe: universe2 }, + ) => { + // If we unify two unbound variables, ?T and ?U, then whatever + // value they wind up taking (which must be the same value) must + // be nameable by both universes. Therefore, the resulting + // universe is the minimum of the two universes, because that is + // the one which contains the fewest names in scope. + let universe = cmp::min(universe1, universe2); + EffectVarValue { + val: EffectVariableValue::Unknown { universe }, + origin: value1.origin, + } + } + }) + } +} diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index f785fb5c4b9be..8b8330520c3db 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -350,4 +350,37 @@ impl DeepRejectCtxt { } } } + + pub fn effects_may_unify(self, obligation: ty::Effect<'_>, impl_: ty::Effect<'_>) -> bool { + match impl_.val { + ty::EffectValue::Param { .. } | ty::EffectValue::Err(_) => { + return true; + } + ty::EffectValue::Rigid { .. } => {} + ty::EffectValue::Infer(_) + | ty::EffectValue::Bound(..) + | ty::EffectValue::Placeholder(_) => { + bug!("unexpected impl arg: {:?}", impl_) + } + } + + match obligation.val { + ty::EffectValue::Param { .. } => match self.treat_obligation_params { + TreatParams::AsPlaceholder => false, + TreatParams::AsInfer => true, + }, + + ty::EffectValue::Err(_) => true, + ty::EffectValue::Rigid { on: obl } => match impl_.val { + ty::EffectValue::Rigid { on: impl_ } => obl == impl_, + _ => true, + }, + + ty::EffectValue::Infer(_) => true, + + ty::EffectValue::Bound(..) | ty::EffectValue::Placeholder(_) => { + bug!("unexpected obl const: {:?}", obligation) + } + } + } } From e523a953a65c5844892dee31e63b51058dac1758 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 8 Sep 2022 11:40:10 +0000 Subject: [PATCH 06/13] Add effects to TypeRelation --- .../rustc_hir_analysis/src/check/dropck.rs | 9 ++ compiler/rustc_hir_typeck/src/demand.rs | 1 + compiler/rustc_infer/src/infer/combine.rs | 109 +++++++++++++++++- compiler/rustc_infer/src/infer/equate.rs | 8 ++ .../src/infer/error_reporting/mod.rs | 10 ++ compiler/rustc_infer/src/infer/glb.rs | 8 ++ compiler/rustc_infer/src/infer/lub.rs | 8 ++ .../rustc_infer/src/infer/nll_relate/mod.rs | 54 +++++++++ .../rustc_infer/src/infer/opaque_types.rs | 2 + .../src/infer/outlives/test_type_match.rs | 10 ++ compiler/rustc_infer/src/infer/sub.rs | 12 ++ .../src/opaque_hidden_inferred_bound.rs | 1 + compiler/rustc_middle/src/ty/_match.rs | 14 +++ compiler/rustc_middle/src/ty/effect.rs | 12 ++ compiler/rustc_middle/src/ty/error.rs | 6 +- compiler/rustc_middle/src/ty/fold.rs | 20 +++- compiler/rustc_middle/src/ty/relate.rs | 29 +++++ .../traits/error_reporting/method_chain.rs | 8 ++ .../src/traits/select/mod.rs | 1 + 19 files changed, 317 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index d6e3ddb0a6139..dbd41d457c842 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -319,6 +319,15 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> { ty::relate::super_relate_consts(self, a, b) } + fn effects( + &mut self, + a: ty::Effect<'tcx>, + b: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + debug!("SimpleEqRelation::effects(a={:?}, b={:?})", a, b); + ty::relate::super_relate_effect(self, a, b) + } + fn binders( &mut self, a: ty::Binder<'tcx, T>, diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index f68a428d09ae3..06e4ad5d8a895 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -278,6 +278,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => t, }, + e_op: |e| e, }; let mut prev = eraser.fold_ty(ty); let mut prev_span = None; diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 9a1c49c1aa6af..00ab24b6104fb 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -31,13 +31,15 @@ use super::{InferCtxt, MiscVariable, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; use rustc_data_structures::sso::SsoHashMap; use rustc_hir::def_id::DefId; -use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; +use rustc_middle::infer::unify_key::{ + ConstVarValue, ConstVariableValue, EffectVarValue, EffectVariableValue, +}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{self, InferConst, InferEffect, Ty, TyCtxt, TypeVisitable}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::{Span, DUMMY_SP}; @@ -186,6 +188,40 @@ impl<'tcx> InferCtxt<'tcx> { ty::relate::super_relate_consts(relation, a, b) } + pub fn super_combine_effect( + &self, + relation: &mut impl TypeRelation<'tcx>, + a: ty::Effect<'tcx>, + b: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + debug!("{}.effect({:?}, {:?})", relation.tag(), a, b); + if a == b { + return Ok(a); + } + + let a = self.shallow_resolve(a); + let b = self.shallow_resolve(b); + + match (a.val, b.val) { + ( + ty::EffectValue::Infer(InferEffect::Var(a_vid)), + ty::EffectValue::Infer(InferEffect::Var(b_vid)), + ) => { + self.inner.borrow_mut().effect_unification_table().union(a_vid, b_vid); + return Ok(a); + } + + // All other cases of inference with other variables are errors. + (ty::EffectValue::Infer(InferEffect::Var(_)), ty::EffectValue::Infer(_)) + | (ty::EffectValue::Infer(_), ty::EffectValue::Infer(InferEffect::Var(_))) => { + bug!("tried to combine Effect::Infer/Effect::Infer(InferEffect::Var)") + } + _ => {} + } + + ty::relate::super_relate_effect(relation, a, b) + } + /// Unifies the const variable `target_vid` with the given constant. /// /// This also tests if the given const `ct` contains an inference variable which was previously @@ -728,6 +764,39 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe)) } + fn effects( + &mut self, + e: ty::Effect<'tcx>, + e2: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + assert_eq!(e, e2); // we are abusing TypeRelation here; both LHS and RHS ought to be == + match e.val { + ty::EffectValue::Infer(ty::InferEffect::Var(vid)) => { + let mut inner = self.infcx.inner.borrow_mut(); + let variable_table = &mut inner.effect_unification_table(); + let var_value = variable_table.probe_value(vid); + match var_value.val { + EffectVariableValue::Known { value: u } => { + drop(inner); + self.relate(u, u) + } + EffectVariableValue::Unknown { universe } => { + if self.for_universe.can_name(universe) { + Ok(e) + } else { + let new_var_id = variable_table.new_key(EffectVarValue { + origin: var_value.origin, + val: EffectVariableValue::Unknown { universe: self.for_universe }, + }); + Ok(self.tcx().mk_effect(new_var_id, e.kind)) + } + } + } + } + _ => Ok(e), + } + } + fn consts( &mut self, c: ty::Const<'tcx>, @@ -990,4 +1059,40 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { _ => relate::super_relate_consts(self, c, c), } } + + #[instrument(level = "debug", skip(self))] + fn effects( + &mut self, + e: ty::Effect<'tcx>, + _e: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + debug_assert_eq!(e, _e); + + match e.val { + ty::EffectValue::Infer(ty::InferEffect::Var(vid)) => { + let var_value = + self.infcx.inner.borrow_mut().effect_unification_table().probe_value(vid); + match var_value.val { + EffectVariableValue::Known { value: u } => self.effects(u, u), + EffectVariableValue::Unknown { universe } => { + if self.for_universe.can_name(universe) { + Ok(e) + } else { + let new_var_id = + self.infcx.inner.borrow_mut().effect_unification_table().new_key( + EffectVarValue { + origin: var_value.origin, + val: EffectVariableValue::Unknown { + universe: self.for_universe, + }, + }, + ); + Ok(self.tcx().mk_effect(new_var_id, e.kind)) + } + } + } + } + _ => Ok(e), + } + } } diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 46e7813d99e56..a8b5da67f2c3d 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -174,6 +174,14 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { self.fields.infcx.super_combine_consts(self, a, b) } + fn effects( + &mut self, + a: ty::Effect<'tcx>, + b: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + self.fields.infcx.super_combine_effect(self, a, b) + } + fn binders( &mut self, a: ty::Binder<'tcx, T>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 5abc19d9b0c53..696f3d78a913f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2609,6 +2609,16 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { // relation Ok(a) } + + fn effects( + &mut self, + a: ty::Effect<'tcx>, + _b: ty::Effect<'tcx>, + ) -> relate::RelateResult<'tcx, ty::Effect<'tcx>> { + // FIXME(compiler-errors): This could at least do some first-order + // relation + Ok(a) + } } impl<'tcx> InferCtxt<'tcx> { diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 21b68ce998997..c238d5161feb7 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -95,6 +95,14 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { self.fields.infcx.super_combine_consts(self, a, b) } + fn effects( + &mut self, + a: ty::Effect<'tcx>, + b: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + self.fields.infcx.super_combine_effect(self, a, b) + } + fn binders( &mut self, a: ty::Binder<'tcx, T>, diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index c07ac1d3ace92..90ae4b95539c5 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -95,6 +95,14 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { self.fields.infcx.super_combine_consts(self, a, b) } + fn effects( + &mut self, + a: ty::Effect<'tcx>, + b: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + self.fields.infcx.super_combine_effect(self, a, b) + } + fn binders( &mut self, a: ty::Binder<'tcx, T>, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 1f9d86a78d6e5..3b3b9a3181db9 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -27,6 +27,7 @@ use crate::infer::{ConstVarValue, ConstVariableValue}; use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::traits::{Obligation, PredicateObligation}; use rustc_data_structures::fx::FxHashMap; +use rustc_middle::infer::unify_key::{EffectVarValue, EffectVariableValue}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; @@ -700,6 +701,31 @@ where } } + fn effects( + &mut self, + a: ty::Effect<'tcx>, + mut b: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + let a = self.infcx.shallow_resolve(a); + + if !D::forbid_inference_vars() { + b = self.infcx.shallow_resolve(b); + } + + match b.val { + ty::EffectValue::Infer(ty::InferEffect::Var(_)) if D::forbid_inference_vars() => { + // Forbid inference variables in the RHS. + self.infcx.tcx.sess.delay_span_bug( + self.delegate.span(), + format!("unexpected inference var {:?}", b,), + ); + Ok(a) + } + // FIXME(invariance): see the related FIXME above. + _ => self.infcx.super_combine_effect(self, a, b), + } + } + #[instrument(skip(self), level = "trace")] fn binders( &mut self, @@ -1102,6 +1128,34 @@ where } } + fn effects( + &mut self, + a: ty::Effect<'tcx>, + _: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + match a.val { + ty::EffectValue::Infer(ty::InferEffect::Var(_)) if D::forbid_inference_vars() => { + bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); + } + ty::EffectValue::Infer(ty::InferEffect::Var(vid)) => { + let mut inner = self.infcx.inner.borrow_mut(); + let variable_table = &mut inner.effect_unification_table(); + let var_value = variable_table.probe_value(vid); + match var_value.val.known() { + Some(u) => self.relate(u, u), + None => { + let new_var_id = variable_table.new_key(EffectVarValue { + origin: var_value.origin, + val: EffectVariableValue::Unknown { universe: self.universe }, + }); + Ok(self.tcx().mk_effect(new_var_id, a.kind)) + } + } + } + _ => relate::super_relate_effect(self, a, a), + } + } + fn binders( &mut self, a: ty::Binder<'tcx, T>, diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 749e960bfd030..94be0a164b6f2 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -65,6 +65,7 @@ impl<'tcx> InferCtxt<'tcx> { tcx: self.tcx, lt_op: |lt| lt, ct_op: |ct| ct, + e_op: |e| e, ty_op: |ty| match *ty.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) if replace_opaque_type(def_id) => @@ -595,6 +596,7 @@ impl<'tcx> InferCtxt<'tcx> { }, lt_op: |lt| lt, ct_op: |ct| ct, + e_op: |e| e, }); if let ty::PredicateKind::Clause(ty::Clause::Projection(projection)) = diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 10b474efd5aeb..e461f4765059f 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -210,6 +210,16 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { } } + #[instrument(skip(self), level = "debug")] + fn effects( + &mut self, + pattern: ty::Effect<'tcx>, + value: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + debug!("{}.effects({:?}, {:?})", self.tag(), pattern, value); + relate::super_relate_effect(self, pattern, value) + } + fn binders( &mut self, pattern: ty::Binder<'tcx, T>, diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index bd38b52ba34a7..26a6d064391a9 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -209,6 +209,18 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { self.fields.infcx.super_combine_consts(self, a, b) } + fn effects( + &mut self, + a: ty::Effect<'tcx>, + b: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + match (a.val, b.val) { + // Any effect matches the rigid "off" effect. For example: `T: ~const Trait` implies `T: Trait` + (ty::EffectValue::Rigid { on: false }, _) => Ok(a), + _ => self.fields.infcx.super_combine_effect(self, a, b), + } + } + fn binders( &mut self, a: ty::Binder<'tcx, T>, diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 42442cfb1904d..a78170a5d003f 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -91,6 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { ty_op: |ty| if ty == proj_ty { proj_term } else { ty }, lt_op: |lt| lt, ct_op: |ct| ct, + e_op: |e| e, }; // For example, in `impl Trait`, for all of the bounds on `Assoc`, // e.g. `type Assoc: OtherTrait`, replace `::Assoc: OtherTrait` diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index cd147d7e55813..a0e08b403eea7 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -120,6 +120,20 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { relate::super_relate_consts(self, a, b) } + fn effects( + &mut self, + a: ty::Effect<'tcx>, + b: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + debug!("{}.effects({:?}, {:?})", self.tag(), a, b); + + if let ty::EffectValue::Infer(ty::InferEffect::Fresh(_)) = b.val { + return Ok(a); + } + + ty::relate::super_relate_effect(self, a, b) + } + fn binders( &mut self, a: ty::Binder<'tcx, T>, diff --git a/compiler/rustc_middle/src/ty/effect.rs b/compiler/rustc_middle/src/ty/effect.rs index a2452a1bceca5..3d3ae77dca890 100644 --- a/compiler/rustc_middle/src/ty/effect.rs +++ b/compiler/rustc_middle/src/ty/effect.rs @@ -74,6 +74,18 @@ pub enum EffectKind { Host, } +impl<'tcx> From> for EffectValue<'tcx> { + fn from(infer: InferEffect<'tcx>) -> Self { + Self::Infer(infer) + } +} + +impl<'tcx> From> for EffectValue<'tcx> { + fn from(infer: EffectVid<'tcx>) -> Self { + InferEffect::Var(infer).into() + } +} + /// An inference variable for an effect, for use in effect generics. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash, Lift)] #[derive(HashStable)] diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 50554cf9a82c8..be8b57117d136 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -71,6 +71,7 @@ pub enum TypeError<'tcx> { ProjectionMismatched(ExpectedFound), ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), ConstMismatch(ExpectedFound>), + EffectMismatch(ExpectedFound>), IntrinsicCast, /// Safe `#[target_feature]` functions are not assignable to safe function pointers. @@ -228,6 +229,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { ConstMismatch(ref values) => { write!(f, "expected `{}`, found `{}`", values.expected, values.found) } + EffectMismatch(ref values) => { + write!(f, "expected `{:?}`, found `{:?}`", values.expected, values.found) + } IntrinsicCast => write!(f, "cannot coerce intrinsics to function pointers"), TargetFeatureCast(_) => write!( f, @@ -244,7 +248,7 @@ impl<'tcx> TypeError<'tcx> { CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_) | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_) - | VariadicMismatch(_) | TargetFeatureCast(_) => false, + | VariadicMismatch(_) | TargetFeatureCast(_) | EffectMismatch(_) => false, Mutability | ArgumentMutability(_) diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index b223dd9a6044e..bc28249f70729 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -126,6 +126,10 @@ pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> { c.super_fold_with(self) } + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + e.super_fold_with(self) + } + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { p.super_fold_with(self) } @@ -205,6 +209,10 @@ where Ok(self.fold_const(c)) } + fn try_fold_effect(&mut self, e: ty::Effect<'tcx>) -> Result, !> { + Ok(self.fold_effect(e)) + } + fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result, !> { Ok(self.fold_predicate(p)) } @@ -213,23 +221,26 @@ where /////////////////////////////////////////////////////////////////////////// // Some sample folders -pub struct BottomUpFolder<'tcx, F, G, H> +pub struct BottomUpFolder<'tcx, F, G, H, E> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>, + E: FnMut(ty::Effect<'tcx>) -> ty::Effect<'tcx>, { pub tcx: TyCtxt<'tcx>, pub ty_op: F, pub lt_op: G, pub ct_op: H, + pub e_op: E, } -impl<'tcx, F, G, H> TypeFolder<'tcx> for BottomUpFolder<'tcx, F, G, H> +impl<'tcx, F, G, H, E> TypeFolder<'tcx> for BottomUpFolder<'tcx, F, G, H, E> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>, + E: FnMut(ty::Effect<'tcx>) -> ty::Effect<'tcx>, { fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.tcx @@ -249,6 +260,11 @@ where let ct = ct.super_fold_with(self); (self.ct_op)(ct) } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + let e = e.super_fold_with(self); + (self.e_op)(e) + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 4d34ca3d66b5f..6ab079769ab03 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -97,6 +97,12 @@ pub trait TypeRelation<'tcx>: Sized { b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>>; + fn effects( + &mut self, + a: ty::Effect<'tcx>, + b: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>>; + fn binders( &mut self, a: ty::Binder<'tcx, T>, @@ -707,6 +713,18 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) } } +/// The main "effect relation" routine. Note that this does not handle +/// inference artifacts, so you should filter those out before calling +/// it. +pub fn super_relate_effect<'tcx, R: TypeRelation<'tcx>>( + relation: &mut R, + a: ty::Effect<'tcx>, + b: ty::Effect<'tcx>, +) -> RelateResult<'tcx, ty::Effect<'tcx>> { + debug!("{}.super_relate_effect(a = {:?}, b = {:?})", relation.tag(), a, b); + if a == b { Ok(a) } else { Err(TypeError::EffectMismatch(expected_found(relation, a, b))) } +} + impl<'tcx> Relate<'tcx> for &'tcx ty::List> { fn relate>( relation: &mut R, @@ -797,6 +815,17 @@ impl<'tcx> Relate<'tcx> for ty::Const<'tcx> { } } +impl<'tcx> Relate<'tcx> for ty::Effect<'tcx> { + fn relate>( + relation: &mut R, + a: ty::Effect<'tcx>, + b: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + debug_assert_eq!(a.kind, b.kind); + relation.effects(a, b) + } +} + impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder<'tcx, T> { fn relate>( relation: &mut R, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs index 27c207528c735..be1ee6eaadc51 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs @@ -53,6 +53,14 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> { Ok(a) } + fn effects( + &mut self, + a: ty::Effect<'tcx>, + _b: ty::Effect<'tcx>, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + Ok(a) + } + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { self.infcx.probe(|_| { if a.is_ty_infer() || b.is_ty_infer() { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3f14491f8032f..c669ddf2c98dc 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2357,6 +2357,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty_op: |_| err, lt_op: |l| l, ct_op: |c| c, + e_op: |e| e, }); Normalized { value, obligations: vec![] } } From 23f84752e2379b71ffcfc2c7b3cb0ae81649a375 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 12 Sep 2022 18:18:26 +0000 Subject: [PATCH 07/13] Add effect generic param --- .../src/diagnostics/region_name.rs | 1 + .../src/region_infer/opaque_types.rs | 1 + .../src/type_check/constraint_conversion.rs | 2 +- .../src/transform/check_consts/check.rs | 6 +- .../src/outlives/implicit_infer.rs | 6 +- .../rustc_hir_analysis/src/outlives/mod.rs | 4 + .../rustc_hir_analysis/src/outlives/utils.rs | 4 + .../src/variance/constraints.rs | 3 + .../rustc_hir_typeck/src/method/suggest.rs | 11 +++ .../src/infer/canonical/query_response.rs | 14 ++++ .../infer/error_reporting/need_type_info.rs | 4 + compiler/rustc_infer/src/infer/mod.rs | 52 +++++++++++++ .../rustc_infer/src/infer/opaque_types.rs | 4 +- .../src/infer/outlives/components.rs | 3 + .../src/infer/outlives/obligations.rs | 3 + compiler/rustc_middle/src/infer/canonical.rs | 6 ++ compiler/rustc_middle/src/ty/effect.rs | 6 ++ compiler/rustc_middle/src/ty/fast_reject.rs | 3 + compiler/rustc_middle/src/ty/flags.rs | 1 + compiler/rustc_middle/src/ty/impls_ty.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 1 + compiler/rustc_middle/src/ty/relate.rs | 6 ++ compiler/rustc_middle/src/ty/subst.rs | 74 +++++++++++++++++++ .../rustc_middle/src/ty/typeck_results.rs | 9 +++ compiler/rustc_middle/src/ty/util.rs | 13 ++++ compiler/rustc_middle/src/ty/visit.rs | 1 + compiler/rustc_middle/src/ty/walk.rs | 1 + .../src/thir/pattern/const_to_pat.rs | 1 + compiler/rustc_monomorphize/src/collector.rs | 1 + .../src/typeid/typeid_itanium_cxx_abi.rs | 34 +++++++++ compiler/rustc_symbol_mangling/src/v0.rs | 3 + .../src/traits/select/confirmation.rs | 3 + .../rustc_trait_selection/src/traits/wf.rs | 6 ++ compiler/rustc_traits/src/chalk/db.rs | 3 + compiler/rustc_traits/src/chalk/lowering.rs | 4 + .../src/implied_outlives_bounds.rs | 1 + compiler/rustc_ty_utils/src/ty.rs | 3 + src/librustdoc/clean/utils.rs | 2 + .../clippy/clippy_lints/src/let_underscore.rs | 2 +- .../src/non_send_fields_in_send_ty.rs | 1 + .../src/only_used_in_recursion.rs | 1 + .../clippy_utils/src/qualify_min_const_fn.rs | 1 + src/tools/clippy/clippy_utils/src/ty.rs | 3 +- 43 files changed, 301 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 579ce90a760f2..edd80d2e1fd24 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -612,6 +612,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ( GenericArgKind::Lifetime(_) | GenericArgKind::Type(_) + | GenericArgKind::Effect(_) | GenericArgKind::Const(_), _, ) => { diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d82d4cc39fb1c..d20da9f92dff5 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -382,6 +382,7 @@ fn check_opaque_type_parameter_valid( matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) } GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)), + GenericArgKind::Effect(e) => matches!(e.val, ty::EffectValue::Param { .. }), }; if arg_is_param { diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index ce7f857e27310..2aad9b3f9ae7d 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -169,7 +169,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { .type_must_outlive(origin, t1, r2, constraint_category); } - GenericArgKind::Const(_) => unreachable!(), + GenericArgKind::Effect(_) | GenericArgKind::Const(_) => unreachable!(), } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 54213d55a2da7..354c5e7f2a167 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -344,9 +344,11 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { let ty = match ty.unpack() { GenericArgKind::Type(ty) => ty, - // No constraints on lifetimes or constants, except potentially + // No constraints on lifetimes, effects or constants, except potentially // constants' types, but `walk` will get to them as well. - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, + GenericArgKind::Effect(_) + | GenericArgKind::Lifetime(_) + | GenericArgKind::Const(_) => continue, }; match *ty.kind() { diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index a46f2a94cd281..319465425bc8b 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -97,9 +97,11 @@ fn insert_required_predicates_to_be_wf<'tcx>( let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, - // No predicates from lifetimes or constants, except potentially + // No predicates from lifetimes, effects or constants, except potentially // constants' types, but `walk` will get to them as well. - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, + GenericArgKind::Effect(_) | GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => { + continue; + } }; match *ty.kind() { diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index 81fe32000d307..aa2be50d6ab38 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -112,6 +112,10 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { // Generic consts don't impose any constraints. None } + GenericArgKind::Effect(_) => { + // Effects don't impose any constraints. + None + } } }, )); diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index b51b740d08e2e..1b5a47c903e24 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -145,6 +145,10 @@ pub(crate) fn insert_outlives_predicate<'tcx>( GenericArgKind::Const(_) => { // Generic consts don't impose any constraints. } + + GenericArgKind::Effect(_) => { + // Effect don't impose any constraints. + } } } diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 5e4d82b6fd569..7991c0b77aadb 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -189,6 +189,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { GenericArgKind::Const(val) => { self.add_constraints_from_const(current, val, variance_i) } + // There are no constraints from effects + GenericArgKind::Effect(_) => {} } } } @@ -350,6 +352,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { GenericArgKind::Const(val) => { self.add_constraints_from_const(current, val, variance) } + GenericArgKind::Effect(_) => {} } } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 536c427065958..8d57939badddd 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -21,6 +21,8 @@ use rustc_infer::infer::{ type_variable::{TypeVariableOrigin, TypeVariableOriginKind}, RegionVariableOrigin, }; +use rustc_middle::infer::unify_key::EffectVariableOrigin; +use rustc_middle::infer::unify_key::EffectVariableOriginKind; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::util::supertraits; use rustc_middle::ty::fast_reject::DeepRejectCtxt; @@ -1187,6 +1189,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ) .into(), + GenericArgKind::Effect(e) => self + .next_effect_var( + e.kind, + EffectVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: EffectVariableOriginKind::MiscVariable, + }, + ) + .into(), } } else { arg diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index a722613e3310e..ae998bf5e7e0d 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -473,6 +473,15 @@ impl<'tcx> InferCtxt<'tcx> { if let ty::ConstKind::Bound(debrujin, b) = result_value.kind() { // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(debrujin, ty::INNERMOST); + opt_values[b] = Some(*original_value); + } + } + GenericArgKind::Effect(result_value) => { + if let ty::EffectValue::Bound(debrujin, b) = result_value.val { + // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. + // We only allow a `ty::INNERMOST` index in substitutions. assert_eq!(debrujin, ty::INNERMOST); opt_values[b] = Some(*original_value); @@ -583,6 +592,11 @@ impl<'tcx> InferCtxt<'tcx> { // encounter this branch. span_bug!(cause.span, "unexpected const outlives {:?}", predicate); } + GenericArgKind::Effect(..) => { + // Effects cannot outlive one another, so we don't expect to + // encounter this branch. + span_bug!(cause.span, "unexpected effect outlives {:?}", predicate); + } }; let predicate = predicate.0.rebind(atom); diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index a4c36b4c9cd59..11703b3cc96e2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -326,6 +326,7 @@ impl<'tcx> InferCtxt<'tcx> { } } GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), + GenericArgKind::Effect(_) => bug!("unexpected effect"), } } @@ -481,6 +482,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match arg.unpack() { GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), + GenericArgKind::Effect(_) => bug!("unexpected effect"), GenericArgKind::Type(_) => self .next_ty_var(TypeVariableOrigin { span: rustc_span::DUMMY_SP, @@ -753,6 +755,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { GenericArgKind::Lifetime(_) => 0, // erased GenericArgKind::Type(ty) => self.ty_cost(ty), GenericArgKind::Const(_) => 3, // some non-zero value + GenericArgKind::Effect(_) => 3, // some non-zero value } } fn ty_cost(self, ty: Ty<'tcx>) -> usize { @@ -878,6 +881,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { } match inner.unpack() { GenericArgKind::Lifetime(_) => {} + GenericArgKind::Effect(_) => {} GenericArgKind::Type(ty) => { if matches!( ty.kind(), diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 839757c4590ad..5939326d2857e 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -18,6 +18,9 @@ use rustc_data_structures::unify as ut; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; +use rustc_middle::infer::unify_key::EffectVarValue; +use rustc_middle::infer::unify_key::EffectVariableOrigin; +use rustc_middle::infer::unify_key::EffectVariableValue; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; @@ -1085,6 +1088,35 @@ impl<'tcx> InferCtxt<'tcx> { }) } + pub fn next_effect_var( + &self, + kind: ty::EffectKind, + origin: EffectVariableOrigin, + ) -> ty::Effect<'tcx> { + self.tcx.mk_effect(self.next_effect_var_id(origin), kind) + } + + pub fn next_effect_var_in_universe( + &self, + kind: ty::EffectKind, + origin: EffectVariableOrigin, + universe: ty::UniverseIndex, + ) -> ty::Effect<'tcx> { + let vid = self + .inner + .borrow_mut() + .effect_unification_table() + .new_key(EffectVarValue { origin, val: EffectVariableValue::Unknown { universe } }); + self.tcx.mk_effect(vid, kind) + } + + pub fn next_effect_var_id(&self, origin: EffectVariableOrigin) -> ty::EffectVid<'tcx> { + self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue { + origin, + val: EffectVariableValue::Unknown { universe: self.universe() }, + }) + } + fn next_int_var_id(&self) -> IntVid { self.inner.borrow_mut().int_unification_table().new_key(None) } @@ -1691,6 +1723,17 @@ impl<'tcx> InferCtxt<'tcx> { ConstVariableValue::Known { .. } => true, } } + + TyOrConstInferVar::Effect(v) => { + // If `probe_value` returns a `Known` value, it never equals + // `ty::EffectValue::Infer(ty::InferEffect::Var(v))`. + // + // Not `inlined_probe_value(v)` because this call site is colder. + match self.inner.borrow_mut().effect_unification_table().probe_value(v).val { + EffectVariableValue::Unknown { .. } => false, + EffectVariableValue::Known { .. } => true, + } + } } } } @@ -1797,6 +1840,9 @@ pub enum TyOrConstInferVar<'tcx> { /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`. Const(ConstVid<'tcx>), + + /// Equivalent to `ty::EffectValue::Infer(ty::InferEffect::Var(_))`. + Effect(ty::EffectVid<'tcx>), } impl<'tcx> TyOrConstInferVar<'tcx> { @@ -1808,6 +1854,12 @@ impl<'tcx> TyOrConstInferVar<'tcx> { GenericArgKind::Type(ty) => Self::maybe_from_ty(ty), GenericArgKind::Const(ct) => Self::maybe_from_const(ct), GenericArgKind::Lifetime(_) => None, + GenericArgKind::Effect(e) => match e.val { + ty::EffectValue::Infer(ty::InferEffect::Var(v)) => { + Some(TyOrConstInferVar::Effect(v)) + } + _ => None, + }, } } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 94be0a164b6f2..db632cb187095 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -360,7 +360,9 @@ impl<'tcx> InferCtxt<'tcx> { .filter(|(i, _)| variances[*i] == ty::Variance::Invariant) .filter_map(|(_, arg)| match arg.unpack() { GenericArgKind::Lifetime(r) => Some(r), - GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, + GenericArgKind::Type(_) + | GenericArgKind::Const(_) + | GenericArgKind::Effect(_) => None, }) .chain(std::iter::once(self.tcx.lifetimes.re_static)) .collect(), diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index aa2b5d067d266..b71d85ae089d8 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -88,6 +88,7 @@ fn compute_components<'tcx>( compute_components(tcx, ty, out, visited); } GenericArgKind::Lifetime(_) => {} + GenericArgKind::Effect(_) => {} GenericArgKind::Const(_) => { compute_components_recursive(tcx, child, out, visited); } @@ -227,6 +228,8 @@ pub(super) fn compute_components_recursive<'tcx>( GenericArgKind::Const(_) => { compute_components_recursive(tcx, child, out, visited); } + // Effects have no components + GenericArgKind::Effect(_) => {} } } } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index f71c39dc0d26a..8970517519419 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -521,6 +521,9 @@ where GenericArgKind::Const(_) => { // Const parameters don't impose constraints. } + GenericArgKind::Effect(_) => { + // Effect parameters don't impose constraints. + } } } } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 0b32f67a81e16..6cd00f577bfd5 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -358,6 +358,12 @@ impl<'tcx> CanonicalVarValues<'tcx> { ct.ty(), ) .into(), + GenericArgKind::Effect(e) => tcx + .mk_effect( + ty::EffectValue::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)), + e.kind, + ) + .into(), }) .collect(), } diff --git a/compiler/rustc_middle/src/ty/effect.rs b/compiler/rustc_middle/src/ty/effect.rs index 3d3ae77dca890..c99ce37da2174 100644 --- a/compiler/rustc_middle/src/ty/effect.rs +++ b/compiler/rustc_middle/src/ty/effect.rs @@ -23,6 +23,12 @@ impl<'tcx> fmt::Debug for Effect<'tcx> { } } +impl<'tcx> Effect<'tcx> { + pub fn is_e_infer(self) -> bool { + matches!(self.val, ty::EffectValue::Infer(_)) + } +} + #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, Debug, TyEncodable, TyDecodable)] pub struct EffectData<'tcx> { pub val: EffectValue<'tcx>, diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 8b8330520c3db..b6334d6e3a35f 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -177,6 +177,9 @@ impl DeepRejectCtxt { (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => { self.consts_may_unify(obl, imp) } + (GenericArgKind::Effect(obl), GenericArgKind::Effect(imp)) => { + self.effects_may_unify(obl, imp) + } _ => bug!("kind mismatch: {obligation_arg} {impl_arg}"), } } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index bf815f50993f2..0327ff8dd9fd2 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -400,6 +400,7 @@ impl FlagComputation { GenericArgKind::Type(ty) => self.add_ty(ty), GenericArgKind::Lifetime(lt) => self.add_region(lt), GenericArgKind::Const(ct) => self.add_const(ct), + GenericArgKind::Effect(e) => self.add_effect(e), } } } diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index 3e59c0b967c3d..6d35800c9536b 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -97,6 +97,7 @@ impl<'a, 'tcx> HashStable> for ty::subst::GenericArgKin 0xF5u8.hash_stable(hcx, hasher); lt.hash_stable(hcx, hasher); } + ty::subst::GenericArgKind::Effect(e) => e.hash_stable(hcx, hasher), } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index da42eee38dd35..419137db97534 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2837,6 +2837,7 @@ define_print_and_forward_display! { GenericArgKind::Lifetime(lt) => p!(print(lt)), GenericArgKind::Type(ty) => p!(print(ty)), GenericArgKind::Const(ct) => p!(print(ct)), + GenericArgKind::Effect(e) => p!(print(e)), } } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 6ab079769ab03..6ba6e99fb8fe2 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -852,6 +852,9 @@ impl<'tcx> Relate<'tcx> for GenericArg<'tcx> { (GenericArgKind::Const(a_ct), GenericArgKind::Const(b_ct)) => { Ok(relation.relate(a_ct, b_ct)?.into()) } + (GenericArgKind::Effect(a), GenericArgKind::Effect(b)) => { + Ok(relation.relate(a, b)?.into()) + } (GenericArgKind::Lifetime(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } @@ -861,6 +864,9 @@ impl<'tcx> Relate<'tcx> for GenericArg<'tcx> { (GenericArgKind::Const(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } + (GenericArgKind::Effect(unpacked), x) => { + bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) + } } } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 0c33e5bda1a55..9d798e50a07fd 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -40,12 +40,14 @@ const TAG_MASK: usize = 0b11; const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; const CONST_TAG: usize = 0b10; +const EFFECT_TAG: usize = 0b11; #[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord)] pub enum GenericArgKind<'tcx> { Lifetime(ty::Region<'tcx>), Type(Ty<'tcx>), Const(ty::Const<'tcx>), + Effect(ty::Effect<'tcx>), } /// This function goes from `&'a [Ty<'tcx>]` to `&'a [GenericArg<'tcx>]` @@ -92,6 +94,11 @@ impl<'tcx> GenericArgKind<'tcx> { assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); (CONST_TAG, ct.0.0 as *const ty::ConstData<'tcx> as usize) } + GenericArgKind::Effect(e) => { + // Ensure we can use the tag bits. + assert_eq!(mem::align_of_val(&*e.0.0) & TAG_MASK, 0); + (EFFECT_TAG, e.0.0 as *const ty::EffectData<'tcx> as usize) + } }; GenericArg { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData } @@ -104,6 +111,7 @@ impl<'tcx> fmt::Debug for GenericArg<'tcx> { GenericArgKind::Lifetime(lt) => lt.fmt(f), GenericArgKind::Type(ty) => ty.fmt(f), GenericArgKind::Const(ct) => ct.fmt(f), + GenericArgKind::Effect(e) => e.fmt(f), } } } @@ -150,6 +158,13 @@ impl<'tcx> From> for GenericArg<'tcx> { } } +impl<'tcx> From> for GenericArg<'tcx> { + #[inline] + fn from(e: ty::Effect<'tcx>) -> GenericArg<'tcx> { + GenericArgKind::Effect(e).pack() + } +} + impl<'tcx> GenericArg<'tcx> { #[inline] pub fn unpack(self) -> GenericArgKind<'tcx> { @@ -168,6 +183,9 @@ impl<'tcx> GenericArg<'tcx> { CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked( &*((ptr & !TAG_MASK) as *const ty::ConstData<'tcx>), ))), + EFFECT_TAG => GenericArgKind::Effect(ty::Effect(Interned::new_unchecked( + &*((ptr & !TAG_MASK) as *const ty::EffectData<'tcx>), + ))), _ => intrinsics::unreachable(), } } @@ -204,6 +222,15 @@ impl<'tcx> GenericArg<'tcx> { GenericArgKind::Lifetime(_) => false, GenericArgKind::Type(ty) => ty.is_ty_infer(), GenericArgKind::Const(ct) => ct.is_ct_infer(), + GenericArgKind::Effect(e) => e.is_e_infer(), + } + } + + /// Unpack the `GenericArg` as an effect when it is known certainly to be an effect. + pub fn expect_effect(self) -> ty::Effect<'tcx> { + match self.unpack() { + GenericArgKind::Effect(e) => e, + _ => bug!("expected an effect, but found another kind"), } } } @@ -216,6 +243,7 @@ impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> { GenericArgKind::Lifetime(lt) => tcx.lift(lt).map(|lt| lt.into()), GenericArgKind::Type(ty) => tcx.lift(ty).map(|ty| ty.into()), GenericArgKind::Const(ct) => tcx.lift(ct).map(|ct| ct.into()), + GenericArgKind::Effect(e) => tcx.lift(e).map(|e| e.into()), } } } @@ -226,6 +254,7 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { GenericArgKind::Lifetime(lt) => lt.try_fold_with(folder).map(Into::into), GenericArgKind::Type(ty) => ty.try_fold_with(folder).map(Into::into), GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into), + GenericArgKind::Effect(e) => e.try_fold_with(folder).map(Into::into), } } } @@ -236,6 +265,7 @@ impl<'tcx> TypeVisitable<'tcx> for GenericArg<'tcx> { GenericArgKind::Lifetime(lt) => lt.visit_with(visitor), GenericArgKind::Type(ty) => ty.visit_with(visitor), GenericArgKind::Const(ct) => ct.visit_with(visitor), + GenericArgKind::Effect(e) => e.visit_with(visitor), } } } @@ -801,6 +831,15 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { c.super_fold_with(self) } } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + // FIXME(keyword_generics): handle other effects + if let ty::EffectValue::Param { index } = e.val { + self.effect_for_param(index, e) + } else { + e.super_fold_with(self) + } + } } impl<'a, 'tcx> SubstFolder<'a, 'tcx> { @@ -883,6 +922,41 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { ) } + fn effect_for_param(&self, p: u32, source_fx: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + // Look up the effect in the substitutions. It really should be in there. + let opt_ct = self.substs.get(p as usize).map(|k| k.unpack()); + let ct = match opt_ct { + Some(GenericArgKind::Effect(fx)) => fx, + Some(kind) => self.effect_param_expected(p, source_fx, kind), + None => self.effect_param_out_of_range(p, source_fx), + }; + + self.shift_vars_through_binders(ct) + } + + #[cold] + #[inline(never)] + fn effect_param_expected(&self, p: u32, fx: ty::Effect<'tcx>, kind: GenericArgKind<'tcx>) -> ! { + bug!( + "expected effect for {:?}/{} but found {:?} when substituting substs={:?}", + fx, + p, + kind, + self.substs, + ) + } + + #[cold] + #[inline(never)] + fn effect_param_out_of_range(&self, p: u32, fx: ty::Effect<'tcx>) -> ! { + bug!( + "effect parameter {:?}/{} out of range when substituting substs={:?}", + fx, + p, + self.substs, + ) + } + /// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs /// when we are substituting a type with escaping bound vars into a context where we have /// passed through binders. That's quite a mouthful. Let's see an example: diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 136a4906c58de..28566ac847f6e 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -668,6 +668,15 @@ impl<'tcx> CanonicalUserType<'tcx> { } _ => false, }, + + GenericArgKind::Effect(e) => match e.val { + ty::EffectValue::Bound(debruijn, b) => { + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(debruijn, ty::INNERMOST); + cvar == b + } + _ => false, + }, } }) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index cc53659f82798..43d30428d158e 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -448,6 +448,11 @@ impl<'tcx> TyCtxt<'tcx> { // Error: not a const param _ => false, }, + GenericArgKind::Effect(e) => match e.val { + ty::EffectValue::Param { .. } => true, + // Error: not an effect param + _ => false, + }, } }) .map(|(item_param, _)| item_param) @@ -491,6 +496,14 @@ impl<'tcx> TyCtxt<'tcx> { } _ => return Err(NotUniqueParam::NotParam(c.into())), }, + GenericArgKind::Effect(e) => match e.val { + ty::EffectValue::Param { index } => { + if !seen.insert(index) { + return Err(NotUniqueParam::DuplicateParam(arg)); + } + } + _ => return Err(NotUniqueParam::NotParam(arg)), + }, } } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index bcbee1f322619..bb4cf8d0f9252 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -133,6 +133,7 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone { self.has_type_flags( TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER + | TypeFlags::HAS_EFFECT_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER, ) } diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 708a5e4d059e8..40bcd19b1aaea 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -203,6 +203,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) } }, GenericArgKind::Lifetime(_) => {} + GenericArgKind::Effect(_) => {} GenericArgKind::Const(parent_ct) => { stack.push(parent_ct.ty().into()); match parent_ct.kind() { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 6470efab2e93c..292ace9f2024c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -248,6 +248,7 @@ impl<'tcx> ConstToPat<'tcx> { ty::subst::GenericArgKind::Lifetime(_) => false, ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(), ty::subst::GenericArgKind::Const(_) => false, + ty::subst::GenericArgKind::Effect(_) => false, }) } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b573df4325051..787a14019a65d 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -624,6 +624,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { .filter(|arg| match arg.unpack() { GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, GenericArgKind::Lifetime(_) => false, + GenericArgKind::Effect(_) => false, }) .count(); debug!(" => type length={}", type_length); diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 0759b95bd94c8..a319348f5ca94 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -35,6 +35,7 @@ enum DictKey<'tcx> { Ty(Ty<'tcx>, TyQ), Region(Region<'tcx>), Const(Const<'tcx>), + Effect(ty::Effect<'tcx>), Predicate(ExistentialPredicate<'tcx>), } @@ -162,6 +163,36 @@ fn encode_const<'tcx>( s } +/// Encodes an effect using the Itanium C++ ABI as a literal argument (see +/// ). +fn encode_effect<'tcx>( + _tcx: TyCtxt<'tcx>, + e: ty::Effect<'tcx>, + dict: &mut FxHashMap, usize>, + _options: EncodeTyOptions, +) -> String { + // L[n]E as literal argument + let mut s = String::from('L'); + match e.kind { + ty::EffectKind::Host => write!(s, "h").unwrap(), + } + match e.val { + ty::EffectValue::Rigid { on } => write!(s, "{}", on as usize).unwrap(), + ty::EffectValue::Param { .. } + | ty::EffectValue::Infer(_) + | ty::EffectValue::Err(_) + | ty::EffectValue::Bound(_, _) + | ty::EffectValue::Placeholder(_) => bug!("encode_effect: unexpected effect {e:?}"), + } + + // Close the "L..E" pair + s.push('E'); + + compress(dict, DictKey::Effect(e), &mut s); + + s +} + /// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for /// Rust types that are not used at the FFI boundary. #[instrument(level = "trace", skip(tcx, dict))] @@ -331,6 +362,9 @@ fn encode_substs<'tcx>( GenericArgKind::Const(c) => { s.push_str(&encode_const(tcx, c, dict, options)); } + GenericArgKind::Effect(e) => { + s.push_str(&encode_effect(tcx, e, dict, options)); + } } } s.push('E'); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 037753623c25e..29b362d32ee09 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -844,6 +844,9 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { self.push("K"); self = c.print(self)?; } + GenericArgKind::Effect(e) => { + self = e.print(self)?; + } } } self.push("E"); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 15526b34ed2d8..949b47a7bccd1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -1075,6 +1075,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Lifetimes aren't allowed to change during unsizing. GenericArgKind::Lifetime(_) => None, + // Effects aren't allowed to change during unsizing. + GenericArgKind::Effect(_) => None, + GenericArgKind::Const(ct) => match ct.kind() { ty::ConstKind::Param(p) => Some(p.index), _ => None, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 0e0a883d9f590..573d864415094 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -56,6 +56,9 @@ pub fn obligations<'tcx>( } // There is nothing we have to do for lifetimes. GenericArgKind::Lifetime(..) => return Some(Vec::new()), + + // There is nothing we have to do for effects. + GenericArgKind::Effect(..) => return Some(Vec::new()), }; let mut wf = WfPredicates { @@ -448,6 +451,9 @@ impl<'tcx> WfPredicates<'tcx> { // obligations are handled by the parent (e.g. `ty::Ref`). GenericArgKind::Lifetime(_) => continue, + // No WF constraints for effects being present + GenericArgKind::Effect(_) => continue, + GenericArgKind::Const(ct) => { match ct.kind() { ty::ConstKind::Unevaluated(uv) => { diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index f288eb112582d..b92ce85a5858b 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -762,6 +762,9 @@ fn binders_for<'tcx>( ty::subst::GenericArgKind::Const(c) => { chalk_ir::VariableKind::Const(c.ty().lower_into(interner)) } + ty::subst::GenericArgKind::Effect(_e) => { + unimplemented!() + } }), ) } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 9712abb708f27..abb13fd61a9c7 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -192,6 +192,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } GenericArgKind::Lifetime(lt) => bug!("unexpected well formed predicate: {:?}", lt), + GenericArgKind::Effect(e) => bug!("unexpected well formed predicate: {:?}", e), }, ty::PredicateKind::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal( @@ -580,6 +581,9 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GenericArg>> for Generic ty::subst::GenericArgKind::Const(c) => { chalk_ir::GenericArgData::Const(c.lower_into(interner)) } + ty::subst::GenericArgKind::Effect(_e) => { + unimplemented!() + } } .intern(interner) } diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 010233d7718c2..fe27dd349150b 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -133,6 +133,7 @@ fn compute_implied_outlives_bounds<'tcx>( push_outlives_components(tcx, ty_a, &mut components); implied_bounds_from_components(r_b, components) } + ty::GenericArgKind::Effect(_) => unreachable!(), ty::GenericArgKind::Const(_) => unreachable!(), }) .collect(); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 87923ebbe4bc9..4d3bee5b3f34e 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -326,6 +326,9 @@ fn well_formed_types_in_env(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List None, + + // FIXME(oli-obk) support effects in Chalk + GenericArgKind::Effect(_) => None, } }); diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index a12f764fa8e3b..9afdabd3c73bd 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -101,6 +101,8 @@ pub(crate) fn substs_to_args<'tcx>( GenericArgKind::Const(ct) => { Some(GenericArg::Const(Box::new(clean_middle_const(kind.rebind(ct), cx)))) } + // FIXME(oli-obk,keyword-generics): teach rustdoc about effects + GenericArgKind::Effect(_) => None, })); ret_val } diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 61f87b91400d7..fad6aa5d19ad4 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { let init_ty = cx.typeck_results().expr_ty(init); let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)), - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + GenericArgKind::Effect(_) | GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }); if contains_sync_guard { span_lint_and_help( diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs index 714c0ff227bf8..93f77c95e87d9 100644 --- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -212,6 +212,7 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t substs.iter().all(|generic_arg| match generic_arg.unpack() { GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait), // Lifetimes and const generics are not solid part of ADT and ignored + GenericArgKind::Effect(_) | GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true, }) } else { diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index 7722a476d7b4e..f9b166aa3e645 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -388,6 +388,7 @@ fn has_matching_substs(kind: FnKind, substs: SubstsRef<'_>) -> bool { GenericArgKind::Lifetime(_) => true, GenericArgKind::Type(ty) => matches!(*ty.kind(), ty::Param(ty) if ty.index as usize == idx), GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx), + GenericArgKind::Effect(e) => matches!(e.val, ty::EffectValue::Param { index } if index as usize == idx), }), #[allow(trivial_casts)] FnKind::ImplTraitFn(expected_substs) => substs as *const _ as usize == expected_substs, diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index e5d7da682813c..2a155bde60267 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -75,6 +75,7 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { // No constraints on lifetimes or constants, except potentially // constants' types, but `walk` will get to them as well. + GenericArgKind::Effect(_) | GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, }; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index c8d56a3be5cf3..05f21c1090cfb 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -59,6 +59,7 @@ pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool { ty.walk().any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt), + GenericArgKind::Effect(_) | GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }) } @@ -121,7 +122,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' false }, - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + GenericArgKind::Lifetime(_) | GenericArgKind::Effect(_) | GenericArgKind::Const(_) => false, }) } From 82f21302cc09aa8df99b24752176abe69264dd65 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 16 Sep 2022 16:02:11 +0000 Subject: [PATCH 08/13] Add GenericParamDefKind::Effect --- .../locales/en-US/middle.ftl | 4 +- .../rustc_hir_analysis/src/astconv/mod.rs | 21 +++++++ .../src/check/compare_impl_item.rs | 22 ++++++- .../rustc_hir_analysis/src/check/wfcheck.rs | 10 +-- compiler/rustc_hir_analysis/src/collect.rs | 9 +++ .../rustc_hir_analysis/src/impl_wf_check.rs | 5 ++ .../rustc_hir_analysis/src/variance/mod.rs | 1 + .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 1 + compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 20 +++++- .../src/generator_interior/mod.rs | 1 + compiler/rustc_hir_typeck/src/method/mod.rs | 4 +- compiler/rustc_hir_typeck/src/method/probe.rs | 12 +++- .../rustc_hir_typeck/src/method/suggest.rs | 7 +-- compiler/rustc_hir_typeck/src/writeback.rs | 12 ++++ .../src/infer/canonical/substitute.rs | 6 ++ compiler/rustc_infer/src/infer/fudge.rs | 16 +++++ .../src/infer/higher_ranked/mod.rs | 9 +++ compiler/rustc_infer/src/infer/mod.rs | 61 ++++++++++++++++++- compiler/rustc_infer/src/infer/resolve.rs | 17 ++++++ compiler/rustc_middle/src/error.rs | 6 +- compiler/rustc_middle/src/infer/unify_key.rs | 1 + compiler/rustc_middle/src/ty/context.rs | 30 ++++++++- compiler/rustc_middle/src/ty/flags.rs | 3 + compiler/rustc_middle/src/ty/fold.rs | 43 +++++++++++++ compiler/rustc_middle/src/ty/generics.rs | 32 ++++++---- compiler/rustc_middle/src/ty/instance.rs | 3 + .../src/ty/normalize_erasing_regions.rs | 4 ++ compiler/rustc_middle/src/ty/opaque_types.rs | 30 ++++++++- compiler/rustc_middle/src/ty/print/pretty.rs | 1 + compiler/rustc_middle/src/ty/sty.rs | 8 +++ compiler/rustc_middle/src/ty/subst.rs | 1 - compiler/rustc_monomorphize/src/collector.rs | 1 + compiler/rustc_privacy/src/lib.rs | 2 + .../error_reporting/on_unimplemented.rs | 14 +++-- .../src/traits/error_reporting/suggestions.rs | 4 +- .../src/traits/select/confirmation.rs | 12 ++++ .../src/traits/vtable.rs | 1 + compiler/rustc_traits/src/chalk/db.rs | 4 ++ compiler/rustc_type_ir/src/lib.rs | 3 + src/librustdoc/clean/auto_trait.rs | 1 + src/librustdoc/clean/mod.rs | 9 ++- src/librustdoc/clean/types.rs | 5 +- src/librustdoc/html/format.rs | 9 +++ src/librustdoc/json/conversions.rs | 1 + src/rustdoc-json-types/lib.rs | 1 + src/tools/jsondoclint/src/validator.rs | 1 + 46 files changed, 418 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl index 4f4e5c6a2c9c2..e174134bd9cfb 100644 --- a/compiler/rustc_error_messages/locales/en-US/middle.ftl +++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl @@ -32,5 +32,5 @@ middle_strict_coherence_needs_negative_coherence = to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled .label = due to this attribute -middle_const_not_used_in_type_alias = - const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias +middle_param_not_used_in_type_alias = + parameter `{$param}` is part of concrete type but not used in parameter list for the `impl Trait` type alias diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 9a111cb8609fd..99df472ad5d13 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -91,6 +91,14 @@ pub trait AstConv<'tcx> { span: Span, ) -> Const<'tcx>; + /// Returns the effect to use when an effect is omitted. + fn effect_infer( + &self, + kind: ty::EffectKind, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> ty::Effect<'tcx>; + /// Projecting an associated type from a (potentially) /// higher-ranked trait reference is more complicated, because of /// the possibility of late-bound regions appearing in the @@ -518,6 +526,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } } + GenericParamDefKind::Effect { kind } => { + if infer_args { + self.astconv.effect_infer(kind, Some(param), self.span).into() + } else { + // We've already errored above about the mismatch. + tcx.effect_error_with_message( + self.span, + "non-inference missing effect args", + kind, + ) + .into() + } + } } } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 0d3391bbc1efb..3c36af35acc0f 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1328,11 +1328,15 @@ fn compare_synthetic_generics<'tcx>( let trait_m_generics = tcx.generics_of(trait_m.def_id); let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind { GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None, + GenericParamDefKind::Lifetime + | GenericParamDefKind::Effect { .. } + | GenericParamDefKind::Const { .. } => None, }); let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| match param.kind { GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None, + GenericParamDefKind::Lifetime + | GenericParamDefKind::Effect { .. } + | GenericParamDefKind::Const { .. } => None, }); for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in iter::zip(impl_m_type_params, trait_m_type_params) @@ -1503,6 +1507,7 @@ fn compare_generic_param_kinds<'tcx>( // to make sure this error is reported for them. (Const { .. }, Const { .. }) | (Type { .. }, Type { .. }) => false, (Lifetime { .. }, _) | (_, Lifetime { .. }) => unreachable!(), + (Effect { .. }, _) | (_, Effect { .. }) => unreachable!(), } { let param_impl_span = tcx.def_span(param_impl.def_id); let param_trait_span = tcx.def_span(param_trait.def_id); @@ -1523,6 +1528,7 @@ fn compare_generic_param_kinds<'tcx>( } Type { .. } => format!("{} type parameter", prefix), Lifetime { .. } => unreachable!(), + Effect { .. } => unreachable!(), }; let trait_header_span = tcx.def_ident_span(tcx.parent(trait_item.def_id)).unwrap(); @@ -1857,6 +1863,18 @@ pub(super) fn check_type_bounds<'tcx>( ) .into() } + GenericParamDefKind::Effect { kind } => { + let bound_var = ty::BoundVariableKind::Effect; + bound_vars.push(bound_var); + tcx.mk_effect( + ty::EffectValue::Bound( + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), + ), + kind, + ) + .into() + } }); let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter()); let impl_ty_substs = tcx.intern_substs(&substs); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index d70d0ddcca6ff..c47a705352ec9 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1304,7 +1304,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id | GenericParamDefKind::Const { has_default } => { has_default && def.index >= generics.parent_count as u32 } - GenericParamDefKind::Lifetime => unreachable!(), + GenericParamDefKind::Effect { .. } | GenericParamDefKind::Lifetime => unreachable!(), }; // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`. @@ -1346,8 +1346,8 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } } } - // Doesn't have defaults. - GenericParamDefKind::Lifetime => {} + // Don't have defaults. + GenericParamDefKind::Effect { .. } | GenericParamDefKind::Lifetime => {} } } @@ -1361,8 +1361,8 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // First we build the defaulted substitution. let substs = InternalSubsts::for_item(tcx, def_id.to_def_id(), |param, _| { match param.kind { - GenericParamDefKind::Lifetime => { - // All regions are identity. + GenericParamDefKind::Effect { .. } | GenericParamDefKind::Lifetime => { + // All regions and effects are identity. tcx.mk_param_from_def(param) } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 7afde550b42ad..9157c92ae486e 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -405,6 +405,15 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx().const_error_with_message(ty, span, "bad placeholder constant") } + fn effect_infer( + &self, + kind: ty::EffectKind, + _: Option<&ty::GenericParamDef>, + span: Span, + ) -> ty::Effect<'tcx> { + span_bug!(span, "bad placeholder effect: {kind:?}") + } + fn projected_ty_from_poly_trait_ref( &self, span: Span, diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 136f6199911a0..9078a80d38fe4 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -147,6 +147,11 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) ); } } + ty::GenericParamDefKind::Effect { .. } => { + if !input_parameters.contains(&cgp::Parameter(param.index)) { + report_unused_parameter(tcx, tcx.def_span(param.def_id), "effect", param.name); + } + } } } diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 24008f8881433..7d8e492f9fc27 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -140,6 +140,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc variances[param.index as usize] = ty::Bivariant; } ty::GenericParamDefKind::Type { .. } + | ty::GenericParamDefKind::Effect { .. } | ty::GenericParamDefKind::Const { .. } => {} } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 634688de01a65..2d6e8a332551a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1246,6 +1246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.fcx.var_for_def(self.span, param) } } + GenericParamDefKind::Effect { .. } => self.fcx.var_for_def(self.span, param), } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 30b59da7852d4..b04995da0c7fa 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -15,7 +15,9 @@ use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_middle::infer::unify_key::{ + ConstVariableOrigin, ConstVariableOriginKind, EffectVariableOriginKind, +}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; @@ -274,6 +276,22 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } } + fn effect_infer( + &self, + kind: ty::EffectKind, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> ty::Effect<'tcx> { + if let Some(param) = param { + if let GenericArgKind::Effect(e) = self.var_for_def(span, param).unpack() { + return e; + } + unreachable!() + } else { + self.next_effect_var(span, EffectVariableOriginKind::EffectInference, kind) + } + } + fn projected_ty_from_poly_trait_ref( &self, span: Span, diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index e4ac91befac61..827c019b2426d 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -296,6 +296,7 @@ pub fn resolve_interior<'a, 'tcx>( }, types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"), consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"), + effects: &mut |b, kind| bug!("unexpected bound effect in binder: {b:?} {kind:?}"), }, ) } else { diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index d276bcdb81e3e..f7a1b926dd15b 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -278,7 +278,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Construct a trait-reference `self_ty : Trait` let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { match param.kind { - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {} + GenericParamDefKind::Lifetime + | GenericParamDefKind::Const { .. } + | GenericParamDefKind::Effect { .. } => {} GenericParamDefKind::Type { .. } => { if param.index == 0 { return self_ty.into(); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 2daf1979ee5e6..1363426945ad0 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -13,6 +13,7 @@ use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; +use rustc_middle::infer::unify_key::EffectVariableOriginKind; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::middle::stability; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; @@ -1845,9 +1846,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // In general, during probe we erase regions. self.tcx.lifetimes.re_erased.into() } - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { - self.var_for_def(self.span, param) - } + GenericParamDefKind::Type { .. } + | GenericParamDefKind::Const { .. } + | GenericParamDefKind::Effect { .. } => self.var_for_def(self.span, param), } } }); @@ -1882,6 +1883,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }; self.next_const_var(self.tcx.type_of(param.def_id), origin).into() } + GenericParamDefKind::Effect { kind } => { + let span = self.tcx.def_span(def_id); + self.next_effect_var(span, EffectVariableOriginKind::SubstitutionPlaceholder, kind) + .into() + } }) } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 8d57939badddd..9ff3fcf359d4f 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -21,7 +21,6 @@ use rustc_infer::infer::{ type_variable::{TypeVariableOrigin, TypeVariableOriginKind}, RegionVariableOrigin, }; -use rustc_middle::infer::unify_key::EffectVariableOrigin; use rustc_middle::infer::unify_key::EffectVariableOriginKind; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::util::supertraits; @@ -1191,11 +1190,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into(), GenericArgKind::Effect(e) => self .next_effect_var( + rustc_span::DUMMY_SP, + EffectVariableOriginKind::MiscVariable, e.kind, - EffectVariableOrigin { - span: rustc_span::DUMMY_SP, - kind: EffectVariableOriginKind::MiscVariable, - }, ) .into(), } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index bb956ddc78042..6dc34daf39136 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -797,6 +797,18 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } } } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + match self.infcx.fully_resolve(e) { + Ok(e) => e, + Err(_) => { + debug!("Resolver::fold_effect: input effect `{e:?}` not fully resolvable"); + let err = self.report_error(e); + self.replaced_with_error = Some(err); + self.tcx().effect_error(e.kind) + } + } + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs index 389afe22eb767..84c75a208e969 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs @@ -85,6 +85,12 @@ where GenericArgKind::Const(ct) => ct, c => bug!("{:?} is a const but value is {:?}", bound_ct, c), }, + effects: &mut |bound_effect: ty::BoundVar, _| match var_values.var_values[bound_effect] + .unpack() + { + GenericArgKind::Effect(e) => e, + c => bug!("{:?} is an effect but value is {:?}", bound_effect, c), + }, }; tcx.replace_escaping_bound_vars_uncached(value, delegate) diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index 488b2409b1cc8..5ae368f835f4c 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -266,4 +266,20 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { ct.super_fold_with(self) } } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + if let ty::EffectValue::Infer(ty::InferEffect::Var(vid)) = e.val { + if self.effect_vars.0.contains(&vid) { + // This variable was created during the fudging. + // Recreate it with a fresh variable here. + let idx = (vid.index - self.effect_vars.0.start.index) as usize; + let origin = self.effect_vars.1[idx]; + self.infcx.next_effect_var(origin.span, origin.kind, e.kind) + } else { + e + } + } else { + e.super_fold_with(self) + } + } } diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index 817ae10c76087..ec0e14cd75050 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -97,6 +97,15 @@ impl<'tcx> InferCtxt<'tcx> { self.tcx .mk_const(ty::PlaceholderConst { universe: next_universe, name: bound_var }, ty) }, + effects: &mut |bound_var: ty::BoundVar, kind| { + self.tcx.mk_effect( + ty::EffectValue::Placeholder(ty::PlaceholderEffect { + universe: next_universe, + name: bound_var, + }), + kind, + ) + }, }; debug!(?next_universe); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 5939326d2857e..e82e95e79256d 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -20,6 +20,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::infer::unify_key::EffectVariableOrigin; +use rustc_middle::infer::unify_key::EffectVariableOriginKind; use rustc_middle::infer::unify_key::EffectVariableValue; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; @@ -1090,10 +1091,14 @@ impl<'tcx> InferCtxt<'tcx> { pub fn next_effect_var( &self, + span: Span, + origin: EffectVariableOriginKind, kind: ty::EffectKind, - origin: EffectVariableOrigin, ) -> ty::Effect<'tcx> { - self.tcx.mk_effect(self.next_effect_var_id(origin), kind) + self.tcx.mk_effect( + self.next_effect_var_id(EffectVariableOrigin { span, kind: origin, effect_kind: kind }), + kind, + ) } pub fn next_effect_var_in_universe( @@ -1225,6 +1230,25 @@ impl<'tcx> InferCtxt<'tcx> { }); self.tcx.mk_const(const_var_id, self.tcx.type_of(param.def_id)).into() } + GenericParamDefKind::Effect { kind } => { + let origin = EffectVariableOrigin { + kind: EffectVariableOriginKind::EffectParameterDefinition( + param.name, + param.def_id, + ), + span, + effect_kind: kind, + }; + let var_id = + self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue { + origin, + val: EffectVariableValue::Unknown { universe: self.universe() }, + }); + + self.tcx + .mk_effect(ty::EffectValue::Infer(ty::InferEffect::Var(var_id)), kind) + .into() + } } } @@ -1549,6 +1573,24 @@ impl<'tcx> InferCtxt<'tcx> { }) .expect_const() } + fn replace_effects( + &mut self, + bv: ty::BoundVar, + kind: ty::EffectKind, + ) -> ty::Effect<'tcx> { + self.map + .entry(bv) + .or_insert_with(|| { + self.infcx + .next_effect_var( + self.span, + EffectVariableOriginKind::MiscVariable, + kind, + ) + .into() + }) + .expect_effect() + } } let delegate = ToFreshVars { infcx: self, span, lbrct, map: Default::default() }; self.tcx.replace_bound_vars_uncached(value, delegate) @@ -1969,6 +2011,21 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { ct } } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + if let ty::EffectValue::Infer(ty::InferEffect::Var(vid)) = e.val { + self.infcx + .inner + .borrow_mut() + .effect_unification_table() + .probe_value(vid) + .val + .known() + .unwrap_or(e) + } else { + e + } + } } impl<'tcx> TypeTrace<'tcx> { diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 8671f8d45a917..39f2e7f4ae9fc 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -48,6 +48,15 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> { ct.super_fold_with(self) } } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + if !e.has_non_region_infer() { + e // micro-optimize -- if there is nothing in this effect that this fold affects... + } else { + let e = self.infcx.shallow_resolve(e); + e.super_fold_with(self) + } + } } /// The opportunistic region resolver opportunistically resolves regions @@ -102,6 +111,14 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> { ct.super_fold_with(self) } } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + if !e.has_infer_regions() { + e // micro-optimize -- if there is nothing in this effect that this fold affects... + } else { + e.super_fold_with(self) + } + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 5e94da8cb4d36..d9f5161399767 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -66,9 +66,9 @@ pub(crate) struct StrictCoherenceNeedsNegativeCoherence { } #[derive(Diagnostic)] -#[diag(middle_const_not_used_in_type_alias)] -pub(super) struct ConstNotUsedTraitAlias { - pub ct: String, +#[diag(middle_param_not_used_in_type_alias)] +pub(super) struct ParamNotUsedTraitAlias { + pub param: String, #[primary_span] pub span: Span, } diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 1f0fbea91d939..86dbee3ca1e09 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -167,6 +167,7 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { pub struct EffectVariableOrigin { pub kind: EffectVariableOriginKind, pub span: Span, + pub effect_kind: ty::EffectKind, } /// Reasons to create a effect inference variable diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index fef60a08e7568..029f61af12ee0 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -712,6 +712,28 @@ impl<'tcx> TyCtxt<'tcx> { ) } + /// Like [TyCtxt::ty_error] but for effects. + #[track_caller] + pub fn effect_error(self, kind: ty::EffectKind) -> ty::Effect<'tcx> { + self.effect_error_with_message( + DUMMY_SP, + "ty::EffectValue::Error constructed but no error reported", + kind, + ) + } + + /// Like [TyCtxt::ty_error] but for effects. + #[track_caller] + pub fn effect_error_with_message( + self, + span: Span, + msg: &str, + kind: ty::EffectKind, + ) -> ty::Effect<'tcx> { + let reported = self.sess.delay_span_bug(span, msg); + self.mk_effect(ty::EffectValue::Err(reported), kind) + } + /// Like [TyCtxt::ty_error_with_message] but for constants. #[track_caller] pub fn const_error_with_message>( @@ -1834,7 +1856,9 @@ impl<'tcx> TyCtxt<'tcx> { let adt_def = self.adt_def(wrapper_def_id); let substs = InternalSubsts::for_item(self, wrapper_def_id, |param, substs| match param.kind { - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => bug!(), + GenericParamDefKind::Effect { .. } + | GenericParamDefKind::Lifetime + | GenericParamDefKind::Const { .. } => bug!(), GenericParamDefKind::Type { has_default, .. } => { if param.index == 0 { ty_param.into() @@ -2055,6 +2079,10 @@ impl<'tcx> TyCtxt<'tcx> { self.type_of(param.def_id), ) .into(), + + GenericParamDefKind::Effect { kind } => { + self.mk_effect(ty::EffectValue::Param { index: param.index }, kind).into() + } } } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 0327ff8dd9fd2..b082521c922f6 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -78,6 +78,9 @@ impl FlagComputation { ty::BoundVariableKind::Const => { computation.flags |= TypeFlags::HAS_CT_LATE_BOUND; } + ty::BoundVariableKind::Effect => { + computation.flags |= TypeFlags::HAS_EFFECT_LATE_BOUND; + } } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index bc28249f70729..8cea8fdb18217 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -368,12 +368,14 @@ pub trait BoundVarReplacerDelegate<'tcx> { fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>; fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>; fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx>; + fn replace_effects(&mut self, bv: ty::BoundVar, kind: ty::EffectKind) -> ty::Effect<'tcx>; } pub struct FnMutDelegate<'a, 'tcx> { pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), pub consts: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a), + pub effects: &'a mut (dyn FnMut(ty::BoundVar, ty::EffectKind) -> ty::Effect<'tcx> + 'a), } impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { @@ -386,6 +388,9 @@ impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> { (self.consts)(bv, ty) } + fn replace_effects(&mut self, bv: ty::BoundVar, kind: ty::EffectKind) -> ty::Effect<'tcx> { + (self.effects)(bv, kind) + } } /// Replaces the escaping bound vars (late bound regions or bound types) in a type. @@ -465,6 +470,16 @@ where } } + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + match e.val { + ty::EffectValue::Bound(debruijn, bound_effect) if debruijn == self.current_index => { + let e = self.delegate.replace_effects(bound_effect, e.kind); + ty::fold::shift_vars(self.tcx, e, self.current_index.as_u32()) + } + _ => e.super_fold_with(self), + } + } + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } @@ -516,6 +531,7 @@ impl<'tcx> TyCtxt<'tcx> { regions: &mut replace_regions, types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"), consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"), + effects: &mut |b, kind| bug!("unexpected bound effect in binder: {b:?} {kind:?}"), }; let mut replacer = BoundVarReplacer::new(self, delegate); value.fold_with(&mut replacer) @@ -590,6 +606,9 @@ impl<'tcx> TyCtxt<'tcx> { consts: &mut |c, ty: Ty<'tcx>| { self.mk_const(ty::ConstKind::Bound(ty::INNERMOST, shift_bv(c)), ty) }, + effects: &mut |e, kind| { + self.mk_effect(ty::EffectValue::Bound(ty::INNERMOST, shift_bv(e)), kind) + }, }, ) } @@ -641,6 +660,17 @@ impl<'tcx> TyCtxt<'tcx> { let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const(); self.tcx.mk_const(ty::ConstKind::Bound(ty::INNERMOST, var), ty) } + fn replace_effects( + &mut self, + bv: ty::BoundVar, + kind: ty::EffectKind, + ) -> ty::Effect<'tcx> { + let entry = self.map.entry(bv); + let index = entry.index(); + let var = ty::BoundVar::from_usize(index); + let () = entry.or_insert_with(|| ty::BoundVariableKind::Effect).expect_effect(); + self.tcx.mk_effect(ty::EffectValue::Bound(ty::INNERMOST, var), kind) + } } let mut map = Default::default(); @@ -724,6 +754,19 @@ impl<'tcx> TypeFolder<'tcx> for Shifter<'tcx> { fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + if let ty::EffectValue::Bound(debruijn, bound_effect) = e.val { + if self.amount == 0 || debruijn < self.current_index { + e + } else { + let debruijn = debruijn.shifted_in(self.amount); + self.tcx.mk_effect(ty::EffectValue::Bound(debruijn, bound_effect), e.kind) + } + } else { + e.super_fold_with(self) + } + } } pub fn shift_region<'tcx>( diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 705adecd3b90f..b0bc36773172d 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -13,6 +13,7 @@ pub enum GenericParamDefKind { Lifetime, Type { has_default: bool, synthetic: bool }, Const { has_default: bool }, + Effect { kind: ty::EffectKind }, } impl GenericParamDefKind { @@ -21,20 +22,21 @@ impl GenericParamDefKind { GenericParamDefKind::Lifetime => "lifetime", GenericParamDefKind::Type { .. } => "type", GenericParamDefKind::Const { .. } => "constant", + GenericParamDefKind::Effect { .. } => "effect", } } pub fn to_ord(&self) -> ast::ParamKindOrd { match self { GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime, - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { - ast::ParamKindOrd::TypeOrConst - } + GenericParamDefKind::Type { .. } + | GenericParamDefKind::Const { .. } + | GenericParamDefKind::Effect { .. } => ast::ParamKindOrd::TypeOrConst, } } pub fn is_ty_or_const(&self) -> bool { match self { - GenericParamDefKind::Lifetime => false, + GenericParamDefKind::Effect { .. } | GenericParamDefKind::Lifetime => false, GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => true, } } @@ -79,10 +81,7 @@ impl GenericParamDef { } } - pub fn default_value<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - ) -> Option>> { + fn default_value<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option>> { match self.kind { GenericParamDefKind::Type { has_default, .. } if has_default => { Some(tcx.bound_type_of(self.def_id).map_bound(|t| t.into())) @@ -99,9 +98,10 @@ impl GenericParamDef { tcx: TyCtxt<'tcx>, preceding_substs: &[ty::GenericArg<'tcx>], ) -> ty::GenericArg<'tcx> { - match &self.kind { + match self.kind { ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), ty::GenericParamDefKind::Type { .. } => tcx.ty_error().into(), + ty::GenericParamDefKind::Effect { kind, .. } => tcx.effect_error(kind).into(), ty::GenericParamDefKind::Const { .. } => { tcx.const_error(tcx.bound_type_of(self.def_id).subst(tcx, preceding_substs)).into() } @@ -114,6 +114,7 @@ pub struct GenericParamCount { pub lifetimes: usize, pub types: usize, pub consts: usize, + pub effects: usize, } /// Information about the formal type/lifetime parameters associated @@ -167,6 +168,7 @@ impl<'tcx> Generics { GenericParamDefKind::Lifetime => own_counts.lifetimes += 1, GenericParamDefKind::Type { .. } => own_counts.types += 1, GenericParamDefKind::Const { .. } => own_counts.consts += 1, + GenericParamDefKind::Effect { .. } => own_counts.effects += 1, } } @@ -179,6 +181,7 @@ impl<'tcx> Generics { for param in &self.params { match param.kind { GenericParamDefKind::Lifetime => (), + GenericParamDefKind::Effect { .. } => (), GenericParamDefKind::Type { has_default, .. } => { own_defaults.types += has_default as usize; } @@ -207,7 +210,9 @@ impl<'tcx> Generics { pub fn own_requires_monomorphization(&self) -> bool { for param in &self.params { match param.kind { - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + GenericParamDefKind::Effect { .. } + | GenericParamDefKind::Type { .. } + | GenericParamDefKind::Const { .. } => { return true; } GenericParamDefKind::Lifetime => {} @@ -298,9 +303,10 @@ impl<'tcx> Generics { .iter() .rev() .take_while(|param| { - param.default_value(tcx).map_or(false, |default| { - default.subst(tcx, substs) == substs[param.index as usize] - }) + matches!(param.kind, ty::GenericParamDefKind::Effect { .. }) + || param.default_value(tcx).map_or(false, |default| { + default.subst(tcx, substs) == substs[param.index as usize] + }) }) .count(); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 35d369ffc891c..435f05bb972d0 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -338,6 +338,9 @@ impl<'tcx> Instance<'tcx> { ty::GenericParamDefKind::Const { .. } => { bug!("Instance::mono: {:?} has const parameters", def_id) } + ty::GenericParamDefKind::Effect { .. } => { + bug!("Instance::mono: {:?} has effect parameters", def_id) + } }); Instance::new(def_id, substs) diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index ee13920d52edd..54b1ee890ffa1 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -214,6 +214,10 @@ impl<'tcx> TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> { fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const() } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + self.normalize_generic_arg_after_erasing_regions(e.into()).expect_effect() + } } struct TryNormalizeAfterErasingRegionsFolder<'tcx> { diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 98cd92007c2b2..b192d97f2b09a 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -1,4 +1,4 @@ -use crate::error::ConstNotUsedTraitAlias; +use crate::error::ParamNotUsedTraitAlias; use crate::ty::fold::{TypeFolder, TypeSuperFoldable}; use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -202,8 +202,8 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { Some(u) => panic!("const mapped to unexpected kind: {:?}", u), None => { if !self.ignore_errors { - self.tcx.sess.emit_err(ConstNotUsedTraitAlias { - ct: ct.to_string(), + self.tcx.sess.emit_err(ParamNotUsedTraitAlias { + param: ct.to_string(), span: self.span, }); } @@ -216,4 +216,28 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { _ => ct, } } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + match e.val { + ty::EffectValue::Param { .. } => { + // Look it up in the substitution list. + match self.map.get(&e.into()).map(|k| k.unpack()) { + // Found it in the substitution list, replace with the parameter from the + // opaque type. + Some(GenericArgKind::Effect(e)) => e, + Some(u) => panic!("effect mapped to unexpected kind: {:?}", u), + None => { + self.tcx.sess.emit_err(ParamNotUsedTraitAlias { + param: e.to_string(), + span: self.span, + }); + + self.tcx().effect_error(e.kind) + } + } + } + + _ => e, + } + } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 419137db97534..50123c70619a3 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2769,6 +2769,7 @@ define_print_and_forward_display! { if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl { p!("~const "); } + p!(print(self.trait_ref.print_only_trait_path())) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index f7e4c8215698e..27cb1ce83b9cf 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -930,6 +930,7 @@ pub enum BoundVariableKind { Ty(BoundTyKind), Region(BoundRegionKind), Const, + Effect, } impl BoundVariableKind { @@ -953,6 +954,13 @@ impl BoundVariableKind { _ => bug!("expected a const, but found another kind"), } } + + pub fn expect_effect(self) { + match self { + BoundVariableKind::Effect => (), + _ => bug!("expected a effect, but found another kind"), + } + } } /// Binder is a binder for higher-ranked lifetimes or types. It is part of the diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 9d798e50a07fd..0cc416842984f 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -833,7 +833,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { } fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { - // FIXME(keyword_generics): handle other effects if let ty::EffectValue::Param { index } = e.val { self.effect_for_param(index, e) } else { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 787a14019a65d..46d79db237ab3 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1369,6 +1369,7 @@ fn create_mono_items_for_default_impls<'tcx>( InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind { GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), GenericParamDefKind::Type { .. } + | GenericParamDefKind::Effect { .. } | GenericParamDefKind::Const { .. } => { trait_ref.substs[param.index as usize] } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 8fe47d862e77d..a8327f61f8f2b 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -830,6 +830,7 @@ impl ReachEverythingInTheInterfaceVisitor<'_, '_> { for param in &self.ev.tcx.generics_of(self.item_def_id).params { match param.kind { GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Effect { .. } => {} GenericParamDefKind::Type { has_default, .. } => { if has_default { self.visit(self.ev.tcx.type_of(param.def_id)); @@ -1735,6 +1736,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { for param in &self.tcx.generics_of(self.item_def_id).params { match param.kind { GenericParamDefKind::Lifetime => {} + GenericParamDefKind::Effect { .. } => {} GenericParamDefKind::Type { has_default, .. } => { if has_default { self.visit(self.tcx.type_of(param.def_id)); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index b0a730c8ad168..3bc2d97ab426f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -191,9 +191,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { for param in generics.params.iter() { let value = match param.kind { - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { - substs[param.index as usize].to_string() - } + GenericParamDefKind::Effect { .. } + | GenericParamDefKind::Type { .. } + | GenericParamDefKind::Const { .. } => substs[param.index as usize].to_string(), GenericParamDefKind::Lifetime => continue, }; let name = param.name; @@ -609,10 +609,14 @@ impl<'tcx> OnUnimplementedFormatString { .iter() .filter_map(|param| { let value = match param.kind { - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + GenericParamDefKind::Effect { .. } + | GenericParamDefKind::Type { .. } + | GenericParamDefKind::Const { .. } => { trait_ref.substs[param.index as usize].to_string() } - GenericParamDefKind::Lifetime => return None, + GenericParamDefKind::Lifetime => { + return None; + } }; let name = param.name; Some((name, value)) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index c52365ae3b7c7..68cd686f33b0f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3553,7 +3553,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return prev_ty.into(); } } - ty::GenericParamDefKind::Lifetime | ty::GenericParamDefKind::Const { .. } => {} + ty::GenericParamDefKind::Effect { .. } + | ty::GenericParamDefKind::Lifetime + | ty::GenericParamDefKind::Const { .. } => {} } self.var_for_def(span, param) }); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 949b47a7bccd1..1f0689e051509 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -564,6 +564,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) .into() } + GenericParamDefKind::Effect { kind } => { + let bound_var = ty::BoundVariableKind::Effect; + bound_vars.push(bound_var); + tcx.mk_effect( + ty::EffectValue::Bound( + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), + ), + kind, + ) + .into() + } }); let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter()); let assoc_ty_substs = tcx.intern_substs(&substs); diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 5ec9c2a24cd44..47c6ba07fbce8 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -244,6 +244,7 @@ fn vtable_entries<'tcx>( InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind { GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), GenericParamDefKind::Type { .. } + | GenericParamDefKind::Effect { .. } | GenericParamDefKind::Const { .. } => { trait_ref.substs[param.index as usize] } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index b92ce85a5858b..9b79239b83a29 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -745,6 +745,10 @@ fn bound_vars_for_item(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> { tcx.type_of(param.def_id), ) .into(), + + ty::GenericParamDefKind::Effect { kind } => tcx + .mk_effect(ty::EffectValue::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)), kind) + .into(), }) } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index f1c0fc66f38d8..783515173b6e0 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -283,6 +283,9 @@ bitflags! { /// Does this have `Effect::Placeholder`? const HAS_EFFECT_PLACEHOLDER = 1 << 25; + + /// Does this have any `Effect::Bound` consts? + const HAS_EFFECT_LATE_BOUND = 1 << 26; } } diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 4d6f1524732f7..e529441586f61 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -645,6 +645,7 @@ where } } GenericParamDefKind::Lifetime { .. } => {} + GenericParamDefKind::Effect { .. } => {} GenericParamDefKind::Const { ref mut default, .. } => { // We never want something like `impl` default.take(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 025a4379f45a3..bc01a63b2aa77 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -511,6 +511,9 @@ fn clean_generic_param_def<'tcx>( }, }, ), + ty::GenericParamDefKind::Effect { .. } => { + (def.name, GenericParamDefKind::Effect { did: def.def_id }) + } }; GenericParamDef { name, kind } @@ -609,6 +612,7 @@ pub(crate) fn clean_generics<'tcx>( cx.impl_trait_bounds.insert(did.into(), bounds.clone()); } GenericParamDefKind::Const { .. } => unreachable!(), + GenericParamDefKind::Effect { .. } => unreachable!(), } param }) @@ -688,7 +692,9 @@ pub(crate) fn clean_generics<'tcx>( } } } - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + GenericParamDefKind::Type { .. } + | GenericParamDefKind::Effect { .. } + | GenericParamDefKind::Const { .. } => { // nothing to do here. } } @@ -745,6 +751,7 @@ fn clean_ty_generics<'tcx>( Some(clean_generic_param_def(param, cx)) } ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)), + ty::GenericParamDefKind::Effect { .. } => None, }) .collect::>(); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 827afafbba3b6..41fefc01aa77b 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1424,6 +1424,7 @@ pub(crate) enum GenericParamDefKind { Lifetime { outlives: Vec }, Type { did: DefId, bounds: Vec, default: Option>, synthetic: bool }, Const { did: DefId, ty: Box, default: Option> }, + Effect { did: DefId }, } impl GenericParamDefKind { @@ -1445,7 +1446,9 @@ impl GenericParamDef { pub(crate) fn is_synthetic_type_param(&self) -> bool { match self.kind { - GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false, + GenericParamDefKind::Lifetime { .. } + | GenericParamDefKind::Const { .. } + | GenericParamDefKind::Effect { .. } => false, GenericParamDefKind::Type { synthetic, .. } => synthetic, } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 5ad24bf268133..d8a3631a851b6 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -237,6 +237,15 @@ impl clean::GenericParamDef { } } + Ok(()) + } + clean::GenericParamDefKind::Effect { .. } => { + if f.alternate() { + write!(f, "effect {}", self.name)?; + } else { + write!(f, "effect {}: ", self.name)?; + } + Ok(()) } }) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 56283b2c0eff9..365a178bcded5 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -424,6 +424,7 @@ impl FromWithTcx for GenericParamDefKind { type_: (*ty).into_tcx(tcx), default: default.map(|x| *x), }, + Effect { did: _ } => GenericParamDefKind::Effect, } } } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 387d5787dfcb2..3d9aea31e1120 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -480,6 +480,7 @@ pub enum GenericParamDefKind { type_: Type, default: Option, }, + Effect, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index c6f55410e4437..8b69f1b322d16 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -316,6 +316,7 @@ impl<'a> Validator<'a> { rustdoc_json_types::GenericParamDefKind::Const { type_, default: _ } => { self.check_type(type_) } + rustdoc_json_types::GenericParamDefKind::Effect {} => {} } } From 6d5c6796f9ed972fbf1ed832c76809a77a0398ad Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 29 Sep 2022 08:37:12 +0000 Subject: [PATCH 09/13] Add canonicalization for effects --- compiler/rustc_infer/src/infer/at.rs | 15 ++++ .../src/infer/canonical/canonicalizer.rs | 86 ++++++++++++++++++- .../rustc_infer/src/infer/canonical/mod.rs | 19 ++++ .../src/infer/canonical/query_response.rs | 25 ++++-- .../src/infer/error_reporting/mod.rs | 2 + compiler/rustc_infer/src/infer/freshen.rs | 65 ++++++++++++++ compiler/rustc_infer/src/infer/mod.rs | 11 +++ compiler/rustc_middle/src/infer/canonical.rs | 10 +++ .../src/traits/project.rs | 61 ++++++++++++- .../src/traits/query/normalize.rs | 3 +- compiler/rustc_traits/src/chalk/mod.rs | 2 + 11 files changed, 289 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index d816a9ed3d7c1..ac6650e88557b 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -369,6 +369,21 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> { } } +impl<'tcx> ToTrace<'tcx> for ty::Effect<'tcx> { + fn to_trace( + _: TyCtxt<'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self, + ) -> TypeTrace<'tcx> { + TypeTrace { + cause: cause.clone(), + values: Effects(ExpectedFound::new(a_is_expected, a.into(), b.into())), + } + } +} + impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { fn to_trace( _: TyCtxt<'tcx>, diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index ec5221379d2c9..dc2c78714db6f 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -513,6 +513,57 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { let flags = FlagComputation::for_const(ct); if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { ct } } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + match e.val { + ty::EffectValue::Infer(ty::InferEffect::Var(vid)) => { + debug!("canonical: effect var found with vid {:?}", vid); + match self.infcx.probe_effect_var(vid) { + Ok(e) => { + debug!("(resolved to {:?})", e); + return self.fold_effect(e); + } + + // `InferEffect::Var(vid)` is unresolved, track its universe index in the + // canonicalized result + Err(mut ui) => { + if !self.canonicalize_mode.preserve_universes() { + // FIXME: perf problem described in #55921. + ui = ty::UniverseIndex::ROOT; + } + return self.canonicalize_effect_var( + CanonicalVarInfo { + kind: CanonicalVarKind::Effect(ui, ty::EffectKind::Host), + }, + e, + ); + } + } + } + ty::EffectValue::Infer(ty::InferEffect::Fresh(_)) => { + bug!("encountered a fresh const during canonicalization") + } + ty::EffectValue::Bound(debruijn, _) => { + if debruijn >= self.binder_index { + bug!("escaping bound type during canonicalization") + } else { + return e; + } + } + ty::EffectValue::Placeholder(placeholder) => { + return self.canonicalize_effect_var( + CanonicalVarInfo { + kind: CanonicalVarKind::PlaceholderEffect(placeholder, e.kind), + }, + e, + ); + } + _ => {} + } + + let flags = FlagComputation::for_effect(e); + if flags.intersects(self.needs_canonical_flags) { e.super_fold_with(self) } else { e } + } } impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { @@ -532,12 +583,14 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { TypeFlags::NEEDS_INFER | TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` TypeFlags::HAS_TY_PLACEHOLDER | - TypeFlags::HAS_CT_PLACEHOLDER + TypeFlags::HAS_CT_PLACEHOLDER | + TypeFlags::HAS_EFFECT_PLACEHOLDER } else { TypeFlags::NEEDS_INFER | TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER + | TypeFlags::HAS_EFFECT_PLACEHOLDER }; // Fast path: nothing that needs to be canonicalized. @@ -675,6 +728,9 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { CanonicalVarKind::Const(u, t) => { CanonicalVarKind::Const(reverse_universe_map[&u], t) } + CanonicalVarKind::Effect(u, effect_kind) => { + CanonicalVarKind::Effect(reverse_universe_map[&u], effect_kind) + } CanonicalVarKind::PlaceholderTy(placeholder) => { CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: reverse_universe_map[&placeholder.universe], @@ -696,6 +752,15 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { t, ) } + CanonicalVarKind::PlaceholderEffect(placeholder, kind) => { + CanonicalVarKind::PlaceholderEffect( + ty::Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }, + kind, + ) + } }, }) .collect() @@ -778,4 +843,23 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { ) } } + + /// Given a type variable `effect_var` of the given kind, first check + /// if `effect_var` is bound to anything; if so, canonicalize + /// *that*. Otherwise, create a new canonical variable for + /// `const_var`. + fn canonicalize_effect_var( + &mut self, + info: CanonicalVarInfo<'tcx>, + effect_var: ty::Effect<'tcx>, + ) -> ty::Effect<'tcx> { + let infcx = self.infcx; + let bound_to = infcx.shallow_resolve(effect_var); + if bound_to != effect_var { + self.fold_effect(bound_to) + } else { + let var = self.canonical_var(info, effect_var.into()); + self.tcx().mk_effect(ty::EffectValue::Bound(self.binder_index, var), effect_var.kind) + } + } } diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index e59715b706b29..c46e4c58e2464 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -24,6 +24,7 @@ use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind}; use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind}; use rustc_index::vec::IndexVec; +use rustc_middle::infer::unify_key::{EffectVariableOrigin, EffectVariableOriginKind}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArg; use rustc_middle::ty::{self, BoundVar, List}; @@ -152,6 +153,24 @@ impl<'tcx> InferCtxt<'tcx> { let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name }; self.tcx.mk_const(placeholder_mapped, ty).into() } + + CanonicalVarKind::Effect(ui, effect_kind) => self + .next_effect_var_in_universe( + effect_kind, + EffectVariableOrigin { + kind: EffectVariableOriginKind::MiscVariable, + span, + effect_kind, + }, + universe_map(ui), + ) + .into(), + + CanonicalVarKind::PlaceholderEffect(ty::PlaceholderEffect { universe, name }, kind) => { + let universe_mapped = universe_map(universe); + let placeholder_mapped = ty::PlaceholderEffect { universe: universe_mapped, name }; + self.tcx.mk_effect(ty::EffectValue::Placeholder(placeholder_mapped), kind).into() + } } } } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index ae998bf5e7e0d..a085d5c87a526 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -175,6 +175,7 @@ impl<'tcx> InferCtxt<'tcx> { /// out the [chapter in the rustc dev guide][c]. /// /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#processing-the-canonicalized-query-result + #[instrument(level = "debug", skip(self, cause, param_env), ret)] pub fn instantiate_query_response_and_region_obligations( &self, cause: &ObligationCause<'tcx>, @@ -310,6 +311,20 @@ impl<'tcx> InferCtxt<'tcx> { .relate(v1, v2)?; } + (GenericArgKind::Effect(v1), GenericArgKind::Effect(v2)) => { + TypeRelating::new( + self, + QueryTypeRelatingDelegate { + infcx: self, + param_env, + cause, + obligations: &mut obligations, + }, + ty::Variance::Invariant, + ) + .relate(v1, v2)?; + } + _ => { bug!("kind mismatch, cannot unify {:?} and {:?}", original_value, result_value); } @@ -355,6 +370,7 @@ impl<'tcx> InferCtxt<'tcx> { /// example) we are doing lazy normalization and the value /// assigned to a type variable is unified with an unnormalized /// projection. + #[instrument(level = "debug", skip(self, cause, param_env), ret)] fn query_response_substitution( &self, cause: &ObligationCause<'tcx>, @@ -365,11 +381,6 @@ impl<'tcx> InferCtxt<'tcx> { where R: Debug + TypeFoldable<'tcx>, { - debug!( - "query_response_substitution(original_values={:#?}, query_response={:#?})", - original_values, query_response, - ); - let mut value = self.query_response_substitution_guess( cause, param_env, @@ -635,6 +646,10 @@ impl<'tcx> InferCtxt<'tcx> { let ok = self.at(cause, param_env).eq(v1, v2)?; obligations.extend(ok.into_obligations()); } + (GenericArgKind::Effect(v1), GenericArgKind::Effect(v2)) => { + let ok = self.at(cause, param_env).eq(v1, v2)?; + obligations.extend(ok.into_obligations()); + } _ => { bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 696f3d78a913f..8a91a78390b1e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1583,6 +1583,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (false, Mismatch::Fixed("trait")) } ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")), + ValuePairs::Effects(_) => (false, Mismatch::Fixed("effect")), }; let Some(vals) = self.values_str(values) else { // Derived error. Cancel the emitter. @@ -2025,6 +2026,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { { match values { infer::Regions(exp_found) => self.expected_found_str(exp_found), + infer::Effects(exp_found) => self.expected_found_str(exp_found), infer::Terms(exp_found) => self.expected_found_str_term(exp_found), infer::TraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 8f53b1ccdf458..6fdd5791779ea 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -41,8 +41,10 @@ pub struct TypeFreshener<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, ty_freshen_count: u32, const_freshen_count: u32, + effect_freshen_count: u32, ty_freshen_map: FxHashMap>, const_freshen_map: FxHashMap, ty::Const<'tcx>>, + effect_freshen_map: FxHashMap, ty::Effect<'tcx>>, keep_static: bool, } @@ -52,8 +54,10 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { infcx, ty_freshen_count: 0, const_freshen_count: 0, + effect_freshen_count: 0, ty_freshen_map: Default::default(), const_freshen_map: Default::default(), + effect_freshen_map: Default::default(), keep_static, } } @@ -108,6 +112,32 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { } } } + + fn freshen_effect( + &mut self, + opt_e: Option>, + key: ty::InferEffect<'tcx>, + freshener: F, + kind: ty::EffectKind, + ) -> ty::Effect<'tcx> + where + F: FnOnce(u32) -> ty::InferEffect<'tcx>, + { + if let Some(e) = opt_e { + return e.fold_with(self); + } + + match self.effect_freshen_map.entry(key) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let index = self.effect_freshen_count; + self.effect_freshen_count += 1; + let e = self.infcx.tcx.mk_effect(freshener(index), kind); + entry.insert(e); + e + } + } + } } impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { @@ -251,4 +281,39 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { | ty::ConstKind::Error(_) => ct.super_fold_with(self), } } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + match e.val { + ty::EffectValue::Infer(ty::InferEffect::Var(v)) => { + let opt_e = self + .infcx + .inner + .borrow_mut() + .effect_unification_table() + .probe_value(v) + .val + .known(); + self.freshen_effect(opt_e, ty::InferEffect::Var(v), ty::InferEffect::Fresh, e.kind) + } + ty::EffectValue::Infer(ty::InferEffect::Fresh(i)) => { + if i >= self.effect_freshen_count { + bug!( + "Encountered a freshend effect with id {} \ + but our counter is only at {}", + i, + self.effect_freshen_count, + ); + } + e + } + + ty::EffectValue::Bound(..) | ty::EffectValue::Placeholder(_) => { + bug!("unexpected effect {:?}", e) + } + + ty::EffectValue::Rigid { .. } + | ty::EffectValue::Err(_) + | ty::EffectValue::Param { .. } => e.super_fold_with(self), + } + } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e82e95e79256d..1d84683d3f368 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -380,6 +380,7 @@ pub struct InferCtxt<'tcx> { pub enum ValuePairs<'tcx> { Regions(ExpectedFound>), Terms(ExpectedFound>), + Effects(ExpectedFound>), TraitRefs(ExpectedFound>), PolyTraitRefs(ExpectedFound>), Sigs(ExpectedFound>), @@ -1494,6 +1495,16 @@ impl<'tcx> InferCtxt<'tcx> { } } + pub fn probe_effect_var( + &self, + vid: ty::EffectVid<'tcx>, + ) -> Result, ty::UniverseIndex> { + match self.inner.borrow_mut().effect_unification_table().probe_value(vid).val { + EffectVariableValue::Known { value } => Ok(value), + EffectVariableValue::Unknown { universe } => Err(universe), + } + } + pub fn fully_resolve>(&self, value: T) -> FixupResult<'tcx, T> { /*! * Attempts to resolve all type/region/const variables in diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 6cd00f577bfd5..ca19165b9043a 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -117,6 +117,8 @@ impl<'tcx> CanonicalVarInfo<'tcx> { CanonicalVarKind::PlaceholderRegion(..) => false, CanonicalVarKind::Const(..) => true, CanonicalVarKind::PlaceholderConst(_, _) => false, + CanonicalVarKind::Effect(..) => true, + CanonicalVarKind::PlaceholderEffect(_, _) => false, } } } @@ -146,6 +148,12 @@ pub enum CanonicalVarKind<'tcx> { /// A "placeholder" that represents "any const". PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>), + + /// Some kind of effect inference variable. + Effect(ty::UniverseIndex, ty::EffectKind), + + /// A "placeholder" that represents "any effect". + PlaceholderEffect(ty::PlaceholderEffect, ty::EffectKind), } impl<'tcx> CanonicalVarKind<'tcx> { @@ -161,6 +169,8 @@ impl<'tcx> CanonicalVarKind<'tcx> { CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe, CanonicalVarKind::Const(ui, _) => ui, CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe, + CanonicalVarKind::Effect(ui, _) => ui, + CanonicalVarKind::PlaceholderEffect(placeholder, _) => placeholder.universe, } } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index f7614997585cf..174bd8932bae3 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -577,7 +577,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // or handle this some other way. let infcx = self.selcx.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = + let (data, mapped_regions, mapped_types, mapped_consts, mapped_effects) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); let data = data.fold_with(self); let normalized_ty = opt_normalize_projection_type( @@ -597,6 +597,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { mapped_regions, mapped_types, mapped_consts, + mapped_effects, &self.universes, normalized_ty, ) @@ -652,6 +653,7 @@ pub struct BoundVarReplacer<'me, 'tcx> { mapped_regions: BTreeMap, mapped_types: BTreeMap, mapped_consts: BTreeMap, ty::BoundVar>, + mapped_effects: BTreeMap, // The current depth relative to *this* folding, *not* the entire normalization. In other words, // the depth of binders we've passed here. current_index: ty::DebruijnIndex, @@ -679,7 +681,7 @@ pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: Typ f: impl FnOnce(T) -> R, ) -> R { if value.has_escaping_bound_vars() { - let (value, mapped_regions, mapped_types, mapped_consts) = + let (value, mapped_regions, mapped_types, mapped_consts, mapped_effects) = BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value); let result = f(value); PlaceholderReplacer::replace_placeholders( @@ -687,6 +689,7 @@ pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: Typ mapped_regions, mapped_types, mapped_consts, + mapped_effects, universe_indices, result, ) @@ -707,23 +710,32 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { BTreeMap, BTreeMap, BTreeMap, ty::BoundVar>, + BTreeMap, ) { let mapped_regions: BTreeMap = BTreeMap::new(); let mapped_types: BTreeMap = BTreeMap::new(); let mapped_consts: BTreeMap, ty::BoundVar> = BTreeMap::new(); + let mapped_effects: BTreeMap = BTreeMap::new(); let mut replacer = BoundVarReplacer { infcx, mapped_regions, mapped_types, mapped_consts, + mapped_effects, current_index: ty::INNERMOST, universe_indices, }; let value = value.fold_with(&mut replacer); - (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts) + ( + value, + replacer.mapped_regions, + replacer.mapped_types, + replacer.mapped_consts, + replacer.mapped_effects, + ) } fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex { @@ -810,6 +822,24 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> { } } + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + match e.val { + ty::EffectValue::Bound(debruijn, _) + if debruijn.as_usize() + 1 + > self.current_index.as_usize() + self.universe_indices.len() => + { + bug!("Bound vars outside of `self.universe_indices`"); + } + ty::EffectValue::Bound(debruijn, bound_const) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = ty::PlaceholderEffect { universe, name: bound_const }; + self.mapped_effects.insert(p, bound_const); + self.infcx.tcx.mk_effect(ty::EffectValue::Placeholder(p), e.kind) + } + _ => e.super_fold_with(self), + } + } + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } @@ -821,6 +851,7 @@ pub struct PlaceholderReplacer<'me, 'tcx> { mapped_regions: BTreeMap, mapped_types: BTreeMap, mapped_consts: BTreeMap, ty::BoundVar>, + mapped_effects: BTreeMap, universe_indices: &'me [Option], current_index: ty::DebruijnIndex, } @@ -831,6 +862,7 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { mapped_regions: BTreeMap, mapped_types: BTreeMap, mapped_consts: BTreeMap, ty::BoundVar>, + mapped_effects: BTreeMap, universe_indices: &'me [Option], value: T, ) -> T { @@ -839,6 +871,7 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { mapped_regions, mapped_types, mapped_consts, + mapped_effects, universe_indices, current_index: ty::INNERMOST, }; @@ -947,6 +980,28 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { ct.super_fold_with(self) } } + + fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { + if let ty::EffectValue::Placeholder(p) = e.val { + let replace_var = self.mapped_effects.get(&p); + match replace_var { + Some(replace_var) => { + let index = self + .universe_indices + .iter() + .position(|u| matches!(u, Some(pu) if *pu == p.universe)) + .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); + let db = ty::DebruijnIndex::from_usize( + self.universe_indices.len() - index + self.current_index.as_usize() - 1, + ); + self.tcx().mk_effect(ty::EffectValue::Bound(db, *replace_var), e.kind) + } + None => e, + } + } else { + e.super_fold_with(self) + } + } } /// The guts of `normalize`: normalize a specific projection like ` FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let tcx = self.infcx.tcx; let infcx = self.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = + let (data, mapped_regions, mapped_types, mapped_consts, mapped_effects) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); let data = data.try_fold_with(self)?; @@ -349,6 +349,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { mapped_regions, mapped_types, mapped_consts, + mapped_effects, &self.universes, result.normalized_ty, ); diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index f76386fa720df..01388f89c9bd7 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -77,6 +77,8 @@ pub(crate) fn evaluate_goal<'tcx>( ), CanonicalVarKind::Const(_ui, _ty) => unimplemented!(), CanonicalVarKind::PlaceholderConst(_pc, _ty) => unimplemented!(), + CanonicalVarKind::Effect(_ui, _effect_kind) => unimplemented!(), + CanonicalVarKind::PlaceholderEffect(_pc, _effect_kind) => unimplemented!(), }), ), value: obligation.value.lower_into(interner), From 490c46277d77139ff822b2389503b0a71ea6957b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 11 Oct 2022 11:05:19 +0000 Subject: [PATCH 10/13] Fiddle HirId through a bunch of methods --- compiler/rustc_hir_typeck/src/autoderef.rs | 2 +- compiler/rustc_hir_typeck/src/callee.rs | 1 + .../src/generator_interior/mod.rs | 3 +-- compiler/rustc_hir_typeck/src/method/mod.rs | 5 ++++- compiler/rustc_hir_typeck/src/op.rs | 21 ++++++++++++++++--- compiler/rustc_hir_typeck/src/place_op.rs | 18 +++++++++++++--- 6 files changed, 40 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index 41b52a4c4a9fc..3654977db4d12 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -20,7 +20,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, base_ty: Ty<'tcx>, ) -> Option>> { - self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref) + self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref, self.body_id) } /// Returns the adjustment steps. diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 2cb976f718c22..2127e8b33a7d4 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -246,6 +246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_def_id, adjusted_ty, opt_input_type.as_ref().map(slice::from_ref), + call_expr.hir_id, ) { let method = self.register_infer_ok_obligations(ok); let mut autoref = None; diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 827c019b2426d..11207eb7c56a1 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -306,8 +306,7 @@ pub fn resolve_interior<'a, 'tcx>( // Extract type components to build the witness type. let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty)); let bound_vars = fcx.tcx.mk_bound_variable_kinds(bound_vars.iter()); - let witness = - fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone())); + let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars)); drop(typeck_results); // Store the generator types and spans into the typeck results for this generator. diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index f7a1b926dd15b..a1a027ad5559c 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -12,6 +12,7 @@ pub use self::MethodError::*; use crate::errors::OpMethodGenericParams; use crate::FnCtxt; +use hir::HirId; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; @@ -273,6 +274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, + _hir_id: HirId, ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List>) { // Construct a trait-reference `self_ty : Trait` @@ -320,9 +322,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, + hir_id: HirId, ) -> Option>> { let (obligation, substs) = - self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types); + self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types, hir_id); self.construct_obligation_for_trait(m_name, trait_def_id, obligation, substs) } diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index e4837ee60bd37..a890fea8017af 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -3,6 +3,7 @@ use super::method::MethodCallee; use super::FnCtxt; use crate::Expectation; +use hir::HirId; use rustc_ast as ast; use rustc_errors::{self, struct_span_err, Applicability, Diagnostic}; use rustc_hir as hir; @@ -52,6 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_deref_ty, Some((rhs, rhs_ty)), Op::Binary(op, IsAssign::Yes), + expr.hir_id, expected, ) .is_ok() @@ -63,6 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, Some((rhs, rhs_ty)), Op::Binary(op, IsAssign::Yes), + expr.hir_id, expected, ) .is_err() @@ -250,6 +253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, Some((rhs_expr, rhs_ty_var)), Op::Binary(op, is_assign), + expr.hir_id, expected, ); @@ -383,6 +387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_deref_ty, Some((rhs_expr, rhs_ty)), Op::Binary(op, is_assign), + expr.hir_id, expected, ) .is_ok() @@ -410,6 +415,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, Some((rhs_expr, rhs_ty)), Op::Binary(op, is_assign), + expr.hir_id, expected, ) .is_ok() @@ -470,6 +476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, Some((rhs_expr, rhs_ty)), Op::Binary(op, is_assign), + expr.hir_id, expected, ) .unwrap_err(); @@ -622,7 +629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, ) -> Ty<'tcx> { assert!(op.is_by_value()); - match self.lookup_op_method(operand_ty, None, Op::Unary(op, ex.span), expected) { + match self.lookup_op_method(operand_ty, None, Op::Unary(op, ex.span), ex.hir_id, expected) { Ok(method) => { self.write_method_call(ex.hir_id, method); method.sig.output() @@ -711,6 +718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty: Ty<'tcx>, opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>, op: Op, + hir_id: HirId, expected: Expectation<'tcx>, ) -> Result, Vec>> { let span = match op { @@ -738,7 +746,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let method = trait_did.and_then(|trait_did| { - self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, Some(input_types)) + self.lookup_method_in_trait( + cause.clone(), + opname, + trait_did, + lhs_ty, + Some(input_types), + hir_id, + ) }); match (method, trait_did) { @@ -750,7 +765,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, None) => Err(vec![]), (None, Some(trait_did)) => { let (obligation, _) = - self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types)); + self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types), hir_id); Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation)) } } diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index f3927988095f9..5792f74392aa1 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -1,5 +1,6 @@ use crate::method::MethodCallee; use crate::{FnCtxt, PlaceOp}; +use hir::HirId; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir as hir; @@ -155,8 +156,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: TypeVariableOriginKind::AutoDeref, span: base_expr.span, }); - let method = - self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index); + let method = self.try_overloaded_place_op( + expr.span, + self_ty, + &[input_ty], + PlaceOp::Index, + expr.hir_id, + ); if let Some(result) = method { debug!("try_index_step: success, using overloaded indexing"); @@ -201,6 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_ty: Ty<'tcx>, arg_tys: &[Ty<'tcx>], op: PlaceOp, + hir_id: HirId, ) -> Option>> { debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op); @@ -216,6 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_did, base_ty, Some(arg_tys), + hir_id, ) }) } @@ -226,6 +234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_ty: Ty<'tcx>, arg_tys: &[Ty<'tcx>], op: PlaceOp, + hir_id: HirId, ) -> Option>> { debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op); @@ -241,6 +250,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_did, base_ty, Some(arg_tys), + hir_id, ) }) } @@ -294,6 +304,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source, &[], PlaceOp::Deref, + expr.hir_id, ) { let method = self.register_infer_ok_obligations(ok); @@ -373,7 +384,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(ref ty) => slice::from_ref(ty), }; - let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op); + let method = + self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op, expr.hir_id); let method = match method { Some(ok) => self.register_infer_ok_obligations(ok), // Couldn't find the mutable variant of the place op, keep the From 200b34dffe93f77ddbc064c821f745a55e6c2837 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 23 Nov 2022 08:48:39 +0000 Subject: [PATCH 11/13] Need to wait for derive_const to land on master before we can land effects --- library/core/src/alloc/layout.rs | 3 +-- library/core/src/ptr/alignment.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index ac3d84718d54e..60e86aed9200c 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -376,9 +376,8 @@ impl Layout { /// # assert_eq!(repr_c(&[u64, u32, u16, u32]), Ok((s, vec![0, 8, 12, 16]))); /// ``` #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[inline] - pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { + pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { let new_align = cmp::max(self.align, next.align); let pad = self.padding_needed_for(next.align()); diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 2123147c7e44c..c81971220c568 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -170,7 +170,7 @@ impl From for usize { #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl const cmp::Ord for Alignment { +impl cmp::Ord for Alignment { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.as_nonzero().get().cmp(&other.as_nonzero().get()) @@ -179,7 +179,7 @@ impl const cmp::Ord for Alignment { #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl const cmp::PartialOrd for Alignment { +impl cmp::PartialOrd for Alignment { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) From 5da0201adb7647f581a8fb3181966dcf0dae157e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 20 Oct 2022 09:39:09 +0000 Subject: [PATCH 12/13] Generate effects for const fns and const traits under the `effects` feature gate --- .../rustc_borrowck/src/diagnostics/mod.rs | 21 +- .../src/debuginfo/type_names.rs | 18 + .../src/const_eval/machine.rs | 28 +- .../src/transform/check_consts/check.rs | 2 +- .../src/transform/check_consts/qualifs.rs | 12 +- compiler/rustc_errors/src/lib.rs | 3 + compiler/rustc_feature/src/active.rs | 2 + compiler/rustc_hir/src/def.rs | 37 ++ .../rustc_hir_analysis/src/astconv/mod.rs | 63 ++- .../src/collect/generics_of.rs | 43 +- .../src/collect/predicates_of.rs | 2 +- compiler/rustc_hir_typeck/src/autoderef.rs | 7 +- compiler/rustc_hir_typeck/src/callee.rs | 157 +++++- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- .../src/fn_ctxt/suggestions.rs | 18 +- compiler/rustc_hir_typeck/src/lib.rs | 3 + .../rustc_hir_typeck/src/method/confirm.rs | 9 +- compiler/rustc_hir_typeck/src/method/mod.rs | 15 +- compiler/rustc_hir_typeck/src/place_op.rs | 2 +- compiler/rustc_hir_typeck/src/upvar.rs | 30 +- compiler/rustc_hir_typeck/src/writeback.rs | 7 +- .../src/infer/canonical/canonicalizer.rs | 2 +- compiler/rustc_infer/src/infer/combine.rs | 40 +- .../src/infer/error_reporting/mod.rs | 3 +- compiler/rustc_infer/src/infer/mod.rs | 36 ++ compiler/rustc_infer/src/infer/resolve.rs | 18 +- compiler/rustc_infer/src/infer/sub.rs | 4 +- compiler/rustc_infer/src/traits/util.rs | 30 +- .../rustc_middle/src/mir/interpret/queries.rs | 9 +- compiler/rustc_middle/src/traits/select.rs | 2 +- compiler/rustc_middle/src/ty/adjustment.rs | 8 +- compiler/rustc_middle/src/ty/context.rs | 87 +++- compiler/rustc_middle/src/ty/effect.rs | 2 +- compiler/rustc_middle/src/ty/generics.rs | 16 + compiler/rustc_middle/src/ty/instance.rs | 12 +- compiler/rustc_middle/src/ty/opaque_types.rs | 17 +- compiler/rustc_middle/src/ty/sty.rs | 23 + compiler/rustc_middle/src/ty/subst.rs | 10 + .../rustc_mir_build/src/build/matches/test.rs | 7 +- .../rustc_mir_dataflow/src/elaborate_drops.rs | 12 +- compiler/rustc_mir_transform/src/shim.rs | 13 +- compiler/rustc_span/src/symbol.rs | 1 + .../rustc_trait_selection/src/autoderef.rs | 20 +- .../src/traits/error_reporting/mod.rs | 15 +- .../rustc_trait_selection/src/traits/mod.rs | 2 +- .../src/traits/project.rs | 4 + .../src/traits/query/evaluate_obligation.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 46 +- .../src/traits/select/confirmation.rs | 99 +++- .../src/traits/select/mod.rs | 90 +++- .../rustc_trait_selection/src/traits/util.rs | 31 +- library/core/src/array/mod.rs | 4 +- library/core/src/cmp.rs | 10 +- library/core/src/const_closure.rs | 2 +- library/core/src/ops/deref.rs | 2 +- library/core/src/ops/function.rs | 4 +- library/core/src/ops/try_trait.rs | 3 +- library/core/src/pin.rs | 18 +- .../const_trait_fn-issue-88433.rs | 1 + .../ui/const-generics/issues/issue-98629.rs | 1 + .../const-generics/issues/issue-98629.stderr | 2 +- src/test/ui/consts/const-call.rs | 4 +- src/test/ui/consts/const-call.stderr | 7 +- src/test/ui/consts/const-tuple-struct.rs | 2 + src/test/ui/consts/const_let_assign3.rs | 2 + src/test/ui/consts/const_let_assign3.stderr | 6 +- src/test/ui/consts/const_method_call.rs | 14 + src/test/ui/consts/issue-25826.stderr | 8 +- .../min_const_fn/min_const_fn_unsafe_bad.rs | 2 + .../min_const_fn_unsafe_bad.stderr | 6 +- .../ui/consts/miri_unleashed/non_const_fn.rs | 2 + .../consts/miri_unleashed/non_const_fn.stderr | 4 +- src/test/ui/consts/operator_traits.rs | 493 ++++++++++++++++++ src/test/ui/keyword_generics/const_trait.rs | 94 ++++ .../ui/keyword_generics/const_trait.stderr | 120 +++++ ...cts_are_not_user_visible_generic_params.rs | 18 + ...are_not_user_visible_generic_params.stderr | 17 + .../keyword_generics/feature-gate-effects.rs | 7 + .../feature-gate-effects.stderr | 11 + .../ui/keyword_generics/other_const_fn.rs | 13 + .../assoc-type-const-bound-usage.rs | 3 +- .../rfc-2632-const-trait-impl/attr-misuse.rs | 1 + .../attr-misuse.stderr | 4 +- .../auxiliary/cross-crate.rs | 2 +- .../auxiliary/staged-api.rs | 2 +- .../call-const-trait-method-fail.rs | 1 + .../call-const-trait-method-fail.stderr | 12 +- .../call-generic-method-nonconst-bound.rs | 2 + .../call-generic-method-nonconst.rs | 2 +- .../call-generic-method-nonconst.stderr | 6 +- .../const-default-method-bodies.rs | 1 + .../const-default-method-bodies.stderr | 12 +- .../const-impl-norecover.rs | 1 + .../const-impl-norecover.stderr | 2 +- .../const-impl-recovery.rs | 1 + .../const-impl-recovery.stderr | 4 +- .../const-impl-requires-const-trait.rs | 2 +- .../const-impl-requires-const-trait.stderr | 2 +- ...ross-crate-default-method-body-is-const.rs | 1 + .../cross-crate.gatednc.stderr | 10 +- .../rfc-2632-const-trait-impl/cross-crate.rs | 2 +- ...ault-method-body-is-const-body-checking.rs | 4 +- ...-method-body-is-const-body-checking.stderr | 20 +- ...ault-method-body-is-const-same-trait-ck.rs | 1 + ...-method-body-is-const-same-trait-ck.stderr | 12 +- ...lt-method-body-is-const-with-staged-api.rs | 1 + .../impl-tilde-const-trait.rs | 1 + .../impl-tilde-const-trait.stderr | 2 +- .../impl-with-default-fn-fail.rs | 1 + .../impl-with-default-fn-fail.stderr | 2 +- .../impl-with-default-fn-pass.rs | 1 + .../inherent-impl.rs | 3 + .../inherent-impl.stderr | 19 +- .../rfc-2632-const-trait-impl/intrinsics.rs | 10 + .../rfc-2632-const-trait-impl/issue-100222.rs | 19 +- .../rfc-2632-const-trait-impl/issue-88155.rs | 5 +- .../issue-88155.stderr | 20 +- .../specializing-constness-2.rs | 4 +- .../specializing-constness-2.stderr | 21 +- .../rfc-2632-const-trait-impl/staged-api.rs | 2 +- .../super-traits-fail-2.rs | 4 +- .../super-traits-fail-2.yn.stderr | 17 +- .../super-traits-fail-2.yy.stderr | 17 +- .../super-traits-fail.rs | 1 + .../super-traits-fail.stderr | 17 +- .../rfc-2632-const-trait-impl/super-traits.rs | 1 + .../ui/rfc-2632-const-trait-impl/syntax.rs | 1 + .../tilde-const-invalid-places.rs | 1 + .../tilde-const-invalid-places.stderr | 2 +- .../tilde-const-syntax.rs | 1 + .../rfc-2632-const-trait-impl/tilde-twice.rs | 1 + .../tilde-twice.stderr | 2 +- .../trait-where-clause-const.rs | 1 + .../trait-where-clause-const.stderr | 36 +- .../trait-where-clause-run.rs | 1 + .../trait-where-clause-self-referential.rs | 1 + .../trait-where-clause.rs | 1 + .../trait-where-clause.stderr | 8 +- .../without-tilde.rs | 1 + .../without-tilde.stderr | 2 +- .../static/static-vec-repeat-not-constant.rs | 2 +- 141 files changed, 1978 insertions(+), 380 deletions(-) create mode 100644 src/test/ui/consts/const_method_call.rs create mode 100644 src/test/ui/consts/operator_traits.rs create mode 100644 src/test/ui/keyword_generics/const_trait.rs create mode 100644 src/test/ui/keyword_generics/const_trait.stderr create mode 100644 src/test/ui/keyword_generics/effects_are_not_user_visible_generic_params.rs create mode 100644 src/test/ui/keyword_generics/effects_are_not_user_visible_generic_params.stderr create mode 100644 src/test/ui/keyword_generics/feature-gate-effects.rs create mode 100644 src/test/ui/keyword_generics/feature-gate-effects.stderr create mode 100644 src/test/ui/keyword_generics/other_const_fn.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/intrinsics.rs diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 63b16aa95a6a5..541d6d9f21821 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -20,7 +20,7 @@ use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ - type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause, + pred_known_to_hold_modulo_regions, Obligation, ObligationCause, }; use super::borrow_set::BorrowData; @@ -1075,12 +1075,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) { Some(def_id) => { let infcx = self.infcx.tcx.infer_ctxt().build(); - type_known_to_meet_bound_modulo_regions( + pred_known_to_hold_modulo_regions( &infcx, self.param_env, - tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)), - def_id, - DUMMY_SP, + ty::Binder::dummy( + tcx.mk_trait_ref( + def_id, + [tcx.mk_imm_ref( + tcx.lifetimes.re_erased, + tcx.erase_regions(ty), + ) + .into()] + .into_iter() + .chain(tcx.host_effect()), + ), + ) + .without_const(), + span, ) } _ => false, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 1599ccbb2594c..fbcb2d70f35dc 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -623,6 +623,9 @@ fn push_generic_params_internal<'tcx>( GenericArgKind::Const(ct) => { push_const_param(tcx, ct, output); } + GenericArgKind::Effect(e) => { + push_effect_param(tcx, e, output); + } other => bug!("Unexpected non-erasable generic: {:?}", other), } @@ -634,6 +637,21 @@ fn push_generic_params_internal<'tcx>( true } +fn push_effect_param<'tcx>(_tcx: TyCtxt<'tcx>, e: ty::Effect<'tcx>, output: &mut String) { + match e.kind { + ty::EffectKind::Host => match e.val { + // nothing to add, the host effect is our default symbol + ty::EffectValue::Rigid { on: true } => {} + ty::EffectValue::Rigid { on: false } => write!(output, "const").unwrap(), + ty::EffectValue::Param { index } => write!(output, "~const<{index}>").unwrap(), + ty::EffectValue::Infer(_) + | ty::EffectValue::Bound(_, _) + | ty::EffectValue::Placeholder(_) + | ty::EffectValue::Err(_) => unreachable!(), + }, + }; +} + fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) { match ct.kind() { ty::ConstKind::Param(param) => { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index e006a62feeabd..fe116c03cf37f 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -3,7 +3,7 @@ use rustc_hir::{LangItem, CRATE_HIR_ID}; use rustc_middle::mir; use rustc_middle::mir::interpret::PointerArithmetic; use rustc_middle::ty::layout::FnAbiOf; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::lint::builtin::INVALID_ALIGNMENT; use std::borrow::Borrow; use std::hash::Hash; @@ -202,14 +202,16 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { } else if Some(def_id) == self.tcx.lang_items().panic_fmt() { // For panic_fmt, call const_panic_fmt instead. let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); - let new_instance = ty::Instance::resolve( - *self.tcx, - ty::ParamEnv::reveal_all(), - const_def_id, - instance.substs, - ) - .unwrap() - .unwrap(); + let substs = if self.tcx.effects() { + self.tcx + .mk_substs(instance.substs.iter().chain([self.tcx.effects.always_const.into()])) + } else { + instance.substs + }; + let new_instance = + ty::Instance::resolve(*self.tcx, ty::ParamEnv::reveal_all(), const_def_id, substs) + .unwrap() + .unwrap(); return Ok(Some(new_instance)); } else if Some(def_id) == self.tcx.lang_items().align_offset_fn() { @@ -425,8 +427,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, if new_instance != instance { // We call another const fn instead. - // However, we return the *original* instance to make backtraces work out - // (and we hope this does not confuse the FnAbi checks too much). return Ok(Self::find_mir_or_eval_fn( ecx, new_instance, @@ -436,7 +436,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ret, _unwind, )? - .map(|(body, _instance)| (body, instance))); + .map(|(body, new_instance)| { + // However, we return the *original* instance to make backtraces work out + // (and we hope this does not confuse the FnAbi checks too much). + (body, Instance::new(instance.def_id(), new_instance.substs)) + })); } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 354c5e7f2a167..c40713972bbaa 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -808,7 +808,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { return; } } - _ if !tcx.is_const_fn_raw(callee) => { + _ if !self.tcx.effects() && !tcx.is_const_fn_raw(callee) => { // At this point, it is only legal when the caller is in a trait // marked with #[const_trait], and the callee is in the same trait. let mut nonconst_call_permission = false; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 8ca3fdf400eb3..c810122b18a7d 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -157,8 +157,16 @@ impl Qualif for NeedsNonConstDrop { cx.tcx, ObligationCause::dummy_with_span(cx.body.span), cx.param_env, - ty::Binder::dummy(cx.tcx.at(cx.body.span).mk_trait_ref(LangItem::Destruct, [ty])) - .with_constness(ty::BoundConstness::ConstIfConst), + ty::Binder::dummy(cx.tcx.at(cx.body.span).mk_trait_ref_with_effect( + LangItem::Destruct, + [ty], + cx.def_id().to_def_id(), + )) + .with_constness(if cx.tcx.effects() { + ty::BoundConstness::NotConst + } else { + ty::BoundConstness::ConstIfConst + }), ); let infcx = cx.tcx.infer_ctxt().build(); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b4d23e96f8f45..0dddfd0523639 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1272,6 +1272,7 @@ impl HandlerInner { } // FIXME(eddyb) this should ideally take `diagnostic` by value. + #[track_caller] fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option { // The `LintExpectationId` can be stable or unstable depending on when it was created. // Diagnostics created before the definition of `HirId`s are unstable and can not yet @@ -1540,6 +1541,7 @@ impl HandlerInner { panic::panic_any(ExplicitBug); } + #[track_caller] fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into) { self.emit_diagnostic(diag.set_span(sp)); } @@ -1653,6 +1655,7 @@ impl HandlerInner { self.warn_count += 1; } + #[track_caller] fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { match ( diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index beade4d44da84..c2b65eec3a40d 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -384,6 +384,8 @@ declare_features! ( (active, doc_masked, "1.21.0", Some(44027), None), /// Allows `dyn* Trait` objects. (incomplete, dyn_star, "1.65.0", Some(102425), None), + // Uses generic effect parameters for ~const bounds + (active, effects, "1.62.0", Some(102090), None), /// Allows `X..Y` patterns. (active, exclusive_range_pattern, "1.11.0", Some(37854), None), /// Allows exhaustive pattern matching on types that contain uninhabited types. diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 921039797869f..c90a897cfcb03 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -264,6 +264,43 @@ impl DefKind { | DefKind::ExternCrate => false, } } + + pub fn require_const(self) -> bool { + match self { + DefKind::Const + | DefKind::Static(_) + | DefKind::AssocConst + | DefKind::AnonConst + | DefKind::InlineConst => true, + DefKind::Fn + | DefKind::AssocFn + | DefKind::Ctor(..) + | DefKind::Closure + | DefKind::Generator + | DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::Macro(..) + | DefKind::Use + | DefKind::ForeignMod + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder + | DefKind::Impl + | DefKind::Field + | DefKind::TyParam + | DefKind::ConstParam + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::ExternCrate => false, + } + } } /// The resolution of a path or export. diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 99df472ad5d13..657c3a028bf33 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -383,6 +383,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span: Span, inferred_params: Vec, infer_args: bool, + constness: ty::BoundConstness, } impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> { @@ -530,12 +531,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if infer_args { self.astconv.effect_infer(kind, Some(param), self.span).into() } else { - // We've already errored above about the mismatch. - tcx.effect_error_with_message( - self.span, - "non-inference missing effect args", - kind, - ) + // ```rust + // impl Trait for Foo + // ``` + // does not introduce any effects, even if the trait is `#[const_trait]`. + // We should pick `Rigid { on: false }` for this case, to help inference + // and trait resolution. + // + // On the other hand + // ```rust + // impl const Trait for Foo + // ``` + // introduces an effect, but the caller may choose whether it should be on + // or off. + match (kind, self.constness) { + (ty::EffectKind::Host, ty::BoundConstness::ConstIfConst) => tcx + .effect_from_context(self.astconv.item_def_id(), kind, || { + ty::EffectValue::Rigid { on: true } + }), + (ty::EffectKind::Host, ty::BoundConstness::NotConst) => { + tcx.mk_effect(ty::EffectValue::Rigid { on: true }, kind) + } + } .into() } } @@ -550,6 +567,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_args, inferred_params: vec![], infer_args, + constness, }; let substs = Self::create_substs_for_generic_args( tcx, @@ -561,10 +579,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &mut substs_ctx, ); - if let ty::BoundConstness::ConstIfConst = constness - && generics.has_self && !tcx.has_attr(def_id, sym::const_trait) - { - tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } ); + if let ty::BoundConstness::ConstIfConst = constness { + if tcx.effects() { + // Only check the trait itself for constness, not its parent + if !generics.params.iter().rev().any(|arg| match arg.kind { + ty::GenericParamDefKind::Effect { kind } => kind == ty::EffectKind::Host, + _ => false, + }) { + tcx.sess + .span_err(span, "~const can only be applied to `#[const_trait]` traits"); + } + } else if generics.has_self && !tcx.has_attr(def_id, sym::const_trait) { + tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span }); + } } (substs, arg_count) @@ -1109,6 +1136,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ConvertedBindingKind::Equality(ty) => Some(ty.to_string()), _ => None, }, + constness, )? }; @@ -1727,6 +1755,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_name, span, || None, + ty::BoundConstness::ConstIfConst, ) } @@ -1740,6 +1769,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_name: Ident, span: Span, is_equality: impl Fn() -> Option, + constness: ty::BoundConstness, ) -> Result, ErrorGuaranteed> where I: Iterator>, @@ -1750,7 +1780,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .filter(|r| self.trait_defines_associated_const_named(r.def_id(), assoc_name)); let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) { - (Some(bound), _) => (bound, matching_candidates.next()), + (Some(bound), _) => { + let next = matching_candidates.next(); + // Automatically prefer `T: Trait` over `T: ~const Trait` for back compat + if let Some(bound) = + next.and_then(|bound2| bound.pick_concrete_effect(bound2, constness)) + { + (bound, matching_candidates.next()) + } else { + (bound, next) + } + } (None, Some(bound)) => (bound, const_candidates.next()), (None, None) => { let reported = self.complain_about_assoc_type_not_found( @@ -2013,6 +2053,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_ident, span, || None, + ty::BoundConstness::ConstIfConst, )? } ( diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 96221c3e3d86e..f3bbe6f201b13 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -7,8 +7,11 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; -use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; +use rustc_span::{ + sym, + symbol::{kw, Symbol}, +}; pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { use rustc_hir::*; @@ -164,9 +167,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { let no_generics = hir::Generics::empty(); let ast_generics = node.generics().unwrap_or(&no_generics); + let mut has_constness_effect = false; let (opt_self, allow_defaults) = match node { Node::Item(item) => { - match item.kind { + match &item.kind { ItemKind::Trait(..) | ItemKind::TraitAlias(..) => { // Add in the self type parameter. // @@ -183,6 +187,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { }, }); + has_constness_effect = tcx.has_attr(def_id, rustc_span::sym::const_trait); + (opt_self, Defaults::Allowed) } ItemKind::TyAlias(..) @@ -190,6 +196,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { | ItemKind::Struct(..) | ItemKind::OpaqueTy(..) | ItemKind::Union(..) => (None, Defaults::Allowed), + + ItemKind::Impl(Impl { constness, .. }) + | ItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, _, _) => { + if !tcx.has_attr(def_id, sym::rustc_do_not_const_check) { + has_constness_effect = matches!(constness, Constness::Const); + } + (None, Defaults::FutureCompatDisallowed) + } _ => (None, Defaults::FutureCompatDisallowed), } } @@ -202,8 +216,19 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { (None, Defaults::Deny) } + Node::ImplItem(item) => { + match item.kind { + ImplItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..) => { + has_constness_effect = matches!(constness, Constness::Const); + } + _ => {} + } + (None, Defaults::FutureCompatDisallowed) + } + _ => (None, Defaults::FutureCompatDisallowed), }; + let has_constness_effect = has_constness_effect && tcx.effects(); let has_self = opt_self.is_some(); let mut parent_has_self = false; @@ -216,7 +241,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { generics.parent_count + generics.params.len() }); - let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize); + let mut params: Vec<_> = Vec::with_capacity( + ast_generics.params.len() + has_self as usize + has_constness_effect as usize, + ); if let Some(opt_self) = opt_self { params.push(opt_self); @@ -332,6 +359,16 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { } } + if has_constness_effect { + params.push(ty::GenericParamDef { + index: next_index(), + name: Symbol::intern("host"), + def_id, + pure_wrt_drop: false, + kind: ty::GenericParamDefKind::Effect { kind: ty::EffectKind::Host }, + }) + } + let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); ty::Generics { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 18fc43ce15cbd..10063534ba96b 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -42,7 +42,7 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic // an obligation and instead be skipped. Otherwise we'd use // `tcx.def_span(def_id);` - let constness = if tcx.has_attr(def_id, sym::const_trait) { + let constness = if !tcx.effects() && tcx.has_attr(def_id, sym::const_trait) { ty::BoundConstness::ConstIfConst } else { ty::BoundConstness::NotConst diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index 3654977db4d12..8f2b7daf9cae7 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -44,7 +44,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |InferOk { value: method, obligations: o }| { obligations.extend(o); if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { - Some(OverloadedDeref { region, mutbl, span: autoderef.span() }) + Some(OverloadedDeref { + region, + mutbl, + span: autoderef.span(), + context: self.body_id.owner.to_def_id(), + }) } else { None } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 2127e8b33a7d4..9c307ba7a49c5 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -3,6 +3,7 @@ use super::method::MethodCallee; use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use crate::type_error_struct; +use hir::def::DefKind; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey}; use rustc_hir as hir; @@ -19,8 +20,9 @@ use rustc_infer::{ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::SubstsRef; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeVisitor}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -366,6 +368,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { + self.enforce_context_effects(call_expr.hir_id, call_expr.span, callee_ty); + let (fn_sig, def_id) = match *callee_ty.kind() { ty::FnDef(def_id, subst) => { let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, subst); @@ -717,6 +721,157 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit() } + /// Enforces that functions being called actually have the effects that the current context + /// requires for them being callable. + #[instrument(skip(self))] + pub(super) fn enforce_context_effects(&self, hir_id: hir::HirId, span: Span, value: Ty<'tcx>) { + if !self.tcx.effects() || self.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { + return; + } + if value.references_error() { + return; + } + + // Compute the constness required by the context. + let context = self.tcx.hir().enclosing_body_owner(hir_id); + if self.tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) { + trace!("do not const check this context"); + return; + } + let kind = self.tcx.def_kind(context.to_def_id()); + let require_const = kind.require_const(); + debug_assert_ne!(kind, DefKind::ConstParam); + + let ty::FnDef(did, substs) = *value.kind() else { + if require_const { + let context = kind.descr(context.to_def_id()); + self.tcx.sess.span_err(span, &format!("cannot call non-const fn `{value}` in {context}s")); + } + trace!("not a function item"); + return; + }; + trace!(?substs); + + // Tuple struct/variant constructors are not really function calls, they are always fine. + if let DefKind::Ctor(_, def::CtorKind::Fn) = self.tcx.def_kind(did) { + trace!("variant constructors are fine"); + return; + } + // FIXME: should const intrinsics also have a constness effect? + if self.tcx.is_intrinsic(did) { + trace!("skip const intrinsic"); + if self.tcx.is_const_fn(did) { + return; + } + } + + // These special functions do not have effects but are `const fn` because the const evaluator + // has logic to just not call them and run special logic instead. + if self.tcx.has_attr(did, sym::rustc_do_not_const_check) { + trace!("skip call to rustc_do_not_const_check function"); + return; + } + + // Walk all the effects in the type, error on mismatches and bind inferred effects. + struct EffectVisitor<'a, 'tcx> { + span: Span, + ctx: &'a FnCtxt<'a, 'tcx>, + found_constness: bool, + context_effect: ty::Effect<'tcx>, + context: LocalDefId, + def_id: DefId, + substs: SubstsRef<'tcx>, + } + + impl<'a, 'tcx> TypeVisitor<'tcx> for EffectVisitor<'a, 'tcx> { + type BreakTy = (); + fn visit_effect( + &mut self, + e: ty::Effect<'tcx>, + ) -> std::ops::ControlFlow { + let cause = ObligationCause::dummy_with_span(self.span); + + match self.ctx.at(&cause, self.ctx.param_env).eq(self.context_effect, e) { + Ok(ok) => { + self.ctx.register_infer_ok_obligations(ok); + match e.kind { + ty::EffectKind::Host => self.found_constness = true, + } + std::ops::ControlFlow::CONTINUE + } + Err(err) => { + let TypeError::EffectMismatch(ExpectedFound { expected, found }) = err else { + span_bug!(self.span, "enforce_context_effects can only cause effect mismatches") + }; + let kind = expected.kind; + debug_assert_eq!(kind, found.kind); + match (expected.val, found.val) { + ( + ty::EffectValue::Rigid { on: false } + | ty::EffectValue::Param { .. }, + ty::EffectValue::Rigid { on: true }, + ) => { + let def_path = + self.ctx.tcx.def_path_str_with_substs(self.def_id, self.substs); + let reason = match kind { + ty::EffectKind::Host => "it is not `const`", + }; + self.ctx + .tcx + .sess + .struct_span_err( + self.span, + &format!("cannot call `{def_path}` because {reason}"), + ) + .span_label( + self.ctx + .tcx + .def_ident_span(self.context) + .unwrap_or_else(|| self.ctx.tcx.def_span(self.context)), + "required because of this", + ) + .emit(); + } + _ => bug!("everything else does not cause errors"), + } + + match e.kind { + ty::EffectKind::Host => std::ops::ControlFlow::Break(()), + } + } + } + } + } + + let mut visitor = EffectVisitor { + span, + ctx: self, + found_constness: false, + context_effect: self.tcx.effect_from_context( + context.to_def_id(), + ty::EffectKind::Host, + || ty::EffectValue::Rigid { on: !require_const }, + ), + def_id: did, + context, + substs, + }; + + if let std::ops::ControlFlow::Continue(()) = value.visit_with(&mut visitor) { + if !matches!(visitor.context_effect.val, ty::EffectValue::Rigid { on: true }) + && !visitor.found_constness + { + let def_path = self.tcx.def_path_str_with_substs(did, substs); + let context = kind.descr(context.to_def_id()); + self.tcx.sess.span_err( + span, + &format!("cannot call non-const fn `{def_path}` in {context}s"), + ); + } + // FIXME: add stability checks + } + } + fn confirm_deferred_closure_call( &self, call_expr: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 9e91a3f90764c..1bda04b83af0b 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1042,7 +1042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.infcx .type_implements_trait( self.tcx.lang_items().deref_mut_trait()?, - [expr_ty], + [expr_ty.into()].into_iter().chain(self.tcx.host_effect()), self.param_env, ) .may_apply() diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 236bdc60e677d..bd07e8abde952 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1060,11 +1060,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut suggest_copied_or_cloned = || { let expr_inner_ty = substs.type_at(0); let expected_inner_ty = expected_substs.type_at(0); - if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind() - && self.can_eq(self.param_env, *ty, expected_inner_ty).is_ok() + if let ty::Ref(_, ty, hir::Mutability::Not) = *expr_inner_ty.kind() + && self.can_eq(self.param_env, ty, expected_inner_ty).is_ok() { let def_path = self.tcx.def_path_str(adt_def.did()); - if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) { + if self.type_is_copy_modulo_regions(self.param_env, ty, expr.span) { diag.span_suggestion_verbose( expr.span.shrink_to_hi(), format!( @@ -1075,12 +1075,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); return true; } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() - && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( + && rustc_trait_selection::traits::pred_known_to_hold_modulo_regions( self, self.param_env, - *ty, - clone_did, - expr.span + ty::Binder::dummy(self.tcx.mk_trait_ref(clone_did, [ty.into()].into_iter().chain(self.tcx.host_effect()))).without_const(), + expr.span, ) { diag.span_suggestion_verbose( @@ -1142,9 +1141,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, self.misc(expr.span), self.param_env, - ty::Binder::dummy(self.tcx.mk_trait_ref( + ty::Binder::dummy(self.tcx.mk_trait_ref_with_effect( into_def_id, - [expr_ty, expected_ty] + [expr_ty, expected_ty], + self.body_id.owner.to_def_id() )), )) { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 26a465ffbf064..d718851603b80 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -277,6 +277,7 @@ fn typeck_with_fallback<'tcx>( }; fcx.type_inference_fallback(); + fcx.effects_inference_fallback(); // Even though coercion casts provide type hints, we check casts after fallback for // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. @@ -301,6 +302,8 @@ fn typeck_with_fallback<'tcx>( fcx.require_type_is_sized(ty, span, code); } + // Run effect fallback again as new effect variables may have been introduced + fcx.effects_inference_fallback(); fcx.select_all_obligations_or_error(); if let None = fcx.infcx.tainted_by_errors() { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 218c54688aa3e..a60058b58fe8f 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -132,12 +132,19 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ); } + self.enforce_context_effects( + self.call_expr.hir_id, + self.span, + self.tcx.mk_fn_def(pick.item.def_id, all_substs), + ); + // Create the final `MethodCallee`. let callee = MethodCallee { def_id: pick.item.def_id, substs: all_substs, sig: method_sig.skip_binder(), }; + ConfirmResult { callee, illegal_sized_bound } } @@ -154,7 +161,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty); let Some((ty, n)) = autoderef.nth(pick.autoderefs) else { return self.tcx.ty_error_with_message( - rustc_span::DUMMY_SP, + self.span, &format!("failed autoderef {}", pick.autoderefs), ); }; diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index a1a027ad5559c..5242e02d24ca6 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -274,15 +274,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, - _hir_id: HirId, + hir_id: HirId, ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List>) { // Construct a trait-reference `self_ty : Trait` let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { match param.kind { - GenericParamDefKind::Lifetime - | GenericParamDefKind::Const { .. } - | GenericParamDefKind::Effect { .. } => {} + GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {} GenericParamDefKind::Type { .. } => { if param.index == 0 { return self_ty.into(); @@ -290,6 +288,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return input_types[param.index as usize - 1].into(); } } + GenericParamDefKind::Effect { kind } => { + let context = self.tcx.hir().enclosing_body_owner(hir_id); + return self + .tcx + .effect_from_context(context.to_def_id(), kind, || ty::EffectValue::Rigid { + on: true, + }) + .into(); + } } self.var_for_def(cause.span, param) }); diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 5792f74392aa1..4f2b0f5e16598 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -309,7 +309,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let method = self.register_infer_ok_obligations(ok); if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { - *deref = OverloadedDeref { region, mutbl, span: deref.span }; + *deref = OverloadedDeref { region, mutbl, span: deref.span, context: self.body_id.owner.to_def_id() }; } // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514). // This helps avoid accidental drops. diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index a9347991e7f98..720e72ea931eb 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -929,13 +929,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { var_hir_id: hir::HirId, closure_clause: hir::CaptureBy, ) -> Option>> { - let auto_traits_def_id = vec![ - self.tcx.lang_items().clone_trait(), - self.tcx.lang_items().sync_trait(), - self.tcx.get_diagnostic_item(sym::Send), - self.tcx.lang_items().unpin_trait(), - self.tcx.get_diagnostic_item(sym::unwind_safe_trait), - self.tcx.get_diagnostic_item(sym::ref_unwind_safe_trait), + let auto_traits_def_id: Vec<_> = vec![ + (self.tcx.lang_items().clone_trait(), self.tcx.host_effect()), + (self.tcx.lang_items().sync_trait(), None), + (self.tcx.get_diagnostic_item(sym::Send), None), + (self.tcx.lang_items().unpin_trait(), None), + (self.tcx.get_diagnostic_item(sym::unwind_safe_trait), None), + (self.tcx.get_diagnostic_item(sym::ref_unwind_safe_trait), None), ]; const AUTO_TRAITS: [&str; 6] = ["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"]; @@ -965,12 +965,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut obligations_should_hold = Vec::new(); // Checks if a root variable implements any of the auto traits - for check_trait in auto_traits_def_id.iter() { + for (check_trait, rest) in auto_traits_def_id.iter().copied() { obligations_should_hold.push( check_trait .map(|check_trait| { self.infcx - .type_implements_trait(check_trait, [ty], self.param_env) + .type_implements_trait( + check_trait, + [ty.into()].into_iter().chain(rest), + self.param_env, + ) .must_apply_modulo_regions() }) .unwrap_or(false), @@ -989,12 +993,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Checks if a capture implements any of the auto traits let mut obligations_holds_for_capture = Vec::new(); - for check_trait in auto_traits_def_id.iter() { + for (check_trait, rest) in auto_traits_def_id.iter().copied() { obligations_holds_for_capture.push( check_trait .map(|check_trait| { self.infcx - .type_implements_trait(check_trait, [ty], self.param_env) + .type_implements_trait( + check_trait, + [ty.into()].into_iter().chain(rest), + self.param_env, + ) .must_apply_modulo_regions() }) .unwrap_or(false), diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 6dc34daf39136..d06927250cef6 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -801,12 +801,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { fn fold_effect(&mut self, e: ty::Effect<'tcx>) -> ty::Effect<'tcx> { match self.infcx.fully_resolve(e) { Ok(e) => e, - Err(_) => { - debug!("Resolver::fold_effect: input effect `{e:?}` not fully resolvable"); - let err = self.report_error(e); - self.replaced_with_error = Some(err); - self.tcx().effect_error(e.kind) - } + Err(_) => bug!("Resolver::fold_effect: input effect `{e:?}` not fully resolvable"), } } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index dc2c78714db6f..e9c7c6e430622 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -545,7 +545,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { } ty::EffectValue::Bound(debruijn, _) => { if debruijn >= self.binder_index { - bug!("escaping bound type during canonicalization") + bug!("escaping bound effect during canonicalization") } else { return e; } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 00ab24b6104fb..a36da3e5b9730 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -32,7 +32,8 @@ use crate::traits::{Obligation, PredicateObligations}; use rustc_data_structures::sso::SsoHashMap; use rustc_hir::def_id::DefId; use rustc_middle::infer::unify_key::{ - ConstVarValue, ConstVariableValue, EffectVarValue, EffectVariableValue, + ConstVarValue, ConstVariableValue, EffectVarValue, EffectVariableOrigin, + EffectVariableOriginKind, EffectVariableValue, }; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::ObligationCause; @@ -202,13 +203,15 @@ impl<'tcx> InferCtxt<'tcx> { let a = self.shallow_resolve(a); let b = self.shallow_resolve(b); + let a_is_expected = relation.a_is_expected(); + match (a.val, b.val) { ( ty::EffectValue::Infer(InferEffect::Var(a_vid)), ty::EffectValue::Infer(InferEffect::Var(b_vid)), ) => { self.inner.borrow_mut().effect_unification_table().union(a_vid, b_vid); - return Ok(a); + Ok(a) } // All other cases of inference with other variables are errors. @@ -216,10 +219,15 @@ impl<'tcx> InferCtxt<'tcx> { | (ty::EffectValue::Infer(_), ty::EffectValue::Infer(InferEffect::Var(_))) => { bug!("tried to combine Effect::Infer/Effect::Infer(InferEffect::Var)") } - _ => {} - } - ty::relate::super_relate_effect(relation, a, b) + (ty::EffectValue::Infer(InferEffect::Var(vid)), _) => { + self.unify_effect_variable(relation.param_env(), vid, b, a_is_expected) + } + (_, ty::EffectValue::Infer(InferEffect::Var(vid))) => { + self.unify_effect_variable(relation.param_env(), vid, a, !a_is_expected) + } + _ => ty::relate::super_relate_effect(relation, a, b), + } } /// Unifies the const variable `target_vid` with the given constant. @@ -291,6 +299,28 @@ impl<'tcx> InferCtxt<'tcx> { Ok(value) } + pub(crate) fn unify_effect_variable( + &self, + _param_env: ty::ParamEnv<'tcx>, + target_vid: ty::EffectVid<'tcx>, + value: ty::Effect<'tcx>, + _vid_is_expected: bool, + ) -> RelateResult<'tcx, ty::Effect<'tcx>> { + self.inner.borrow_mut().effect_unification_table().union_value( + target_vid, + EffectVarValue { + origin: EffectVariableOrigin { + kind: EffectVariableOriginKind::EffectInference, + // FIXME: pick something better from the type relation + span: DUMMY_SP, + effect_kind: value.kind, + }, + val: EffectVariableValue::Known { value }, + }, + ); + Ok(value) + } + fn unify_integral_variable( &self, vid_is_expected: bool, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 8a91a78390b1e..8587e4ddbb4d8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1583,7 +1583,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (false, Mismatch::Fixed("trait")) } ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")), - ValuePairs::Effects(_) => (false, Mismatch::Fixed("effect")), + ValuePairs::Effects(_) => (true, Mismatch::Fixed("effect")), }; let Some(vals) = self.values_str(values) else { // Derived error. Cancel the emitter. @@ -2724,6 +2724,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { TypeError::IntrinsicCast => { Error0308("cannot coerce intrinsics to function pointers") } + TypeError::EffectMismatch(_) => Error0308("mismatched effects"), _ => Error0308("mismatched types"), }, } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 1d84683d3f368..6c8ae0f3413cc 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -41,6 +41,7 @@ use rustc_span::Span; use std::cell::{Cell, RefCell}; use std::fmt; +use std::marker::PhantomData; use self::combine::CombineFields; use self::error_reporting::TypeErrCtxt; @@ -743,6 +744,29 @@ impl<'tcx> InferCtxt<'tcx> { freshen::TypeFreshener::new(self, true) } + /// Effect fallback is infallible. We always figure out a concrete value for the effect + /// from the environment. If we can't figure out something we fall back to the effect + /// not applying, which is always a safe choice. + pub fn effects_inference_fallback(&self) { + let mut inner = self.inner.borrow_mut(); + let mut table = inner.effect_unification_table(); + let n = table.len(); + + for i in 0..n { + let index = i as u32; + let vid = ty::EffectVid { index, phantom: PhantomData }; + let EffectVarValue { val, origin } = table.probe_value(vid); + match val { + EffectVariableValue::Unknown { .. } => {} + EffectVariableValue::Known { .. } => continue, + } + let value = self.tcx.mk_effect(ty::EffectValue::Rigid { on: true }, origin.effect_kind); + let val = EffectVariableValue::Known { value }; + let value = EffectVarValue { val, origin }; + table.union_value(vid, value); + } + } + pub fn unsolved_variables(&self) -> Vec> { let mut inner = self.inner.borrow_mut(); let mut vars: Vec> = inner @@ -2079,6 +2103,18 @@ impl<'tcx> TypeTrace<'tcx> { values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } + + pub fn effects( + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: ty::Effect<'tcx>, + b: ty::Effect<'tcx>, + ) -> TypeTrace<'tcx> { + TypeTrace { + cause: cause.clone(), + values: Effects(ExpectedFound::new(a_is_expected, a.into(), b.into())), + } + } } impl<'tcx> SubregionOrigin<'tcx> { diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 39f2e7f4ae9fc..0564e9190c556 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -3,7 +3,9 @@ use super::{FixupError, FixupResult, InferCtxt, Span}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor}; -use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable}; +use rustc_middle::ty::{ + self, Const, InferConst, InferEffect, Ty, TyCtxt, TypeFoldable, TypeVisitable, +}; use std::ops::ControlFlow; @@ -276,4 +278,18 @@ impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { c.try_super_fold_with(self) } } + + fn try_fold_effect(&mut self, e: ty::Effect<'tcx>) -> Result, Self::Error> { + let e = self.infcx.shallow_resolve(e); + match e.val { + ty::EffectValue::Infer(InferEffect::Var(vid)) => { + bug!("unresolved inference effect: {vid:?}"); + } + ty::EffectValue::Infer(InferEffect::Fresh(_)) => { + bug!("Unexpected const in full const resolver: {:?}", e); + } + _ => {} + } + e.try_super_fold_with(self) + } } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 26a6d064391a9..80520428d4326 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -215,8 +215,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { b: ty::Effect<'tcx>, ) -> RelateResult<'tcx, ty::Effect<'tcx>> { match (a.val, b.val) { - // Any effect matches the rigid "off" effect. For example: `T: ~const Trait` implies `T: Trait` - (ty::EffectValue::Rigid { on: false }, _) => Ok(a), + // Any effect matches the rigid "on" effect. For example: `T: ~const Trait` (off) implies `T: Trait` (on) + (ty::EffectValue::Rigid { on: true }, _) => Ok(a), _ => self.fields.infcx.super_combine_effect(self, a, b), } } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 8f0bd3a9abe5e..be7e04778d379 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -3,7 +3,7 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_middle::ty::{self, ToPredicate, TyCtxt}; +use rustc_middle::ty::{self, ToPredicate, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -142,6 +142,20 @@ impl<'tcx> Elaborator<'tcx> { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + // `T: ~const Trait` implies `T: Trait` + if obligation.predicate.has_type_flags(ty::TypeFlags::HAS_EFFECT_PARAM) { + let no_effect = obligation.clone().fold_with(&mut ty::fold::BottomUpFolder { + tcx, + ty_op: |t| t, + lt_op: |l| l, + ct_op: |c| c, + e_op: |e| tcx.mk_effect(ty::EffectValue::Rigid { on: true }, e.kind), + }); + if self.visited.insert(no_effect.predicate) { + self.stack.push(no_effect) + } + } + // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); @@ -185,7 +199,19 @@ impl<'tcx> Elaborator<'tcx> { // though conceivably we might. } ty::PredicateKind::Clause(ty::Clause::Projection(..)) => { - // Nothing to elaborate in a projection predicate. + // `::TYPE` implies `::TYPE` + if obligation.predicate.has_type_flags(ty::TypeFlags::HAS_EFFECT_PARAM) { + let no_effect = obligation.clone().fold_with(&mut ty::fold::BottomUpFolder { + tcx, + ty_op: |t| t, + lt_op: |l| l, + ct_op: |c| c, + e_op: |e| tcx.mk_effect(ty::EffectValue::Rigid { on: true }, e.kind), + }); + if self.visited.insert(no_effect.predicate) { + self.stack.push(no_effect) + } + } } ty::PredicateKind::ClosureKind(..) => { // Nothing to elaborate when waiting for a closure's kind to be inferred. diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index b6c6e9d559c8c..3c1dfcb556aa9 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -8,6 +8,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; +use rustc_type_ir::TypeFlags; impl<'tcx> TyCtxt<'tcx> { /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts @@ -93,7 +94,13 @@ impl<'tcx> TyCtxt<'tcx> { // @lcnr believes that successfully evaluating even though there are // used generic parameters is a bug of evaluation, so checking for it // here does feel somewhat sensible. - if !self.features().generic_const_exprs && ct.substs.has_non_region_param() { + if !self.features().generic_const_exprs + && ct.substs.has_type_flags( + TypeFlags::NEEDS_SUBST + - TypeFlags::HAS_RE_PARAM + - TypeFlags::HAS_EFFECT_PARAM, + ) + { assert!(matches!(self.def_kind(ct.def.did), DefKind::AnonConst)); let mir_body = self.mir_for_ctfe_opt_const_arg(ct.def); if mir_body.is_polymorphic { diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index ec69864c951d4..60295d6aba3fe 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -164,7 +164,7 @@ pub enum SelectionCandidate<'tcx> { BuiltinUnsizeCandidate, /// Implementation of `const Destruct`, optionally from a custom `impl const Drop`. - ConstDestructCandidate(Option), + ConstDestructCandidate(Option, ty::Effect<'tcx>), } /// The result of trait evaluation. The order is important diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 8ce06404de081..283fe1dd72c76 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -1,4 +1,5 @@ use crate::ty::{self, Ty, TyCtxt}; +use hir::def_id::DefId; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; @@ -116,6 +117,8 @@ pub struct OverloadedDeref<'tcx> { /// The `Span` associated with the field access or method call /// that triggered this overloaded deref. pub span: Span, + /// The body that decides what effects are inferred. + pub context: DefId, } impl<'tcx> OverloadedDeref<'tcx> { @@ -131,7 +134,10 @@ impl<'tcx> OverloadedDeref<'tcx> { .find(|m| m.kind == ty::AssocKind::Fn) .unwrap() .def_id; - tcx.mk_fn_def(method_def_id, [source]) + tcx.mk_fn_def( + method_def_id, + tcx.mk_substs_trait_with_effect(trait_def_id, [source], self.context), + ) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 029f61af12ee0..e717590846318 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -722,7 +722,7 @@ impl<'tcx> TyCtxt<'tcx> { ) } - /// Like [TyCtxt::ty_error] but for effects. + /// Like [TyCtxt::ty_error_with_message] but for effects. #[track_caller] pub fn effect_error_with_message( self, @@ -785,6 +785,17 @@ impl<'tcx> TyCtxt<'tcx> { self.features_query(()) } + #[inline(always)] + pub fn effects(self) -> bool { + self.features().effects + || (cfg!(debug_assertions) && std::env::var_os("RUSTC_ENABLE_EFFECTS").is_some()) + } + + /// A helper while effects are not enabled unconditionally. + pub fn host_effect(self) -> Option> { + self.effects().then_some(self.effects.host.into()) + } + pub fn def_key(self, id: DefId) -> rustc_hir::definitions::DefKey { // Accessing the DefKey is ok, since it is part of DefPathHash. if let Some(id) = id.as_local() { @@ -2264,6 +2275,7 @@ impl<'tcx> TyCtxt<'tcx> { iter.intern_with(|xs| self.intern_place_elems(xs)) } + /// Create the substitutions for a trait and its generic params. pub fn mk_substs_trait( self, self_ty: Ty<'tcx>, @@ -2272,6 +2284,7 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_substs(iter::once(self_ty.into()).chain(rest)) } + #[track_caller] pub fn mk_trait_ref( self, trait_def_id: DefId, @@ -2290,6 +2303,48 @@ impl<'tcx> TyCtxt<'tcx> { ty::AliasTy { def_id, substs, _use_mk_alias_ty_instead: () } } + pub fn mk_trait_ref_with_effect( + self, + trait_def_id: DefId, + substs: impl IntoIterator>>, + context: DefId, + ) -> ty::TraitRef<'tcx> { + let substs = self.mk_substs_trait_with_effect(trait_def_id, substs, context); + self.mk_trait_ref(trait_def_id, substs) + } + + /// Create the substitutions for a trait and its generic params and fill in the effects from context + #[instrument(level = "trace", skip(self, substs), ret)] + #[track_caller] + pub fn mk_substs_trait_with_effect( + self, + trait_def_id: DefId, + substs: impl IntoIterator>>, + context: DefId, + ) -> SubstsRef<'tcx> { + debug_assert!(self.is_trait(trait_def_id)); + let effects = + self.generics_of(trait_def_id).params.iter().filter_map(|param| match param.kind { + ty::GenericParamDefKind::Effect { kind } => Some( + self.effect_from_context(context, kind, || ty::EffectValue::Rigid { + on: match kind { + ty::EffectKind::Host => !self.def_kind(context).require_const(), + }, + }) + .into(), + ), + _ => None, + }); + let substs = self.mk_substs(substs.into_iter().map(Into::into).chain(effects)); + let n = self.generics_of(trait_def_id).count(); + debug_assert_eq!( + n, + substs.len(), + "expected {n} generic parameters for {trait_def_id:?}, but got {substs:?}", + ); + substs + } + pub fn mk_bound_variable_kinds< I: InternAs>, >( @@ -2394,6 +2449,26 @@ impl<'tcx> TyCtxt<'tcx> { ) } + pub fn effect_from_context( + self, + def_id: DefId, + kind: ty::EffectKind, + missing: impl FnOnce() -> ty::EffectValue<'tcx>, + ) -> ty::Effect<'tcx> { + if self.is_closure(def_id) { + let on = match kind { + // Closures cannot be const callable yet. + ty::EffectKind::Host => true, + }; + return self.mk_effect(ty::EffectValue::Rigid { on }, kind); + } + let val = match self.generics_of(def_id).effect_param(kind, self) { + Some(param) => ty::EffectValue::Param { index: param.index }, + None => missing(), + }; + self.mk_effect(val, kind) + } + /// Whether the `def_id` counts as const fn in the current crate, considering all active /// feature gates pub fn is_const_fn(self, def_id: DefId) -> bool { @@ -2455,6 +2530,16 @@ impl<'tcx> TyCtxtAt<'tcx> { let trait_def_id = self.require_lang_item(trait_lang_item, Some(self.span)); self.tcx.mk_trait_ref(trait_def_id, substs) } + + pub fn mk_trait_ref_with_effect( + self, + trait_lang_item: LangItem, + substs: impl IntoIterator>>, + context: DefId, + ) -> ty::TraitRef<'tcx> { + let trait_def_id = self.require_lang_item(trait_lang_item, Some(self.span)); + self.tcx.mk_trait_ref_with_effect(trait_def_id, substs, context) + } } /// Parameter attributes that can only be determined by examining the body of a function instead diff --git a/compiler/rustc_middle/src/ty/effect.rs b/compiler/rustc_middle/src/ty/effect.rs index c99ce37da2174..6bdf8d7058b2d 100644 --- a/compiler/rustc_middle/src/ty/effect.rs +++ b/compiler/rustc_middle/src/ty/effect.rs @@ -19,7 +19,7 @@ impl<'tcx> std::ops::Deref for Effect<'tcx> { impl<'tcx> fmt::Debug for Effect<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.0.fmt(f) + fmt::Display::fmt(self, f) } } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index b0bc36773172d..dede7a01dc0f9 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -271,6 +271,22 @@ impl<'tcx> Generics { } } + /// Returns the `GenericParamDef` associated with the effect param (if any). + pub fn effect_param( + &'tcx self, + effect_kind: ty::EffectKind, + tcx: TyCtxt<'tcx>, + ) -> Option<&GenericParamDef> { + self.params + .iter() + .rev() + .find(|pred| match pred.kind { + GenericParamDefKind::Effect { kind } => kind == effect_kind, + _ => false, + }) + .or_else(|| tcx.generics_of(self.parent?).effect_param(effect_kind, tcx)) + } + /// Returns `true` if `params` has `impl Trait`. pub fn has_impl_trait(&'tcx self) -> bool { self.params.iter().any(|param| { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 435f05bb972d0..98b55bc3409fb 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -338,8 +338,13 @@ impl<'tcx> Instance<'tcx> { ty::GenericParamDefKind::Const { .. } => { bug!("Instance::mono: {:?} has const parameters", def_id) } - ty::GenericParamDefKind::Effect { .. } => { - bug!("Instance::mono: {:?} has effect parameters", def_id) + ty::GenericParamDefKind::Effect { kind } => { + // FIXME: this is necessary for `panic` and friends in the monomorphization collector. + // Should we take the constness effect from the context or just ignore this because it's only + // happening for the panic items anyway, and CTFE handles it properly. + match kind { + ty::EffectKind::Host => tcx.effects.host.into(), + } } }); @@ -569,7 +574,8 @@ impl<'tcx> Instance<'tcx> { let sig = tcx.try_normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig).ok()?; assert_eq!(sig.inputs().len(), 1); - let substs = tcx.mk_substs_trait(self_ty, [sig.inputs()[0].into()]); + let substs = + tcx.mk_substs_trait_with_effect(fn_once, [self_ty, sig.inputs()[0]], closure_did); debug!(?self_ty, ?sig); Some(Instance { def, substs }) diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index b192d97f2b09a..fa5e0fd7d9b27 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -224,16 +224,15 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { match self.map.get(&e.into()).map(|k| k.unpack()) { // Found it in the substitution list, replace with the parameter from the // opaque type. - Some(GenericArgKind::Effect(e)) => e, - Some(u) => panic!("effect mapped to unexpected kind: {:?}", u), - None => { - self.tcx.sess.emit_err(ParamNotUsedTraitAlias { - param: e.to_string(), - span: self.span, - }); - - self.tcx().effect_error(e.kind) + Some(GenericArgKind::Effect(e)) => { + self.tcx.sess.delay_span_bug( + self.span, + &format!("this can only happen when we allow `impl const Trait` opaque types: {e:?}"), + ); + self.tcx.mk_effect(ty::EffectValue::Rigid { on: true }, e.kind) } + Some(u) => panic!("effect mapped to unexpected kind: {:?}", u), + None => self.tcx.mk_effect(ty::EffectValue::Rigid { on: true }, e.kind), } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 27cb1ce83b9cf..e44cf96a4b8a8 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -860,6 +860,29 @@ impl<'tcx> PolyTraitRef<'tcx> { pub fn def_id(&self) -> DefId { self.skip_binder().def_id } + + /// Fall back to `!const` if the `other` is `~const` + pub fn pick_concrete_effect(self, other: Self, constness: ty::BoundConstness) -> Option { + if self.def_id() != other.def_id() { + return None; + } + if self.self_ty() != other.self_ty() { + return None; + } + // FIXME(effects): somewhat fishy, should we do a step by step walk of the + // two substs and compare at each site? + match (self.has_effect_param(), other.has_effect_param(), constness) { + (false, false, _) | (true, true, _) => None, + (true, false, ty::BoundConstness::ConstIfConst) => Some(self), + (true, false, ty::BoundConstness::NotConst) => Some(other), + (false, true, ty::BoundConstness::ConstIfConst) => Some(other), + (false, true, ty::BoundConstness::NotConst) => Some(self), + } + } + + fn has_effect_param(&self) -> bool { + self.skip_binder().substs.has_type_flags(ty::TypeFlags::HAS_EFFECT_PARAM) + } } impl rustc_errors::IntoDiagnosticArg for PolyTraitRef<'_> { diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 0cc416842984f..7fa4c8f9bd25e 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -429,6 +429,16 @@ impl<'tcx> InternalSubsts<'tcx> { }) } + #[inline] + #[track_caller] + pub fn effect_at(&self, i: usize) -> ty::Effect<'tcx> { + if let GenericArgKind::Effect(e) = self[i].unpack() { + e + } else { + bug!("expected effect for param #{} in {:?}", i, self); + } + } + #[inline] #[track_caller] pub fn type_at(&self, i: usize) -> Ty<'tcx> { diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 46e14cc9ac3b1..fa0cf78717de9 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -248,7 +248,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ref_str_ty = tcx.mk_imm_ref(re_erased, tcx.types.str_); let ref_str = self.temp(ref_str_ty, test.span); let deref = tcx.require_lang_item(LangItem::Deref, None); - let method = trait_method(tcx, deref, sym::deref, [ty]); + let method = trait_method(tcx, deref, sym::deref, [ty], self.def_id); let eq_block = self.cfg.start_new_block(); self.cfg.push_assign(block, source_info, ref_string, Rvalue::Ref(re_erased, BorrowKind::Shared, place)); self.cfg.terminate( @@ -443,7 +443,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span)); - let method = trait_method(self.tcx, eq_def_id, sym::eq, [deref_ty, deref_ty]); + let method = trait_method(self.tcx, eq_def_id, sym::eq, [deref_ty, deref_ty], self.def_id); let bool_ty = self.tcx.types.bool; let eq_result = self.temp(bool_ty, source_info.span); @@ -836,7 +836,10 @@ fn trait_method<'tcx>( trait_def_id: DefId, method_name: Symbol, substs: impl IntoIterator>>, + context: DefId, ) -> ConstantKind<'tcx> { + let substs = tcx.mk_substs_trait_with_effect(trait_def_id, substs, context); + // The unhygienic comparison here is acceptable because this is only // used on known traits. let item = tcx diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 7836ae2e7b76f..d8d15f7c49794 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -614,6 +614,11 @@ where let drop_trait = tcx.require_lang_item(LangItem::Drop, None); let drop_fn = tcx.associated_item_def_ids(drop_trait)[0]; let ty = self.place_ty(self.place); + let substs = tcx.mk_substs_trait_with_effect( + drop_trait, + [ty], + self.elaborator.body().source.def_id(), + ); let ref_ty = tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }); @@ -631,12 +636,7 @@ where )], terminator: Some(Terminator { kind: TerminatorKind::Call { - func: Operand::function_handle( - tcx, - drop_fn, - [ty.into()], - self.source_info.span, - ), + func: Operand::function_handle(tcx, drop_fn, substs, self.source_info.span), args: vec![Operand::Move(Place::from(ref_place))], destination: unit_temp, target: Some(succ), diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index dace540fa29d2..a209ea7419b3c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -3,8 +3,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::InternalSubsts; use rustc_middle::ty::{self, EarlyBinder, GeneratorSubsts, Ty, TyCtxt}; +use rustc_middle::ty::{DefIdTree, InternalSubsts}; use rustc_target::abi::VariantIdx; use rustc_index::vec::{Idx, IndexVec}; @@ -363,7 +363,8 @@ impl<'tcx> CloneShimBuilder<'tcx> { // we must subst the self_ty because it's // otherwise going to be TySelf and we can't index // or access fields of a Place of type TySelf. - let sig = tcx.bound_fn_sig(def_id).subst(tcx, &[self_ty.into()]); + let substs = tcx.mk_substs([self_ty.into()].into_iter().chain(tcx.host_effect())); + let sig = tcx.bound_fn_sig(def_id).subst(tcx, substs); let sig = tcx.erase_late_bound_regions(sig); let span = tcx.def_span(def_id); @@ -444,7 +445,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { let tcx = self.tcx; // `func == Clone::clone(&ty) -> ty` - let func_ty = tcx.mk_fn_def(self.def_id, [ty]); + let func_ty = tcx.mk_fn_def(self.def_id, [ty.into()].into_iter().chain(tcx.host_effect())); let func = Operand::Constant(Box::new(Constant { span: self.span, user_ty: None, @@ -589,6 +590,8 @@ fn build_call_shim<'tcx>( rcvr_adjustment: Option, call_kind: CallKind<'tcx>, ) -> Body<'tcx> { + let def_id = instance.def_id(); + // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used // to substitute into the signature of the shim. It is not necessary for users of this // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`). @@ -599,13 +602,13 @@ fn build_call_shim<'tcx>( // Create substitutions for the `Self` and `Args` generic parameters of the shim body. let arg_tup = tcx.mk_tup(untuple_args.iter()); + let sig_substs = tcx.mk_substs_trait_with_effect(tcx.parent(def_id), [ty, arg_tup], def_id); - (Some([ty.into(), arg_tup.into()]), Some(untuple_args)) + (Some(sig_substs), Some(untuple_args)) } else { (None, None) }; - let def_id = instance.def_id(); let sig = tcx.bound_fn_sig(def_id); let sig = sig.map_bound(|sig| tcx.erase_late_bound_regions(sig)); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5d5f8d6d65405..8b0b9d4d64c3c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -642,6 +642,7 @@ symbols! { dyn_trait, e, edition_panic, + effects, eh_catch_typeinfo, eh_personality, emit_enum, diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index e988c77a064f6..a33dd4021d13c 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -2,6 +2,7 @@ use crate::errors::AutoDerefReachedRecursionLimit; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::NormalizeExt; use crate::traits::{self, TraitEngine, TraitEngineExt}; +use hir::CRATE_HIR_ID; use rustc_hir as hir; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::TypeVisitable; @@ -122,8 +123,25 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { let tcx = self.infcx.tcx; + let deref_trait = tcx.lang_items().deref_trait()?; + let ty = ty::GenericArg::from(ty); + // - let trait_ref = tcx.mk_trait_ref(tcx.lang_items().deref_trait()?, [ty]); + let trait_ref = if self.body_id == CRATE_HIR_ID { + // The `method_autoderef_steps` doesn't care about details like effects and will just + // find all derefs. The steps will be checked again outside the query. + tcx.mk_trait_ref( + deref_trait, + [ty.into()] + .into_iter() + // HACK: allow using deref non-generically in tests with effects on, even + // if libcore doesn't have the effects feature yet. + .chain(tcx.host_effect().filter(|_| tcx.generics_of(deref_trait).count() == 2)), + ) + } else { + let context = self.body_id.owner.to_def_id(); + tcx.mk_trait_ref_with_effect(deref_trait, [ty], context) + }; let cause = traits::ObligationCause::misc(self.span, self.body_id); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 9c098e1a2fc12..312a7c0f44fe8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -31,6 +31,7 @@ use rustc_hir::Item; use rustc_hir::Node; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; +use rustc_middle::infer::unify_key::EffectVariableOriginKind; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -351,7 +352,19 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { span: DUMMY_SP, kind: TypeVariableOriginKind::MiscVariable, }); - let trait_ref = self.tcx.mk_trait_ref(trait_def_id, [ty.skip_binder(), var]); + let trait_ref = if self.tcx.effects() { + let e_var = self.next_effect_var( + DUMMY_SP, + EffectVariableOriginKind::MiscVariable, + ty::EffectKind::Host, + ); + self.tcx.mk_trait_ref( + trait_def_id, + [ty::GenericArg::from(ty.skip_binder()), var.into(), e_var.into()], + ) + } else { + self.tcx.mk_trait_ref(trait_def_id, [ty.skip_binder(), var]) + }; let obligation = Obligation::new( self.tcx, ObligationCause::dummy(), diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c30531fa90664..b1e19ccbfb38e 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -142,7 +142,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( } #[instrument(level = "debug", skip(infcx, param_env, span, pred), ret)] -fn pred_known_to_hold_modulo_regions<'tcx>( +pub fn pred_known_to_hold_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, pred: impl ToPredicate<'tcx> + TypeVisitable<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 174bd8932bae3..2b61ba7c76703 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1907,6 +1907,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( tcx, gen_def_id, obligation.predicate.self_ty(), + obligation.predicate.substs[2..].to_vec(), gen_sig, ) .map_bound(|(trait_ref, yield_ty, return_ty)| { @@ -2078,6 +2079,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( tcx, fn_once_def_id, obligation.predicate.self_ty(), + obligation.predicate.substs[2..].to_owned(), fn_sig, flag, ) @@ -2242,6 +2244,8 @@ fn check_substs_compatible<'tcx>( (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {} + (ty::GenericParamDefKind::Effect { kind, .. }, ty::GenericArgKind::Effect(e)) + if e.kind == *kind => {} _ => return false, } } diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 09b58894d3040..8a6c12dc7c70e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -66,7 +66,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let mut _orig_values = OriginalQueryValues::default(); let param_env = match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::Clause::Trait(pred)) if !self.tcx.effects() => { // we ignore the value set to it. let mut _constness = pred.constness; obligation diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index c54d901e9b10a..f3a91df1ef0d1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -9,6 +9,7 @@ use hir::LangItem; use rustc_hir as hir; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; +use rustc_middle::infer::unify_key::EffectVariableOriginKind; use rustc_middle::ty::{self, Ty, TypeVisitable}; use rustc_target::spec::abi::Abi; @@ -523,8 +524,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return None; } + let effect = self.infcx.tcx.effects().then(|| { + ty::GenericArg::from(self.infcx.next_effect_var( + cause.span, + EffectVariableOriginKind::EffectInference, + ty::EffectKind::Host, + )) + }); + // - let trait_ref = tcx.mk_trait_ref(tcx.lang_items().deref_trait()?, [ty]); + let trait_ref = tcx + .mk_trait_ref(tcx.lang_items().deref_trait()?, [ty.into()].into_iter().chain(effect)); let obligation = traits::Obligation::new(tcx, cause.clone(), param_env, ty::Binder::dummy(trait_ref)); @@ -725,10 +735,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { + let constness = obligation + .predicate + .map_bound_ref(|pred| { + // This is super hacky, but it's effectively asking whether the + // `Destruct` trait is defined in a crate with the effects + // feature on. Remove this check once the feature is removed. + if pred.trait_ref.substs.len() > 1 { + pred.trait_ref.substs.effect_at(1) + } else { + self.tcx().effects.host + } + }) + .no_bound_vars() + .expect("obligations should not be bound over effects"); + // If the predicate is `~const Destruct` in a non-const environment, we don't actually need // to check anything. We'll short-circuit checking any obligations in confirmation, too. - if !obligation.is_const() { - candidates.vec.push(ConstDestructCandidate(None)); + if self.tcx().effects() { + match constness.val { + ty::EffectValue::Rigid { on: true } => { + candidates.vec.push(ConstDestructCandidate(None, constness)); + return; + } + ty::EffectValue::Infer(_) => candidates.ambiguous = true, + _ => (), + } + } else if !obligation.is_const() { + candidates.vec.push(ConstDestructCandidate(None, constness)); return; } @@ -765,7 +799,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Tuple(_) | ty::GeneratorWitness(_) => { // These are built-in, and cannot have a custom `impl const Destruct`. - candidates.vec.push(ConstDestructCandidate(None)); + candidates.vec.push(ConstDestructCandidate(None, constness)); } ty::Adt(..) => { @@ -779,11 +813,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(impl_def_id) = relevant_impl { // Check that `impl Drop` is actually const, if there is a custom impl if self.tcx().constness(impl_def_id) == hir::Constness::Const { - candidates.vec.push(ConstDestructCandidate(Some(impl_def_id))); + candidates.vec.push(ConstDestructCandidate(Some(impl_def_id), constness)); } } else { // Otherwise check the ADT like a built-in type (structurally) - candidates.vec.push(ConstDestructCandidate(None)); + candidates.vec.push(ConstDestructCandidate(None, constness)); } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 1f0689e051509..03c63b6bd7ac9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -13,7 +13,7 @@ use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_middle::ty::{ self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef, - ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, + ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeVisitable, }; use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; @@ -62,7 +62,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ParamCandidate(param) => { let obligations = self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); - ImplSource::Param(obligations, param.skip_binder().constness) + ImplSource::Param( + obligations, + if self.tcx().effects() { + if param + .skip_binder() + .trait_ref + .substs + .has_type_flags(ty::TypeFlags::HAS_EFFECT_PARAM) + { + ty::BoundConstness::ConstIfConst + } else { + ty::BoundConstness::NotConst + } + } else { + param.skip_binder().constness + }, + ) } ImplCandidate(impl_def_id) => { @@ -126,8 +142,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::TraitUpcasting(data) } - ConstDestructCandidate(def_id) => { - let data = self.confirm_const_destruct_candidate(obligation, def_id)?; + ConstDestructCandidate(def_id, constness) => { + let data = self.confirm_const_destruct_candidate(obligation, def_id, constness)?; ImplSource::ConstDestruct(data) } }; @@ -242,12 +258,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let lang_items = self.tcx().lang_items(); let obligations = if has_nested { let trait_def = obligation.predicate.def_id(); - let conditions = if Some(trait_def) == lang_items.sized_trait() { - self.sized_conditions(obligation) + let const_effect; + let (conditions, params): (_, &[_]) = if Some(trait_def) == lang_items.sized_trait() { + (self.sized_conditions(obligation), &[]) } else if Some(trait_def) == lang_items.copy_trait() { - self.copy_clone_conditions(obligation) + (self.copy_clone_conditions(obligation), &[]) } else if Some(trait_def) == lang_items.clone_trait() { - self.copy_clone_conditions(obligation) + let rest: &[_] = if self.tcx().effects() { + const_effect = [obligation.predicate.skip_binder().trait_ref.substs[1]]; + &const_effect + } else { + &[] + }; + (self.copy_clone_conditions(obligation), rest) } else { bug!("unexpected builtin trait {:?}", trait_def) }; @@ -263,6 +286,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, trait_def, nested, + params, ) }) } else { @@ -355,6 +379,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, trait_def_id, nested, + &[], ); // Adds the predicates from the trait. Note that this contains a `Self: Trait` @@ -616,15 +641,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, "confirm_fn_pointer_candidate"); let tcx = self.tcx(); - let self_ty = self + let (self_ty, effects) = self .infcx - .shallow_resolve(obligation.self_ty().no_bound_vars()) + .shallow_resolve( + obligation + .predicate + .map_bound(|pred| (pred.self_ty(), pred.trait_ref.substs[2..].to_vec())) + .no_bound_vars(), + ) .expect("fn pointer should not capture bound vars from predicate"); let sig = self_ty.fn_sig(tcx); let trait_ref = closure_trait_ref_and_return_type( tcx, obligation.predicate.def_id(), self_ty, + effects, sig, util::TupleArgumentsFlag::Yes, ) @@ -706,16 +737,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // NOTE: The self-type is a generator type and hence is // in fact unparameterized (or at least does not reference any // regions bound in the obligation). - let self_ty = obligation - .predicate - .self_ty() - .no_bound_vars() - .expect("unboxed closure type should not capture bound vars from the predicate"); + let (self_ty, effects) = self + .infcx + .shallow_resolve( + obligation + .predicate + .map_bound(|pred| (pred.self_ty(), pred.trait_ref.substs[2..].to_vec())) + .no_bound_vars(), + ) + .expect("generator type should not capture bound vars from predicate"); let trait_ref = super::util::generator_trait_ref_and_outputs( self.tcx(), obligation.predicate.def_id(), self_ty, + effects, gen_sig, ) .map_bound(|(trait_ref, ..)| trait_ref); @@ -1211,12 +1247,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, impl_def_id: Option, + constness: ty::Effect<'tcx>, ) -> Result>, SelectionError<'tcx>> { - // `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop` - if !obligation.is_const() { - return Ok(ImplSourceConstDestructData { nested: vec![] }); + if self.tcx().effects() { + // `Destruct` is always trivially true, only `~const Destruct` needs to check something. + if let ty::EffectValue::Rigid { on: true } = constness.val { + return Ok(ImplSourceConstDestructData { nested: vec![] }); + } + } else { + // `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop` + if !obligation.is_const() { + return Ok(ImplSourceConstDestructData { nested: vec![] }); + } } + let destruct_effect: Option> = + self.tcx().effects().then_some(constness.into()); + let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None); let tcx = self.tcx(); @@ -1312,10 +1359,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause.clone(), obligation.recursion_depth + 1, self_ty.rebind(ty::TraitPredicate { - trait_ref: self - .tcx() - .at(cause.span) - .mk_trait_ref(LangItem::Destruct, [nested_ty]), + trait_ref: self.tcx().at(cause.span).mk_trait_ref( + LangItem::Destruct, + [nested_ty.into()].into_iter().chain(destruct_effect), + ), constness: ty::BoundConstness::ConstIfConst, polarity: ty::ImplPolarity::Positive, }), @@ -1336,10 +1383,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // or it's an ADT (and we need to check for a custom impl during selection) _ => { let predicate = self_ty.rebind(ty::TraitPredicate { - trait_ref: self - .tcx() - .at(cause.span) - .mk_trait_ref(LangItem::Destruct, [nested_ty]), + trait_ref: self.tcx().at(cause.span).mk_trait_ref( + LangItem::Destruct, + [nested_ty.into()].into_iter().chain(destruct_effect), + ), constness: ty::BoundConstness::ConstIfConst, polarity: ty::ImplPolarity::Positive, }); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c669ddf2c98dc..d908ee80a22ec 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1354,11 +1354,71 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Vec> { trace!("{candidates:#?}"); let tcx = self.tcx(); - let mut result = Vec::with_capacity(candidates.len()); + let mut result: Vec> = Vec::with_capacity(candidates.len()); - for candidate in candidates { + 'candidate: for candidate in candidates { + trace!("{result:#?}"); // Respect const trait obligations - if obligation.is_const() { + if self.tcx().effects() { + match candidate { + // Skip `T: Trait` if we also have `T: ~const Trait` + ParamCandidate(candidate) => { + 'res: for (i, res) in result.iter().enumerate() { + if let ParamCandidate(res) = res { + if res.def_id() == candidate.def_id() { + enum SkipOrRemove { + Skip, + Remove, + } + let mut sor = None; + for (res, candidate) in std::iter::zip( + res.skip_binder().trait_ref.substs, + candidate.skip_binder().trait_ref.substs, + ) { + match (res.unpack(), candidate.unpack()) { + ( + ty::GenericArgKind::Effect(res), + ty::GenericArgKind::Effect(candidate), + ) => match (res.val, candidate.val) { + ( + ty::EffectValue::Param { .. }, + ty::EffectValue::Rigid { on: true }, + ) => sor = sor.or(Some(SkipOrRemove::Skip)), + ( + ty::EffectValue::Rigid { on: true }, + ty::EffectValue::Param { .. }, + ) => sor = sor.or(Some(SkipOrRemove::Remove)), + _ => { + if res != candidate { + continue 'res; + } + } + }, + _ => { + if res != candidate { + continue 'res; + } + } + } + } + match sor { + Some(SkipOrRemove::Skip) => continue 'candidate, + Some(SkipOrRemove::Remove) => { + result.remove(i); + break 'res; + } + // Duplicate candidates, skip this one, as exactly the same candidate + // already exists. + None => continue 'candidate, + } + } + } + } + } + // FIXME(effects): add test for ProjectionCandiate and implement it + _ => {} + } + } else if obligation.is_const() { match candidate { // const impl ImplCandidate(def_id) if tcx.constness(def_id) == hir::Constness::Const => {} @@ -1382,7 +1442,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { continue } } - ConstDestructCandidate(_) => {} + ConstDestructCandidate(..) => {} _ => { // reject all other types of candidates continue; @@ -1806,8 +1866,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false, // (*) - (BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => true, - (_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => false, + (BuiltinCandidate { has_nested: false } | ConstDestructCandidate(..), _) => true, + (_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(..)) => false, (ParamCandidate(other), ParamCandidate(victim)) => { let same_except_bound_vars = other.skip_binder().trait_ref @@ -2270,6 +2330,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { recursion_depth: usize, trait_def_id: DefId, types: ty::Binder<'tcx, Vec>>, + params: &[ty::GenericArg<'tcx>], ) -> Vec> { // Because the types were potentially derived from // higher-ranked obligations they may reference late-bound @@ -2309,7 +2370,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause.clone(), trait_def_id, recursion_depth, - [normalized_ty], + [normalized_ty.into()].into_iter().chain(params.iter().copied()), ); obligations.push(placeholder_obligation); obligations @@ -2507,16 +2568,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // NOTE: The self-type is an unboxed closure type and hence is // in fact unparameterized (or at least does not reference any // regions bound in the obligation). - let self_ty = obligation - .predicate - .self_ty() - .no_bound_vars() - .expect("unboxed closure type should not capture bound vars from the predicate"); + let (self_ty, effects) = self + .infcx + .shallow_resolve( + obligation + .predicate + .map_bound(|pred| (pred.self_ty(), pred.trait_ref.substs[2..].to_vec())) + .no_bound_vars(), + ) + .expect("unboxed closure type should not capture bound vars from predicate"); closure_trait_ref_and_return_type( self.tcx(), obligation.predicate.def_id(), self_ty, + effects, closure_sig, util::TupleArgumentsFlag::No, ) diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index b5df583e3f4cb..1155b77bfef0a 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -286,27 +286,42 @@ pub fn closure_trait_ref_and_return_type<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, self_ty: Ty<'tcx>, + // Make this an array once the effect feature is always active + effects: Vec>, sig: ty::PolyFnSig<'tcx>, tuple_arguments: TupleArgumentsFlag, ) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> { assert!(!self_ty.has_escaping_bound_vars()); - let arguments_tuple = match tuple_arguments { - TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], - TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()), - }; - let trait_ref = tcx.mk_trait_ref(fn_trait_def_id, [self_ty, arguments_tuple]); - sig.map_bound(|sig| (trait_ref, sig.output())) + sig.map_bound(|sig| { + let arguments_tuple = match tuple_arguments { + TupleArgumentsFlag::No => sig.inputs()[0], + TupleArgumentsFlag::Yes => tcx.intern_tup(sig.inputs()), + }; + let trait_ref = tcx.mk_trait_ref( + fn_trait_def_id, + // FIXME: have the caller pass the effects here and use them. + [self_ty.into(), arguments_tuple.into()].into_iter().chain(effects), + ); + (trait_ref, sig.output()) + }) } pub fn generator_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, self_ty: Ty<'tcx>, + // Make this an array once the effect feature is always active + effects: Vec>, sig: ty::PolyGenSig<'tcx>, ) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { assert!(!self_ty.has_escaping_bound_vars()); - let trait_ref = tcx.mk_trait_ref(fn_trait_def_id, [self_ty, sig.skip_binder().resume_ty]); - sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty)) + sig.map_bound(|sig| { + let trait_ref = tcx.mk_trait_ref( + fn_trait_def_id, + [self_ty.into(), sig.resume_ty.into()].into_iter().chain(effects), + ); + (trait_ref, sig.yield_ty, sig.return_ty) + }) } pub fn future_trait_ref_and_outputs<'tcx>( diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 2825e0bbb4385..6f581e1a87995 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -354,7 +354,7 @@ where type Output = <[T] as Index>::Output; #[inline] - fn index(&self, index: I) -> &Self::Output { + fn index(&self, index: I) -> &<[T] as Index>::Output { Index::index(self as &[T], index) } } @@ -366,7 +366,7 @@ where [T]: ~const IndexMut, { #[inline] - fn index_mut(&mut self, index: I) -> &mut Self::Output { + fn index_mut(&mut self, index: I) -> &mut <[T] as Index>::Output { IndexMut::index_mut(self as &mut [T], index) } } diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index ebf5baa3c020b..746669a1b7128 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -280,7 +280,8 @@ pub macro PartialEq($item:item) { #[doc(alias = "!=")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Eq"] -pub trait Eq: PartialEq { +#[const_trait] +pub trait Eq: ~const PartialEq { // this method is used solely by #[deriving] to assert // that every component of a type implements #[deriving] // itself, the current deriving infrastructure means doing this @@ -601,8 +602,7 @@ impl Ordering { pub struct Reverse(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T); #[stable(feature = "reverse_cmp_key", since = "1.19.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] -impl const PartialOrd for Reverse { +impl PartialOrd for Reverse { #[inline] fn partial_cmp(&self, other: &Reverse) -> Option { other.0.partial_cmp(&self.0) @@ -761,7 +761,7 @@ impl Clone for Reverse { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Ord"] #[const_trait] -pub trait Ord: Eq + PartialOrd { +pub trait Ord: Eq + ~const PartialOrd { /// This method returns an [`Ordering`] between `self` and `other`. /// /// By convention, `self.cmp(&other)` returns the ordering matching the expression @@ -1051,7 +1051,7 @@ pub macro Ord($item:item) { )] #[const_trait] #[rustc_diagnostic_item = "PartialOrd"] -pub trait PartialOrd: PartialEq { +pub trait PartialOrd: ~const PartialEq { /// This method returns an ordering between `self` and `other` values if one exists. /// /// # Examples diff --git a/library/core/src/const_closure.rs b/library/core/src/const_closure.rs index 97900a4862f56..116cd00cde6de 100644 --- a/library/core/src/const_closure.rs +++ b/library/core/src/const_closure.rs @@ -61,7 +61,7 @@ macro_rules! impl_fn_mut_tuple { impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const FnMut for ConstFnMutClosure<($(&'a mut $var),*), Function> where - Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue, + Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue+ ~const Destruct, { extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output { #[allow(non_snake_case)] diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index c67867f4436e4..d702ea9edcf3a 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -171,7 +171,7 @@ impl const Deref for &mut T { #[doc(alias = "*")] #[stable(feature = "rust1", since = "1.0.0")] #[const_trait] -pub trait DerefMut: Deref { +pub trait DerefMut: ~const Deref { /// Mutably dereferences the value. #[stable(feature = "rust1", since = "1.0.0")] fn deref_mut(&mut self) -> &mut Self::Target; diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index b7e1aee9d84d1..94f96d7c21e5a 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -73,7 +73,7 @@ use crate::marker::Tuple; #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] #[const_trait] -pub trait Fn: FnMut { +pub trait Fn: ~const FnMut { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] extern "rust-call" fn call(&self, args: Args) -> Self::Output; @@ -160,7 +160,7 @@ pub trait Fn: FnMut { #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] #[const_trait] -pub trait FnMut: FnOnce { +pub trait FnMut: ~const FnOnce { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 84a69046807c4..46f6c06d655a7 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -362,7 +362,8 @@ where pub trait Residual { /// The "return" type of this meta-function. #[unstable(feature = "try_trait_v2_residual", issue = "91285")] - type TryType: ~const Try; + // const-hack: only ~const Try should be required + type TryType: ~const Try + Try; } #[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")] diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 3f8acc8505ff1..8c59da3abb09a 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -663,7 +663,11 @@ impl Pin

{ /// ruled out by the contract of `Pin::new_unchecked`. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn as_ref(&self) -> Pin<&P::Target> { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const fn as_ref(&self) -> Pin<&P::Target> + where + P: ~const Deref, + { // SAFETY: see documentation on this function unsafe { Pin::new_unchecked(&*self.pointer) } } @@ -720,7 +724,11 @@ impl Pin

{ /// ``` #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn as_mut(&mut self) -> Pin<&mut P::Target> { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const fn as_mut(&mut self) -> Pin<&mut P::Target> + where + P: ~const DerefMut, + { // SAFETY: see documentation on this function unsafe { Pin::new_unchecked(&mut *self.pointer) } } @@ -955,7 +963,8 @@ impl Pin<&'static mut T> { } #[stable(feature = "pin", since = "1.33.0")] -impl Deref for Pin

{ +#[rustc_const_unstable(feature = "const_pin", issue = "76654")] +impl const Deref for Pin

{ type Target = P::Target; fn deref(&self) -> &P::Target { Pin::get_ref(Pin::as_ref(self)) @@ -963,7 +972,8 @@ impl Deref for Pin

{ } #[stable(feature = "pin", since = "1.33.0")] -impl> DerefMut for Pin

{ +#[rustc_const_unstable(feature = "const_pin", issue = "76654")] +impl> const DerefMut for Pin

{ fn deref_mut(&mut self) -> &mut P::Target { Pin::get_mut(Pin::as_mut(self)) } diff --git a/src/test/ui/const-generics/const_trait_fn-issue-88433.rs b/src/test/ui/const-generics/const_trait_fn-issue-88433.rs index 6e04cfaec31fb..8e0da8b843b2c 100644 --- a/src/test/ui/const-generics/const_trait_fn-issue-88433.rs +++ b/src/test/ui/const-generics/const_trait_fn-issue-88433.rs @@ -1,6 +1,7 @@ // build-pass #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait Func { diff --git a/src/test/ui/const-generics/issues/issue-98629.rs b/src/test/ui/const-generics/issues/issue-98629.rs index 1d2d3012a6ee1..6e9fec23c514f 100644 --- a/src/test/ui/const-generics/issues/issue-98629.rs +++ b/src/test/ui/const-generics/issues/issue-98629.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait Trait { diff --git a/src/test/ui/const-generics/issues/issue-98629.stderr b/src/test/ui/const-generics/issues/issue-98629.stderr index 4a248be76a9e8..f440e4519f574 100644 --- a/src/test/ui/const-generics/issues/issue-98629.stderr +++ b/src/test/ui/const-generics/issues/issue-98629.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `N` - --> $DIR/issue-98629.rs:8:1 + --> $DIR/issue-98629.rs:9:1 | LL | const N: usize; | -------------- `N` from trait diff --git a/src/test/ui/consts/const-call.rs b/src/test/ui/consts/const-call.rs index 28e89559fe538..cfde6a9f96053 100644 --- a/src/test/ui/consts/const-call.rs +++ b/src/test/ui/consts/const-call.rs @@ -1,8 +1,10 @@ +#![feature(effects)] + fn f(x: usize) -> usize { x } fn main() { let _ = [0; f(2)]; - //~^ ERROR cannot call non-const fn + //~^ ERROR cannot call non-const fn `f` in constant expressions } diff --git a/src/test/ui/consts/const-call.stderr b/src/test/ui/consts/const-call.stderr index e46bcad0e1d0e..2905692d51770 100644 --- a/src/test/ui/consts/const-call.stderr +++ b/src/test/ui/consts/const-call.stderr @@ -1,11 +1,8 @@ -error[E0015]: cannot call non-const fn `f` in constants - --> $DIR/const-call.rs:6:17 +error: cannot call non-const fn `f` in constant expressions + --> $DIR/const-call.rs:8:17 | LL | let _ = [0; f(2)]; | ^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to previous error -For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-tuple-struct.rs b/src/test/ui/consts/const-tuple-struct.rs index 0144afaaceb34..7eaea67eca2f8 100644 --- a/src/test/ui/consts/const-tuple-struct.rs +++ b/src/test/ui/consts/const-tuple-struct.rs @@ -1,5 +1,7 @@ // run-pass +#![feature(effects)] + struct Bar(isize, isize); static X: Bar = Bar(1, 2); diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs index 1f68de8eed09b..f8f4235e01958 100644 --- a/src/test/ui/consts/const_let_assign3.rs +++ b/src/test/ui/consts/const_let_assign3.rs @@ -1,3 +1,5 @@ +#![feature(effects)] + struct S { state: u32, } diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index b550ac54573f0..51d6fd0f08b58 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -1,5 +1,5 @@ error[E0658]: mutable references are not allowed in constant functions - --> $DIR/const_let_assign3.rs:6:18 + --> $DIR/const_let_assign3.rs:8:18 | LL | const fn foo(&mut self, x: u32) { | ^^^^^^^^^ @@ -8,7 +8,7 @@ LL | const fn foo(&mut self, x: u32) { = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0658]: mutable references are not allowed in constants - --> $DIR/const_let_assign3.rs:14:5 + --> $DIR/const_let_assign3.rs:16:5 | LL | s.foo(3); | ^^^^^^^^ @@ -17,7 +17,7 @@ LL | s.foo(3); = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0658]: mutable references are not allowed in constants - --> $DIR/const_let_assign3.rs:20:13 + --> $DIR/const_let_assign3.rs:22:13 | LL | let y = &mut x; | ^^^^^^ diff --git a/src/test/ui/consts/const_method_call.rs b/src/test/ui/consts/const_method_call.rs new file mode 100644 index 0000000000000..f29f928fd289e --- /dev/null +++ b/src/test/ui/consts/const_method_call.rs @@ -0,0 +1,14 @@ +#![feature(effects)] + +// check-pass +// compile-flags: --crate-type lib + +pub struct ManuallyDrop { + value: T, +} + +impl ManuallyDrop { + pub const fn new(value: T) -> ManuallyDrop { + ManuallyDrop { value } + } +} diff --git a/src/test/ui/consts/issue-25826.stderr b/src/test/ui/consts/issue-25826.stderr index 905c5ee6eb4a0..d9487f720bed0 100644 --- a/src/test/ui/consts/issue-25826.stderr +++ b/src/test/ui/consts/issue-25826.stderr @@ -1,11 +1,11 @@ -error[E0277]: can't compare `*const ()` with `*const ()` in const contexts +error[E0277]: can't compare `*const ()` with `_` in const contexts --> $DIR/issue-25826.rs:3:52 | LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; - | ^ no implementation for `*const () < *const ()` and `*const () > *const ()` + | ^ no implementation for `*const () < _` and `*const () > _` | - = help: the trait `~const PartialOrd` is not implemented for `*const ()` -note: the trait `PartialOrd` is implemented for `*const ()`, but that implementation is not `const` + = help: the trait `~const PartialOrd<_>` is not implemented for `*const ()` +note: the trait `PartialOrd<_>` is implemented for `*const ()`, but that implementation is not `const` --> $DIR/issue-25826.rs:3:52 | LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs index a6e1788bb7f07..76e81ebdb3eda 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs @@ -1,3 +1,5 @@ +#![feature(effects)] + const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } //~^ dereferencing raw mutable pointers in constant functions diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr index 820b6433f36c5..2586adee74db5 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr @@ -1,5 +1,5 @@ error[E0658]: dereferencing raw mutable pointers in constant functions is unstable - --> $DIR/min_const_fn_unsafe_bad.rs:1:77 + --> $DIR/min_const_fn_unsafe_bad.rs:3:77 | LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } | ^^^ @@ -8,7 +8,7 @@ LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0658]: dereferencing raw mutable pointers in constant functions is unstable - --> $DIR/min_const_fn_unsafe_bad.rs:4:70 + --> $DIR/min_const_fn_unsafe_bad.rs:6:70 | LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } | ^^ @@ -17,7 +17,7 @@ LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0658]: dereferencing raw mutable pointers in constant functions is unstable - --> $DIR/min_const_fn_unsafe_bad.rs:7:83 + --> $DIR/min_const_fn_unsafe_bad.rs:9:83 | LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } | ^^^ diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.rs b/src/test/ui/consts/miri_unleashed/non_const_fn.rs index 44ab60dcabca6..84646afb0f1a3 100644 --- a/src/test/ui/consts/miri_unleashed/non_const_fn.rs +++ b/src/test/ui/consts/miri_unleashed/non_const_fn.rs @@ -1,5 +1,7 @@ // compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(effects)] + // A test demonstrating that we prevent calling non-const fn during CTFE. fn foo() {} diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr index 57836f7966df2..3e9658ad88ec0 100644 --- a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr +++ b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr @@ -1,5 +1,5 @@ error[E0080]: could not evaluate static initializer - --> $DIR/non_const_fn.rs:7:16 + --> $DIR/non_const_fn.rs:9:16 | LL | static C: () = foo(); | ^^^^^ calling non-const function `foo` @@ -7,7 +7,7 @@ LL | static C: () = foo(); warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/non_const_fn.rs:7:16 + --> $DIR/non_const_fn.rs:9:16 | LL | static C: () = foo(); | ^^^^^ diff --git a/src/test/ui/consts/operator_traits.rs b/src/test/ui/consts/operator_traits.rs new file mode 100644 index 0000000000000..6edb998d64eaf --- /dev/null +++ b/src/test/ui/consts/operator_traits.rs @@ -0,0 +1,493 @@ +#![crate_type = "lib"] +#![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs)] +#![feature(fundamental)] +#![feature(const_trait_impl, effects, const_mut_refs)] +#![no_std] +#![no_core] + +// check-pass + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[lang = "add"] +#[const_trait] +trait Add { + type Output; + + fn add(self, rhs: Rhs) -> Self::Output; +} + +impl const Add for i32 { + type Output = i32; + fn add(self, rhs: i32) -> i32 { + loop {} + } +} + +fn foo() { + let x = 42_i32 + 43_i32; +} + +const fn bar() { + let x = 42_i32 + 43_i32; +} + + +#[lang = "Try"] +#[const_trait] +trait Try: ~const FromResidual { + type Output; + type Residual; + + #[lang = "from_output"] + fn from_output(output: Self::Output) -> Self; + + #[lang = "branch"] + fn branch(self) -> ControlFlow; +} + +#[const_trait] +trait FromResidual::Residual> { + #[lang = "from_residual"] + fn from_residual(residual: R) -> Self; +} + +enum ControlFlow { + #[lang = "Continue"] + Continue(C), + #[lang = "Break"] + Break(B), +} + +#[const_trait] +#[lang = "fn"] +#[rustc_paren_sugar] +trait Fn: ~const FnMut { + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + +#[const_trait] +#[lang = "fn_mut"] +#[rustc_paren_sugar] +trait FnMut: ~const FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[const_trait] +#[lang = "fn_once"] +#[rustc_paren_sugar] +trait FnOnce { + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +struct ConstFnMutClosure { + data: CapturedData, + func: Function, +} + +#[lang = "tuple_trait"] +pub trait Tuple {} + +macro_rules! impl_fn_mut_tuple { + ($($var:ident)*) => { + impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const + FnOnce for ConstFnMutClosure<($(&'a mut $var),*), Function> + where + Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue, + Function: ~const Destruct, + { + type Output = ClosureReturnValue; + + extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output { + self.call_mut(args) + } + } + impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const + FnMut for ConstFnMutClosure<($(&'a mut $var),*), Function> + where + Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue, + Function: ~const Destruct, + { + extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output { + #[allow(non_snake_case)] + let ($($var),*) = &mut self.data; + (self.func)(($($var),*), args) + } + } + }; +} +impl_fn_mut_tuple!(A); +//impl_fn_mut_tuple!(A B); +//impl_fn_mut_tuple!(A B C); +//impl_fn_mut_tuple!(A B C D); +//impl_fn_mut_tuple!(A B C D E); + +#[lang = "receiver"] +trait Receiver {} + +impl Receiver for &T {} + +impl Receiver for &mut T {} + +#[lang = "destruct"] +#[const_trait] +trait Destruct {} + +#[lang = "freeze"] +unsafe auto trait Freeze {} + +#[lang = "drop"] +#[const_trait] +trait Drop { + fn drop(&mut self); +} + +#[const_trait] +trait Residual { + type TryType: ~const Try + Try; +} + +const fn size_of() -> usize { + 42 +} + +impl Copy for u8 {} + +impl usize { + #[rustc_allow_incoherent_impl] + const fn repeat_u8(x: u8) -> usize { + usize::from_ne_bytes([x; size_of::()]) + } + #[rustc_allow_incoherent_impl] + const fn from_ne_bytes(bytes: [u8; size_of::()]) -> Self { + loop {} + } +} + +#[rustc_do_not_const_check] // hooked by const-eval +const fn panic_display() { + panic_fmt(); +} + +fn panic_fmt() {} + +#[lang = "index"] +#[const_trait] +trait Index { + type Output: ?Sized; + + fn index(&self, index: Idx) -> &Self::Output; +} + + +#[const_trait] +unsafe trait SliceIndex { + type Output: ?Sized; + fn index(self, slice: &T) -> &Self::Output; +} + +impl const Index for [T] +where + I: ~const SliceIndex<[T]>, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +impl const Index for [T; N] +where + [T]: ~const Index, +{ + type Output = <[T] as Index>::Output; + + #[inline] + // FIXME: make `Self::Output` act like `>::Output` + fn index(&self, index: I) -> &<[T] as Index>::Output { + Index::index(self as &[T], index) + } +} + +#[lang = "unsize"] +trait Unsize { +} + +#[lang = "coerce_unsized"] +trait CoerceUnsized { +} + +impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} + + +#[lang = "deref"] +#[const_trait] +trait Deref { + #[lang = "deref_target"] + type Target: ?Sized; + + fn deref(&self) -> &Self::Target; +} + + +impl const Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + *self + } +} + +impl const Deref for &mut T { + type Target = T; + + fn deref(&self) -> &T { + *self + } +} + +enum Option { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), +} + +impl Option { + const fn as_ref(&self) -> Option<&T> { + match *self { + Some(ref x) => Some(x), + None => None, + } + } + + const fn as_mut(&mut self) -> Option<&mut T> { + match *self { + Some(ref mut x) => Some(x), + None => None, + } + } +} + +use Option::*; + +const fn as_deref(opt: &Option) -> Option<&T::Target> +where + T: ~const Deref, +{ + match opt { + Option::Some(t) => Option::Some(t.deref()), + Option::None => Option::None, + } +} + +#[const_trait] +trait Into: Sized { + fn into(self) -> T; +} + +#[const_trait] +trait From: Sized { + #[lang = "from"] + fn from(value: T) -> Self; +} + +impl const Into for T +where + U: ~const From, +{ + fn into(self) -> U { + U::from(self) + } +} + +impl const From for T { + fn from(t: T) -> T { + t + } +} + +enum Result { + Ok(T), + Err(E), +} +use Result::*; + +fn from_str(s: &str) -> Result { + match s { + "true" => Ok(true), + "false" => Ok(false), + _ => Err(()), + } +} + +#[lang = "eq"] +#[const_trait] +trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } +} + +impl PartialEq for str { + fn eq(&self, other: &str) -> bool { + loop {} + } +} + + +#[lang = "not"] +#[const_trait] +trait Not { + type Output; + fn not(self) -> Self::Output; +} + +impl const Not for bool { + type Output = bool; + fn not(self) -> bool { + !self + } +} + +impl Copy for bool {} +impl<'a> Copy for &'a str {} + +#[lang = "pin"] +#[fundamental] +#[repr(transparent)] +struct Pin

{ + pointer: P, +} + +impl

Pin

{ + #[lang = "new_unchecked"] + const unsafe fn new_unchecked(pointer: P) -> Pin

{ + Pin { pointer } + } +} + +impl<'a, T: ?Sized> Pin<&'a T> { + const fn get_ref(self) -> &'a T { + self.pointer + } +} + +impl Pin

{ + const fn as_ref(&self) -> Pin<&P::Target> + where + P: ~const Deref, + { + unsafe { Pin::new_unchecked(&*self.pointer) } + } +} + +impl<'a, T: ?Sized> Pin<&'a mut T> { + const unsafe fn get_unchecked_mut(self) -> &'a mut T { + self.pointer + } +} + +impl Option { + const fn as_pin_ref(self: Pin<&Self>) -> Option> { + match Pin::get_ref(self).as_ref() { + Some(x) => unsafe { Some(Pin::new_unchecked(x)) }, + None => None, + } + } + + const fn as_pin_mut(self: Pin<&mut Self>) -> Option> { + unsafe { + match Pin::get_unchecked_mut(self).as_mut() { + Some(x) => Some(Pin::new_unchecked(x)), + None => None, + } + } + } +} + +impl const Deref for Pin

{ + type Target = P::Target; + fn deref(&self) -> &P::Target { + Pin::get_ref(Pin::as_ref(self)) + } +} + +impl const Deref for Option { + type Target = T; + fn deref(&self) -> &T { + loop {} + } +} + +impl Receiver for Pin

{} + +impl Clone for RefCell { + fn clone(&self) -> RefCell { + RefCell::new(self.borrow().clone()) + } +} + +struct RefCell { + borrow: UnsafeCell<()>, + value: UnsafeCell, +} +impl RefCell { + const fn new(value: T) -> RefCell { + loop {} + } +} +impl RefCell { + fn borrow(&self) -> Ref<'_, T> { + loop {} + } +} + +#[lang = "unsafe_cell"] +#[repr(transparent)] +struct UnsafeCell { + value: T, +} + +struct Ref<'b, T: ?Sized + 'b> { + value: *const T, + borrow: &'b UnsafeCell<()>, +} + +impl Deref for Ref<'_, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + loop {} + } +} + +#[lang = "clone"] +#[rustc_trivial_field_reads] +#[const_trait] +trait Clone: Sized { + fn clone(&self) -> Self; + fn clone_from(&mut self, source: &Self) + where + Self: ~const Destruct, + { + *self = source.clone() + } +} + +#[lang = "structural_peq"] +trait StructuralPartialEq {} + +#[lang = "structural_teq"] +trait StructuralEq {} + +const fn drop(_: T) {} diff --git a/src/test/ui/keyword_generics/const_trait.rs b/src/test/ui/keyword_generics/const_trait.rs new file mode 100644 index 0000000000000..4559cdd16f3d7 --- /dev/null +++ b/src/test/ui/keyword_generics/const_trait.rs @@ -0,0 +1,94 @@ +#![feature(const_trait_impl)] +#![feature(effects)] +#![feature(inline_const)] + +#[const_trait] +trait Foo { + type AssocTy; + fn bar(); +} + +struct A; +impl Foo for A { + type AssocTy = (); + fn bar() { + println!(""); + } +} + +struct B; +impl const Foo for B { + type AssocTy = i32; + fn bar() {} +} + +const C: ::AssocTy = (); +const D: ::AssocTy = 42; + +const FOO: () = { + A::bar(); //~ ERROR: cannot call + B::bar(); + foo(); + moo::(); + moo::(); + boo::(); //~ ERROR: cannot call + boo::(); +}; + +static BAR: () = { + A::bar(); //~ ERROR: cannot call + B::bar(); + foo(); + moo::(); + moo::(); + boo::(); //~ ERROR: cannot call + boo::(); +}; + +const fn foo() { + A::bar(); //~ ERROR: cannot call + B::bar(); + moo::(); + moo::(); + boo::(); //~ ERROR: cannot call + boo::(); +} + +const fn moo() { + T::bar(); //~ ERROR: cannot call +} + +const fn boo() { + T::bar(); +} + +fn main() { + A::bar(); + B::bar(); + foo(); + moo::(); + moo::(); + boo::(); + boo::(); + + const { + A::bar(); //~ ERROR: cannot call + B::bar(); + foo(); + moo::(); + moo::(); + boo::(); //~ ERROR: cannot call + boo::(); + }; + + [(); { + A::bar(); //~ ERROR: cannot call + B::bar(); + foo(); + moo::(); + moo::(); + boo::(); //~ ERROR: cannot call + boo::(); + 0 + }]; +} diff --git a/src/test/ui/keyword_generics/const_trait.stderr b/src/test/ui/keyword_generics/const_trait.stderr new file mode 100644 index 0000000000000..cf3bfd2d24c19 --- /dev/null +++ b/src/test/ui/keyword_generics/const_trait.stderr @@ -0,0 +1,120 @@ +error: cannot call `::bar` because it is not `const` + --> $DIR/const_trait.rs:29:5 + | +LL | const FOO: () = { + | --- required because of this +LL | A::bar(); + | ^^^^^^^^ + +error: cannot call `boo::` because it is not `const` + --> $DIR/const_trait.rs:34:5 + | +LL | const FOO: () = { + | --- required because of this +... +LL | boo::(); + | ^^^^^^^^^^ + +error: cannot call `::bar` because it is not `const` + --> $DIR/const_trait.rs:39:5 + | +LL | static BAR: () = { + | --- required because of this +LL | A::bar(); + | ^^^^^^^^ + +error: cannot call `boo::` because it is not `const` + --> $DIR/const_trait.rs:44:5 + | +LL | static BAR: () = { + | --- required because of this +... +LL | boo::(); + | ^^^^^^^^^^ + +error: cannot call `::bar` because it is not `const` + --> $DIR/const_trait.rs:49:5 + | +LL | const fn foo() { + | --- required because of this +LL | A::bar(); + | ^^^^^^^^ + +error: cannot call `boo::` because it is not `const` + --> $DIR/const_trait.rs:53:5 + | +LL | const fn foo() { + | --- required because of this +... +LL | boo::(); + | ^^^^^^^^^^ + +error: cannot call `::bar` because it is not `const` + --> $DIR/const_trait.rs:58:5 + | +LL | const fn moo() { + | --- required because of this +LL | T::bar(); + | ^^^^^^^^ + +error: cannot call `::bar` because it is not `const` + --> $DIR/const_trait.rs:75:9 + | +LL | const { + | ___________- +LL | | A::bar(); + | | ^^^^^^^^ +LL | | B::bar(); +LL | | foo(); +... | +LL | | boo::(); +LL | | }; + | |_____- required because of this + +error: cannot call `boo::` because it is not `const` + --> $DIR/const_trait.rs:80:9 + | +LL | const { + | ___________- +LL | | A::bar(); +LL | | B::bar(); +LL | | foo(); +... | +LL | | boo::(); + | | ^^^^^^^^^^ +LL | | boo::(); +LL | | }; + | |_____- required because of this + +error: cannot call `::bar` because it is not `const` + --> $DIR/const_trait.rs:85:9 + | +LL | [(); { + | __________- +LL | | A::bar(); + | | ^^^^^^^^ +LL | | B::bar(); +LL | | foo(); +... | +LL | | 0 +LL | | }]; + | |_____- required because of this + +error: cannot call `boo::` because it is not `const` + --> $DIR/const_trait.rs:90:9 + | +LL | [(); { + | __________- +LL | | A::bar(); +LL | | B::bar(); +LL | | foo(); +... | +LL | | boo::(); + | | ^^^^^^^^^^ +LL | | boo::(); +LL | | 0 +LL | | }]; + | |_____- required because of this + +error: aborting due to 11 previous errors + diff --git a/src/test/ui/keyword_generics/effects_are_not_user_visible_generic_params.rs b/src/test/ui/keyword_generics/effects_are_not_user_visible_generic_params.rs new file mode 100644 index 0000000000000..3d1c14b6809d7 --- /dev/null +++ b/src/test/ui/keyword_generics/effects_are_not_user_visible_generic_params.rs @@ -0,0 +1,18 @@ +#![feature(const_trait_impl)] +#![feature(effects)] +#![feature(inline_const)] + +#[const_trait] +trait Foo { + fn bar(&self); +} + +fn foo>() {} +//~^ ERROR this trait takes 0 generic arguments but 1 generic argument was supplied + +fn bar(x: &dyn Foo) { + x.bar(); +} + +fn main() { +} diff --git a/src/test/ui/keyword_generics/effects_are_not_user_visible_generic_params.stderr b/src/test/ui/keyword_generics/effects_are_not_user_visible_generic_params.stderr new file mode 100644 index 0000000000000..d23cb75673ffc --- /dev/null +++ b/src/test/ui/keyword_generics/effects_are_not_user_visible_generic_params.stderr @@ -0,0 +1,17 @@ +error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/effects_are_not_user_visible_generic_params.rs:10:11 + | +LL | fn foo>() {} + | ^^^---- help: remove these generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/effects_are_not_user_visible_generic_params.rs:6:7 + | +LL | trait Foo { + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/keyword_generics/feature-gate-effects.rs b/src/test/ui/keyword_generics/feature-gate-effects.rs new file mode 100644 index 0000000000000..b038489cdf7fa --- /dev/null +++ b/src/test/ui/keyword_generics/feature-gate-effects.rs @@ -0,0 +1,7 @@ +// This is a fake feature gate test. There is currently no way +// to fail a test only with the feature gate missing. +// FIXME(effects): make this an actual test once effects enable more code to compile + +fn main() { + "just fail this test" //~ ERROR mismatched types +} diff --git a/src/test/ui/keyword_generics/feature-gate-effects.stderr b/src/test/ui/keyword_generics/feature-gate-effects.stderr new file mode 100644 index 0000000000000..6f735d57d6e98 --- /dev/null +++ b/src/test/ui/keyword_generics/feature-gate-effects.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/feature-gate-effects.rs:6:5 + | +LL | fn main() { + | - expected `()` because of default return type +LL | "just fail this test" + | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `&str` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/keyword_generics/other_const_fn.rs b/src/test/ui/keyword_generics/other_const_fn.rs new file mode 100644 index 0000000000000..429ed19efdcb4 --- /dev/null +++ b/src/test/ui/keyword_generics/other_const_fn.rs @@ -0,0 +1,13 @@ +#![feature(effects)] + +// check-pass + +fn main() {} + +const fn f() { + g(); + let x = g; + x(); +} + +const fn g() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs b/src/test/ui/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs index 780a510c500dc..542748baa444a 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs @@ -1,5 +1,6 @@ +#![feature(const_trait_impl, effects)] + // check-pass -#![feature(const_trait_impl)] #[const_trait] trait Foo { diff --git a/src/test/ui/rfc-2632-const-trait-impl/attr-misuse.rs b/src/test/ui/rfc-2632-const-trait-impl/attr-misuse.rs index 01ac74feff74d..ba79f1383f723 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/attr-misuse.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/attr-misuse.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait A { diff --git a/src/test/ui/rfc-2632-const-trait-impl/attr-misuse.stderr b/src/test/ui/rfc-2632-const-trait-impl/attr-misuse.stderr index b18f33218c2db..9d5df2a34a9e4 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/attr-misuse.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/attr-misuse.stderr @@ -1,11 +1,11 @@ error: attribute should be applied to a trait - --> $DIR/attr-misuse.rs:9:1 + --> $DIR/attr-misuse.rs:10:1 | LL | #[const_trait] | ^^^^^^^^^^^^^^ error: attribute should be applied to a trait - --> $DIR/attr-misuse.rs:5:5 + --> $DIR/attr-misuse.rs:6:5 | LL | #[const_trait] | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs b/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs index e73082c11276f..f40dc27cb4c6f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] #[const_trait] pub trait MyTrait { diff --git a/src/test/ui/rfc-2632-const-trait-impl/auxiliary/staged-api.rs b/src/test/ui/rfc-2632-const-trait-impl/auxiliary/staged-api.rs index 589e3f02420f7..687cb128b05be 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/auxiliary/staged-api.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/auxiliary/staged-api.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] #![feature(staged_api)] #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs index dd99339742072..1ea93f01202c8 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] pub trait Plus { diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr index 7350909ba8e19..ef7e1f57ec167 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr @@ -1,14 +1,10 @@ -error[E0277]: the trait bound `u32: ~const Plus` is not satisfied - --> $DIR/call-const-trait-method-fail.rs:25:7 +error[E0277]: the trait bound `u32: Plus` is not satisfied + --> $DIR/call-const-trait-method-fail.rs:26:7 | LL | a.plus(b) - | ^^^^ the trait `~const Plus` is not implemented for `u32` + | ^^^^ the trait `Plus` is not implemented for `u32` | -note: the trait `Plus` is implemented for `u32`, but that implementation is not `const` - --> $DIR/call-const-trait-method-fail.rs:25:7 - | -LL | a.plus(b) - | ^^^^ + = help: the trait `Plus` is implemented for `u32` error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs index e197c8b73c535..a14b1fe6094b6 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs @@ -1,5 +1,7 @@ // check-pass +#![feature(effects)] + struct S; impl PartialEq for S { diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs index 414a8c87d2c41..cb6a401196abf 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] struct S; diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr index 706f52343659e..35db42f1ae047 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr @@ -6,11 +6,7 @@ LL | pub const EQ: bool = equals_self(&S); | | | required by a bound introduced by this call | -note: the trait `Foo` is implemented for `S`, but that implementation is not `const` - --> $DIR/call-generic-method-nonconst.rs:23:34 - | -LL | pub const EQ: bool = equals_self(&S); - | ^^ + = help: the trait `Foo` is implemented for `S` note: required by a bound in `equals_self` --> $DIR/call-generic-method-nonconst.rs:16:25 | diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs index 140a06a73ac6d..5175a78aa856d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait ConstDefaultFn: Sized { diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr index f9d0d1f7875fb..86e2a61d658b4 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr @@ -1,14 +1,10 @@ -error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied - --> $DIR/const-default-method-bodies.rs:24:18 +error[E0277]: the trait bound `NonConstImpl: ConstDefaultFn` is not satisfied + --> $DIR/const-default-method-bodies.rs:25:18 | LL | NonConstImpl.a(); - | ^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl` + | ^ the trait `ConstDefaultFn` is not implemented for `NonConstImpl` | -note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const` - --> $DIR/const-default-method-bodies.rs:24:5 - | -LL | NonConstImpl.a(); - | ^^^^^^^^^^^^ + = help: the trait `ConstDefaultFn` is implemented for `NonConstImpl` error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs index bed4e9fd1e610..836e152d1b99f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(effects)] struct Foo; diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr index 603f6b7d2835e..612511a479956 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-norecover.stderr @@ -1,5 +1,5 @@ error: expected identifier, found keyword `impl` - --> $DIR/const-impl-norecover.rs:5:7 + --> $DIR/const-impl-norecover.rs:6:7 | LL | const impl Foo { | ^^^^ expected identifier, found keyword diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs index 837124db04e20..a8cc7d8e00eab 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait Foo {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr index 7217fc8554356..2d3cbcaac23c3 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-recovery.stderr @@ -1,5 +1,5 @@ error: expected identifier, found keyword `impl` - --> $DIR/const-impl-recovery.rs:6:7 + --> $DIR/const-impl-recovery.rs:7:7 | LL | const impl Foo for i32 {} | ^^^^ expected identifier, found keyword @@ -11,7 +11,7 @@ LL + impl const Foo for i32 {} | error: expected identifier, found keyword `impl` - --> $DIR/const-impl-recovery.rs:11:7 + --> $DIR/const-impl-recovery.rs:12:7 | LL | const impl Bar for T {} | ^^^^ expected identifier, found keyword diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs index 2b4963991dbef..d5ca0079a4bc8 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs @@ -1,7 +1,7 @@ #![feature(const_trait_impl)] +#![feature(effects)] pub trait A {} -//~^ HELP: mark `A` as const impl const A for () {} //~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]` diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr index 478adcf3e9e89..e98880f4ed3d1 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr @@ -3,7 +3,7 @@ error: const `impl` for trait `A` which is not marked with `#[const_trait]` | LL | pub trait A {} | - help: mark `A` as const: `#[const_trait]` -... +LL | LL | impl const A for () {} | ^ | diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs b/src/test/ui/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs index bde8bf20f46c5..00d7574b244d1 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs @@ -4,6 +4,7 @@ // check-pass #![feature(const_trait_impl)] +#![feature(effects)] // aux-build: cross-crate.rs extern crate cross_crate; diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr index 633b7cc255a52..9f94f63c9d4bb 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr @@ -1,14 +1,10 @@ -error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied +error[E0277]: the trait bound `cross_crate::NonConst: cross_crate::MyTrait` is not satisfied --> $DIR/cross-crate.rs:17:14 | LL | NonConst.func(); - | ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` + | ^^^^ the trait `cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` | -note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const` - --> $DIR/cross-crate.rs:17:5 - | -LL | NonConst.func(); - | ^^^^^^^^ + = help: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst` error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs index 6df47022cc948..bdd336f887909 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs @@ -1,6 +1,6 @@ // revisions: stock gated stocknc gatednc // [gated] check-pass -#![cfg_attr(any(gated, gatednc), feature(const_trait_impl))] +#![cfg_attr(any(gated, gatednc), feature(const_trait_impl, effects))] // aux-build: cross-crate.rs extern crate cross_crate; diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs index 96acdc300e0dd..92c84002ccccc 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] #[const_trait] trait Tr {} @@ -10,7 +10,7 @@ const fn foo() where T: ~const Tr {} pub trait Foo { fn foo() { foo::<()>(); - //~^ ERROR the trait bound `(): ~const Tr` is not satisfied + //~^ ERROR cannot call } } diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr index a244ab10cab6b..3a6a397dde0ee 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr @@ -1,20 +1,10 @@ -error[E0277]: the trait bound `(): ~const Tr` is not satisfied - --> $DIR/default-method-body-is-const-body-checking.rs:12:15 +error: cannot call `foo::<()>` because it is not `const` + --> $DIR/default-method-body-is-const-body-checking.rs:12:9 | +LL | fn foo() { + | --- required because of this LL | foo::<()>(); - | ^^ the trait `~const Tr` is not implemented for `()` - | -note: the trait `Tr` is implemented for `()`, but that implementation is not `const` - --> $DIR/default-method-body-is-const-body-checking.rs:12:15 - | -LL | foo::<()>(); - | ^^ -note: required by a bound in `foo` - --> $DIR/default-method-body-is-const-body-checking.rs:7:28 - | -LL | const fn foo() where T: ~const Tr {} - | ^^^^^^^^^ required by this bound in `foo` + | ^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs index f70ecbc3746f9..9feed122552b2 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] pub trait Tr { diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr index 21ecddaffbb65..81379590179f9 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr @@ -1,14 +1,10 @@ -error[E0277]: the trait bound `(): ~const Tr` is not satisfied - --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12 +error[E0277]: the trait bound `(): Tr` is not satisfied + --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12 | LL | ().a() - | ^ the trait `~const Tr` is not implemented for `()` + | ^ the trait `Tr` is not implemented for `()` | -note: the trait `Tr` is implemented for `()`, but that implementation is not `const` - --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:9 - | -LL | ().a() - | ^^ + = help: the trait `Tr` is implemented for `()` error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs index 1b45cd9aab9da..577a6f6bbbc81 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs @@ -7,6 +7,7 @@ #![feature(staged_api)] #![feature(const_trait_impl)] +#![feature(effects)] #![stable(since = "1", feature = "foo")] #[const_trait] diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs index 05b26465c5b0c..cce7d4968eb8f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(effects)] struct S; trait T {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr index 0a91719e1f15b..f4e1aa3ba00c4 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr @@ -1,5 +1,5 @@ error: expected a trait, found type - --> $DIR/impl-tilde-const-trait.rs:6:6 + --> $DIR/impl-tilde-const-trait.rs:7:6 | LL | impl ~const T for S {} | ^^^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs index 6df9696f2cbd7..0d9082325206b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait Tr { diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr index 6c6ca9f5db820..c4aa0b6028d5b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `req` - --> $DIR/impl-with-default-fn-fail.rs:12:1 + --> $DIR/impl-with-default-fn-fail.rs:13:1 | LL | fn req(&self); | -------------- `req` from trait diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs index ae81421e9e191..38a7fd725bde8 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs @@ -1,6 +1,7 @@ // check-pass #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait Tr { diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs index afd0d137bb4aa..d8746c5708341 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs @@ -1,13 +1,16 @@ #![feature(const_trait_impl)] #![allow(bare_trait_objects)] +#![feature(effects)] struct S; trait T {} impl const S {} //~^ ERROR inherent impls cannot be `const` +//~| ERROR `host` is not constrained impl const T {} //~^ ERROR inherent impls cannot be `const` +//~| ERROR `host` is not constrained fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr index 8c55627031d1e..5e77d67024226 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr @@ -1,5 +1,5 @@ error: inherent impls cannot be `const` - --> $DIR/inherent-impl.rs:7:12 + --> $DIR/inherent-impl.rs:8:12 | LL | impl const S {} | ----- ^ inherent impl for this type @@ -9,7 +9,7 @@ LL | impl const S {} = note: only trait implementations may be annotated with `const` error: inherent impls cannot be `const` - --> $DIR/inherent-impl.rs:10:12 + --> $DIR/inherent-impl.rs:12:12 | LL | impl const T {} | ----- ^ inherent impl for this type @@ -18,5 +18,18 @@ LL | impl const T {} | = note: only trait implementations may be annotated with `const` -error: aborting due to 2 previous errors +error[E0207]: the effect parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/inherent-impl.rs:8:1 + | +LL | impl const S {} + | ^^^^^^^^^^^^ unconstrained effect parameter + +error[E0207]: the effect parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/inherent-impl.rs:12:1 + | +LL | impl const T {} + | ^^^^^^^^^^^^ unconstrained effect parameter + +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/intrinsics.rs b/src/test/ui/rfc-2632-const-trait-impl/intrinsics.rs new file mode 100644 index 0000000000000..dff6392e202bb --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/intrinsics.rs @@ -0,0 +1,10 @@ +#![feature(effects)] +#![feature(core_intrinsics)] + +// check-pass + +const fn foo() -> usize { + std::intrinsics::size_of::() +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs index 9f3f38ad4bc68..07de6f43802b8 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs @@ -1,19 +1,34 @@ // revisions: nn ny yn yy // check-pass #![feature(const_trait_impl, associated_type_defaults, const_mut_refs)] +#![feature(effects)] #[cfg_attr(any(yn, yy), const_trait)] pub trait Index { type Output; } -#[cfg_attr(any(ny, yy), const_trait)] -pub trait IndexMut where Self: Index { +#[cfg(yy)] +#[const_trait] +pub trait IndexMut: ~const Index { const C: ::Output; type Assoc = ::Output; fn foo(&mut self, x: ::Output) -> ::Output; } +#[cfg(not(yy))] +#[cfg_attr(ny, const_trait)] +pub trait IndexMut: Index { + const C: ::Output; + type Assoc = ::Output; + fn foo(&mut self, x: ::Output) -> ::Output; +} + +#[cfg(yy)] +// FIXME: once we have `` syntax, remove this impl +// and merge the `IndexMut` declarations to only use the one without a `~const Index` bound. +impl const Index for () { type Output = (); } +#[cfg(not(yy))] impl Index for () { type Output = (); } #[cfg(not(any(nn, yn)))] diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs index b132c395ac7b4..119a60593f2c0 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] pub trait A { fn assoc() -> bool; @@ -6,8 +6,7 @@ pub trait A { pub const fn foo() -> bool { T::assoc() - //~^ ERROR the trait bound - //~| ERROR cannot call non-const fn + //~^ ERROR cannot call non-const fn `::assoc` in functions } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr index 955923505200a..76a9adf55dbcd 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr @@ -1,24 +1,8 @@ -error[E0277]: the trait bound `T: ~const A` is not satisfied - --> $DIR/issue-88155.rs:8:5 - | -LL | T::assoc() - | ^^^^^^^^^^ the trait `~const A` is not implemented for `T` - | -note: the trait `A` is implemented for `T`, but that implementation is not `const` - --> $DIR/issue-88155.rs:8:5 - | -LL | T::assoc() - | ^^^^^^^^^^ - -error[E0015]: cannot call non-const fn `::assoc` in constant functions +error: cannot call non-const fn `::assoc` in functions --> $DIR/issue-88155.rs:8:5 | LL | T::assoc() | ^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0015, E0277. -For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.rs b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.rs index 633543700d2ec..3e8f760cf8010 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl, min_specialization, rustc_attrs)] +#![feature(effects)] #[rustc_specialization_trait] #[const_trait] @@ -17,7 +18,7 @@ impl A for T { } } -impl const A for T { +impl const A for T { //~ ERROR: conflicting impl fn a() -> u32 { 3 } @@ -25,7 +26,6 @@ impl const A for T { const fn generic() { ::a(); - //~^ ERROR: the trait bound `T: ~const Sup` is not satisfied } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.stderr index c554671e18d82..d592e48f52ebf 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/specializing-constness-2.stderr @@ -1,19 +1,12 @@ -error[E0277]: the trait bound `T: ~const Sup` is not satisfied - --> $DIR/specializing-constness-2.rs:27:5 - | -LL | ::a(); - | ^^^^^^^^^^^^^ the trait `~const Sup` is not implemented for `T` - | -note: required for `T` to implement `~const A` - --> $DIR/specializing-constness-2.rs:20:37 +error[E0119]: conflicting implementations of trait `A` + --> $DIR/specializing-constness-2.rs:21:1 | +LL | impl A for T { + | ------------------------ first implementation here +... LL | impl const A for T { - | ^ ^ -help: consider further restricting this bound - | -LL | const fn generic() { - | ++++++++++++ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/staged-api.rs b/src/test/ui/rfc-2632-const-trait-impl/staged-api.rs index 1d79f5adf93f3..b3977e6cede0f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/staged-api.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/staged-api.rs @@ -1,7 +1,7 @@ // revisions: stable unstable #![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file. -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] #![feature(staged_api)] #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs index d183efde2df1f..cea4db6883681 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] // revisions: yy yn ny nn @@ -13,7 +13,7 @@ trait Bar: ~const Foo {} const fn foo(x: &T) { x.a(); - //[yn,yy]~^ ERROR the trait bound + //[yn,yy]~^ ERROR cannot call } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr index 13fc719f28c5c..5563a52bd8156 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr @@ -1,19 +1,10 @@ -error[E0277]: the trait bound `T: ~const Foo` is not satisfied +error: cannot call `::a` because it is not `const` --> $DIR/super-traits-fail-2.rs:15:7 | +LL | const fn foo(x: &T) { + | --- required because of this LL | x.a(); - | ^ the trait `~const Foo` is not implemented for `T` - | -note: the trait `Foo` is implemented for `T`, but that implementation is not `const` - --> $DIR/super-traits-fail-2.rs:15:5 - | -LL | x.a(); - | ^ -help: consider further restricting this bound - | -LL | const fn foo(x: &T) { - | ++++++++++++ + | ^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr index 13fc719f28c5c..5563a52bd8156 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr @@ -1,19 +1,10 @@ -error[E0277]: the trait bound `T: ~const Foo` is not satisfied +error: cannot call `::a` because it is not `const` --> $DIR/super-traits-fail-2.rs:15:7 | +LL | const fn foo(x: &T) { + | --- required because of this LL | x.a(); - | ^ the trait `~const Foo` is not implemented for `T` - | -note: the trait `Foo` is implemented for `T`, but that implementation is not `const` - --> $DIR/super-traits-fail-2.rs:15:5 - | -LL | x.a(); - | ^ -help: consider further restricting this bound - | -LL | const fn foo(x: &T) { - | ++++++++++++ + | ^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs index 3e2b81368a5fe..b768432d9a5a3 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait Foo { diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr index 1f8f312df0128..d4fc275dcfebc 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr @@ -1,19 +1,10 @@ -error[E0277]: the trait bound `S: ~const Foo` is not satisfied - --> $DIR/super-traits-fail.rs:15:12 +error[E0277]: the trait bound `S: Foo` is not satisfied + --> $DIR/super-traits-fail.rs:16:12 | LL | impl const Bar for S {} - | ^^^ the trait `~const Foo` is not implemented for `S` + | ^^^ the trait `Foo` is not implemented for `S` | -note: the trait `Foo` is implemented for `S`, but that implementation is not `const` - --> $DIR/super-traits-fail.rs:15:12 - | -LL | impl const Bar for S {} - | ^^^ -note: required by a bound in `Bar` - --> $DIR/super-traits-fail.rs:8:12 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^^^^^ required by this bound in `Bar` + = help: the trait `Foo` is implemented for `S` error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs index df96f6fb4ab40..37d39ed0924a1 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs @@ -1,5 +1,6 @@ // check-pass #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait Foo { diff --git a/src/test/ui/rfc-2632-const-trait-impl/syntax.rs b/src/test/ui/rfc-2632-const-trait-impl/syntax.rs index 7ac2458e39928..a4e207a40077f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/syntax.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/syntax.rs @@ -3,6 +3,7 @@ #![feature(const_trait_bound_opt_out)] #![feature(const_trait_impl)] +#![feature(effects)] // For now, this parses since an error does not occur until AST lowering. impl ~const T {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs index 95f7aaba0fc38..8a1e0fbe4007b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs @@ -1,5 +1,6 @@ #![feature(const_trait_impl)] #![feature(associated_type_bounds)] +#![feature(effects)] struct TildeQuestion(std::marker::PhantomData); //~^ ERROR `~const` and `?` are mutually exclusive diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr index d20f146df3f1a..82cf81ce26e72 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr @@ -1,5 +1,5 @@ error: `~const` and `?` are mutually exclusive - --> $DIR/tilde-const-invalid-places.rs:4:25 + --> $DIR/tilde-const-invalid-places.rs:5:25 | LL | struct TildeQuestion(std::marker::PhantomData); | ^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-syntax.rs b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-syntax.rs index 9b3c2cf2a3b04..ecfacef3aac0b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-syntax.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-syntax.rs @@ -2,6 +2,7 @@ // check-pass #![feature(const_trait_impl)] +#![feature(effects)] struct S< T: ~const ?for<'a> Tr<'a> + 'static + ~const std::ops::Add, diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.rs b/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.rs index 06e4ede8b5e7e..fb8ffeaaed520 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.rs @@ -1,6 +1,7 @@ // compile-flags: -Z parse-only #![feature(const_trait_impl)] +#![feature(effects)] struct S; //~^ ERROR expected identifier, found `~` diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.stderr b/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.stderr index 928d23e8a424d..237732251f459 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.stderr @@ -1,5 +1,5 @@ error: expected identifier, found `~` - --> $DIR/tilde-twice.rs:5:20 + --> $DIR/tilde-twice.rs:6:20 | LL | struct S; | ^ expected identifier diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.rs index bfe98b98c7420..2c6d75c76a472 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.rs @@ -3,6 +3,7 @@ // (`rustc_const_eval` instead of `rustc_hir_analysis`) Therefore one file as a // test is not enough. #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait Bar {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.stderr index f2846b6a66262..d274904be6b4d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-const.stderr @@ -1,34 +1,34 @@ -error[E0277]: the trait bound `T: ~const Bar` is not satisfied - --> $DIR/trait-where-clause-const.rs:19:5 +error[E0277]: the trait bound `T: Bar` is not satisfied + --> $DIR/trait-where-clause-const.rs:20:5 | LL | T::b(); - | ^^^^^^ the trait `~const Bar` is not implemented for `T` + | ^^^^ the trait `Bar` is not implemented for `T` | -note: the trait `Bar` is implemented for `T`, but that implementation is not `const` - --> $DIR/trait-where-clause-const.rs:19:5 +note: required by a bound in `Foo::b` + --> $DIR/trait-where-clause-const.rs:14:24 | -LL | T::b(); - | ^^^^^^ +LL | fn b() where Self: ~const Bar; + | ^^^^^^^^^^ required by this bound in `Foo::b` help: consider further restricting this bound | -LL | const fn test1() { - | ++++++++++++ +LL | const fn test1() { + | +++++ -error[E0277]: the trait bound `T: ~const Bar` is not satisfied - --> $DIR/trait-where-clause-const.rs:21:5 +error[E0277]: the trait bound `T: Bar` is not satisfied + --> $DIR/trait-where-clause-const.rs:22:12 | LL | T::c::(); - | ^^^^^^^^^^^ the trait `~const Bar` is not implemented for `T` + | ^ the trait `Bar` is not implemented for `T` | -note: the trait `Bar` is implemented for `T`, but that implementation is not `const` - --> $DIR/trait-where-clause-const.rs:21:5 +note: required by a bound in `Foo::c` + --> $DIR/trait-where-clause-const.rs:15:13 | -LL | T::c::(); - | ^^^^^^^^^^^ +LL | fn c(); + | ^^^^^^^^^^ required by this bound in `Foo::c` help: consider further restricting this bound | -LL | const fn test1() { - | ++++++++++++ +LL | const fn test1() { + | +++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs index 4b8b004069d47..f3ade24e1d36f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs @@ -1,6 +1,7 @@ // run-pass #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait Bar { diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs index 3b028ac48db4b..350d114c2a7c4 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs @@ -1,6 +1,7 @@ // check-pass #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait Foo { diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs index 85ca5fc904877..34accff732e09 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(effects)] #[const_trait] trait Bar {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr index 11f0c40160d89..e52e954db0069 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: Bar` is not satisfied - --> $DIR/trait-where-clause.rs:14:5 + --> $DIR/trait-where-clause.rs:15:5 | LL | T::b(); | ^^^^ the trait `Bar` is not implemented for `T` | note: required by a bound in `Foo::b` - --> $DIR/trait-where-clause.rs:8:24 + --> $DIR/trait-where-clause.rs:9:24 | LL | fn b() where Self: ~const Bar; | ^^^^^^^^^^ required by this bound in `Foo::b` @@ -15,13 +15,13 @@ LL | fn test1() { | +++++ error[E0277]: the trait bound `T: Bar` is not satisfied - --> $DIR/trait-where-clause.rs:16:12 + --> $DIR/trait-where-clause.rs:17:12 | LL | T::c::(); | ^ the trait `Bar` is not implemented for `T` | note: required by a bound in `Foo::c` - --> $DIR/trait-where-clause.rs:9:13 + --> $DIR/trait-where-clause.rs:10:13 | LL | fn c(); | ^^^^^^^^^^ required by this bound in `Foo::c` diff --git a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs index d63381b5f2cc9..f7ff60d84bd1d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs @@ -1,6 +1,7 @@ // compile-flags: -Z parse-only #![feature(const_trait_impl)] +#![feature(effects)] struct S; //~^ ERROR const bounds must start with `~` diff --git a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr index 31300354a5737..296417106acd9 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr @@ -1,5 +1,5 @@ error: const bounds must start with `~` - --> $DIR/without-tilde.rs:5:13 + --> $DIR/without-tilde.rs:6:13 | LL | struct S; | -^^^^ diff --git a/src/test/ui/static/static-vec-repeat-not-constant.rs b/src/test/ui/static/static-vec-repeat-not-constant.rs index 61c87b144d9e4..047426fb33f8f 100644 --- a/src/test/ui/static/static-vec-repeat-not-constant.rs +++ b/src/test/ui/static/static-vec-repeat-not-constant.rs @@ -1,6 +1,6 @@ fn foo() -> isize { 23 } static a: [isize; 2] = [foo(); 2]; -//~^ ERROR: E0015 +//~^ ERROR: cannot call non-const fn `foo` in statics [E0015] fn main() {} From 93b00a775a5064c37c248baaf524cbf62ed5867b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 30 Nov 2022 11:09:22 +0000 Subject: [PATCH 13/13] Add Callable trait for future simplification of const checks --- compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_hir_typeck/src/callee.rs | 28 ++++++ .../src/thir/pattern/const_to_pat.rs | 3 +- .../rustc_mir_dataflow/src/elaborate_drops.rs | 7 ++ compiler/rustc_span/src/symbol.rs | 1 + .../src/traits/select/candidate_assembly.rs | 31 +++++++ .../src/traits/select/confirmation.rs | 9 +- .../src/traits/select/mod.rs | 87 +++++++++++++++++++ library/core/src/ops/function.rs | 27 ++++++ library/core/src/ops/mod.rs | 4 + src/test/ui/consts/operator_traits.rs | 6 +- 11 files changed, 199 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 3474fab34f00b..ee1694318cb30 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -212,6 +212,7 @@ language_item_table! { Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1); FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + Callable, sym::callable, callable_trait, Target::Trait, GenericRequirement::Exact(1); FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9c307ba7a49c5..d7dbc2eebf4f3 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -4,11 +4,13 @@ use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use crate::type_error_struct; use hir::def::DefKind; +use hir::LangItem; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, Namespace, Res}; use rustc_hir::def_id::DefId; +use rustc_infer::traits::ObligationCauseCode; use rustc_infer::{ infer, traits::{self, Obligation}, @@ -772,6 +774,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } + // If libcore had effects enabled, FnOnce has 3 generic params (Self, Args, HostEffect). + // Once we remove the effect feature and just enable it by default, remove the condition + // and everything after the `return`. + if self.tcx.generics_of(self.tcx.require_lang_item(LangItem::Callable, Some(span))).count() + == 3 + { + let effects = + [self.tcx.effect_from_context(context.to_def_id(), ty::EffectKind::Host, || { + ty::EffectValue::Rigid { on: !require_const } + })]; + + for effect in effects { + let cause = self.cause(span, ObligationCauseCode::MiscObligation); + let any_type = self.infcx.next_ty_var(TypeVariableOrigin { + span, + kind: TypeVariableOriginKind::MiscVariable, + }); + let pred = ty::Binder::dummy(self.tcx.at(span).mk_trait_ref( + LangItem::Callable, + [ty::GenericArg::from(value), any_type.into(), effect.into()], + )); + self.register_predicate(Obligation::new(self.tcx, cause, self.param_env, pred)); + } + return; + } + // Walk all the effects in the type, error on mismatches and bind inferred effects. struct EffectVisitor<'a, 'tcx> { span: Span, diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 292ace9f2024c..9254c798c09ba 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -226,13 +226,14 @@ impl<'tcx> ConstToPat<'tcx> { // using `PartialEq::eq` in this scenario in the past.) let partial_eq_trait_id = self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); + let arg = ty::GenericArg::from(ty); let obligation: PredicateObligation<'_> = predicate_for_trait_def( self.tcx(), self.param_env, ObligationCause::misc(self.span, self.id), partial_eq_trait_id, 0, - [ty, ty], + [arg, arg].into_iter().chain(self.tcx().host_effect()), ); // FIXME: should this call a `predicate_must_hold` variant instead? diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index d8d15f7c49794..e4cb188909753 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -962,6 +962,13 @@ where let tcx = self.tcx(); let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); let free_func = tcx.require_lang_item(LangItem::BoxFree, Some(self.source_info.span)); + + let substs = if tcx.effects() { + tcx.mk_substs(substs.iter().chain(tcx.host_effect())) + } else { + substs + }; + let args = adt .variant(VariantIdx::new(0)) .fields diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b0b9d4d64c3c..d743237811387 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -441,6 +441,7 @@ symbols! { call, call_mut, call_once, + callable, caller_location, capture_disjoint_fields, cause, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index f3a91df1ef0d1..68bd21dcc23fb 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -105,6 +105,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let clone_conditions = self.copy_clone_conditions(obligation); self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates); } + if lang_items.callable_trait() == Some(def_id) { + // `Callable` is automatically implemented for all fn items and closures + self.assemble_builtin_callable_candidates(obligation, &mut candidates); + } if lang_items.gen_trait() == Some(def_id) { self.assemble_generator_candidates(obligation, &mut candidates); @@ -328,6 +332,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + /// Implements one of the `Fn()` family for a fn pointer. + #[instrument(skip(self, candidates), level = "debug")] + fn assemble_builtin_callable_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + trace!(substs = ?obligation.predicate.skip_binder().trait_ref.substs); + match obligation.predicate.skip_binder().trait_ref.substs.len() { + // without effects enabled, this always holds + 2 => return candidates.vec.push(BuiltinCandidate { has_nested: false }), + 3 => {} + _ => span_bug!(obligation.cause.span, "invalid number of substs: {obligation:#?}"), + } + // Okay to skip binder because what we are inspecting doesn't involve bound regions. + let self_ty = obligation.self_ty().skip_binder(); + trace!(?self_ty); + trace!(ty = ?self_ty.kind()); + match *self_ty.kind() { + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_builtin_callable_candidates: ambiguous self-type"); + candidates.ambiguous = true; // Could wind up being a fn() type. + } + _ => candidates.vec.push(BuiltinCandidate { has_nested: true }), + } + } + /// Searches for impls that might apply to `obligation`. fn assemble_candidates_from_impls( &mut self, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 03c63b6bd7ac9..2c01f8a580685 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -50,7 +50,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result, SelectionError<'tcx>> { let mut impl_src = match candidate { BuiltinCandidate { has_nested } => { - let data = self.confirm_builtin_candidate(obligation, has_nested); + let data = self.confirm_builtin_candidate(obligation, has_nested)?; ImplSource::Builtin(data) } @@ -252,7 +252,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, has_nested: bool, - ) -> ImplSourceBuiltinData> { + ) -> Result>, SelectionError<'tcx>> { debug!(?obligation, ?has_nested, "confirm_builtin_candidate"); let lang_items = self.tcx().lang_items(); @@ -271,6 +271,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &[] }; (self.copy_clone_conditions(obligation), rest) + } else if Some(trait_def) == lang_items.callable_trait() { + self.callable_predicates(obligation)?; + return Ok(ImplSourceBuiltinData { nested: vec![] }); } else { bug!("unexpected builtin trait {:?}", trait_def) }; @@ -295,7 +298,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligations); - ImplSourceBuiltinData { nested: obligations } + Ok(ImplSourceBuiltinData { nested: obligations }) } fn confirm_transmutability_candidate( diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d908ee80a22ec..3cdf8070fd515 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -38,13 +38,16 @@ use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::LateBoundRegionConversionTime; +use rustc_infer::traits::PredicateObligations; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; +use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::SubstsRef; +use rustc_middle::ty::TypeVisitor; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_span::symbol::sym; @@ -2132,6 +2135,90 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn callable_predicates( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result, SelectionError<'tcx>> { + // NOTE: binder moved to (*) + let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); + let substs = obligation.predicate.skip_binder().trait_ref.substs; + // Increase this number when adding more effects (like async) + assert_eq!(substs.len(), 3, "{substs:?}"); + // This is just a way to ensure that when you add a new effect kind, you get an error here + // and adjust the logic to handle the new effect. + match ty::EffectKind::Host { + ty::EffectKind::Host => {} + } + let mut obligations = vec![]; + for effect in &substs[2..] { + let effect = self.infcx.shallow_resolve(effect.expect_effect()); + match *self_ty.kind() { + ty::FnDef(_, substs) => { + if let ty::EffectValue::Rigid { on: true } = effect.val { + // The function is always callable if the requested effect is on. + // e.g. all functions are callable in a host (non-const) context + continue; + } + struct Visitor<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + effect: ty::Effect<'tcx>, + cause: &'a ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + } + impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> { + type BreakTy = TypeError<'tcx>; + fn visit_effect( + &mut self, + e: ty::Effect<'tcx>, + ) -> std::ops::ControlFlow { + if e.kind == self.effect.kind { + let res = + self.infcx.at(self.cause, self.param_env).eq(e, self.effect); + match res { + Ok(InferOk { value: (), obligations }) => { + assert_eq!(obligations.len(), 0, "{obligations:?}") + } + Err(err) => return std::ops::ControlFlow::Break(err), + } + } + std::ops::ControlFlow::CONTINUE + } + } + match substs.visit_with(&mut Visitor { + effect, + infcx: self.infcx, + cause: &obligation.cause, + param_env: obligation.param_env, + }) { + std::ops::ControlFlow::Continue(()) => {} + std::ops::ControlFlow::Break(_) => { + return Err(SelectionError::Unimplemented); + } + } + } + ty::FnPtr(..) | ty::Closure(..) => { + if let ty::EffectValue::Rigid { on: true } = effect.val { + continue; + } + return Err(SelectionError::Unimplemented); + } + _ => obligations.push(Obligation::new( + self.tcx(), + obligation.cause.clone(), + obligation.param_env, + obligation.predicate.map_bound(|mut pred| { + pred.trait_ref.def_id = self.tcx().require_lang_item( + rustc_hir::LangItem::FnOnce, + Some(obligation.cause.span), + ); + pred + }), + )), + } + } + Ok(obligations) + } + fn copy_clone_conditions( &mut self, obligation: &TraitObligation<'tcx>, diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index 94f96d7c21e5a..94dea25409e9f 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -239,6 +239,25 @@ pub trait FnMut: ~const FnOnce { #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] #[const_trait] +#[cfg(not(bootstrap))] +pub trait FnOnce: Callable { + /// The returned type after the call operator is used. + #[lang = "fn_once_output"] + #[stable(feature = "fn_once_output", since = "1.12.0")] + type Output; + + /// Performs the call operation. + #[unstable(feature = "fn_traits", issue = "29625")] + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +#[cfg(bootstrap)] +#[const_trait] +#[lang = "fn_once"] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` +/// Nope pub trait FnOnce { /// The returned type after the call operator is used. #[lang = "fn_once_output"] @@ -250,6 +269,14 @@ pub trait FnOnce { extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } +#[cfg(not(bootstrap))] +#[const_trait] +#[lang = "callable"] +#[unstable(feature = "fn_traits", issue = "29625")] +/// This is an internal trait that, in contrast to `FnOnce` is also implemented +/// for unsafe functions and intrinsics. +pub trait Callable {} + mod impls { use crate::marker::Tuple; diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 97d9b750d92f9..7e2be8ebbefec 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -209,3 +209,7 @@ pub use self::unsize::DispatchFromDyn; #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] pub use self::control_flow::ControlFlow; + +#[unstable(feature = "fn_traits", issue = "29625")] +#[cfg(not(bootstrap))] +pub use self::function::Callable; diff --git a/src/test/ui/consts/operator_traits.rs b/src/test/ui/consts/operator_traits.rs index 6edb998d64eaf..dae65f79ef051 100644 --- a/src/test/ui/consts/operator_traits.rs +++ b/src/test/ui/consts/operator_traits.rs @@ -79,12 +79,16 @@ trait FnMut: ~const FnOnce { #[const_trait] #[lang = "fn_once"] #[rustc_paren_sugar] -trait FnOnce { +trait FnOnce: Callable { type Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } +#[const_trait] +#[lang = "callable"] +trait Callable {} + struct ConstFnMutClosure { data: CapturedData, func: Function,