mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-19 02:13:57 +00:00
Rollup merge of #126360 - compiler-errors:uplift-structural-traits, r=lcnr
Uplift `structural_traits.rs` into the new trait solver Self-explanatory. I will leave some comments inline regarding design decisions.
This commit is contained in:
commit
4dd8813afd
@ -244,7 +244,9 @@ language_item_table! {
|
||||
AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
|
||||
CoroutineState, sym::coroutine_state, coroutine_state, Target::Enum, GenericRequirement::None;
|
||||
Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Minimum(1);
|
||||
Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
CoroutineReturn, sym::coroutine_return, coroutine_return, Target::AssocTy, GenericRequirement::Exact(1);
|
||||
CoroutineYield, sym::coroutine_yield, coroutine_yield, Target::AssocTy, GenericRequirement::Exact(1);
|
||||
CoroutineResume, sym::coroutine_resume, coroutine_resume, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
|
||||
|
||||
Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
|
||||
|
@ -225,6 +225,50 @@ impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Used in the new solver since we don't care about tracking an `ObligationCause`.
|
||||
pub fn relate_no_trace<T>(
|
||||
self,
|
||||
expected: T,
|
||||
variance: ty::Variance,
|
||||
actual: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>
|
||||
where
|
||||
T: Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
let mut fields = CombineFields::new(
|
||||
self.infcx,
|
||||
TypeTrace::dummy(self.cause),
|
||||
self.param_env,
|
||||
DefineOpaqueTypes::Yes,
|
||||
);
|
||||
fields.sub().relate_with_variance(
|
||||
variance,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
expected,
|
||||
actual,
|
||||
)?;
|
||||
Ok(fields.goals)
|
||||
}
|
||||
|
||||
/// Used in the new solver since we don't care about tracking an `ObligationCause`.
|
||||
pub fn eq_structurally_relating_aliases_no_trace<T>(
|
||||
self,
|
||||
expected: T,
|
||||
actual: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>
|
||||
where
|
||||
T: Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
let mut fields = CombineFields::new(
|
||||
self.infcx,
|
||||
TypeTrace::dummy(self.cause),
|
||||
self.param_env,
|
||||
DefineOpaqueTypes::Yes,
|
||||
);
|
||||
fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?;
|
||||
Ok(fields.goals)
|
||||
}
|
||||
|
||||
/// Computes the least-upper-bound, or mutual supertype, of two
|
||||
/// values. The order of the arguments doesn't matter, but since
|
||||
/// this can result in an error (e.g., if asked to compute LUB of
|
||||
@ -303,7 +347,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -315,7 +359,10 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
|
||||
a: Self,
|
||||
b: Self,
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace { cause: cause.clone(), values: Regions(ExpectedFound::new(a_is_expected, a, b)) }
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,7 +375,7 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -344,13 +391,13 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
|
||||
cause: cause.clone(),
|
||||
values: match (a.unpack(), b.unpack()) {
|
||||
(GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
|
||||
Regions(ExpectedFound::new(a_is_expected, a, b))
|
||||
ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b))
|
||||
}
|
||||
(GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
|
||||
Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
|
||||
ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
|
||||
}
|
||||
(GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
|
||||
Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
|
||||
ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
|
||||
}
|
||||
|
||||
(
|
||||
@ -379,7 +426,10 @@ impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
|
||||
a: Self,
|
||||
b: Self,
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace { cause: cause.clone(), values: Terms(ExpectedFound::new(a_is_expected, a, b)) }
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a, b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,7 +442,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
|
||||
values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -406,7 +456,7 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -418,7 +468,10 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
|
||||
a: Self,
|
||||
b: Self,
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) }
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a, b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,7 +484,7 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: PolySigs(ExpectedFound::new(
|
||||
values: ValuePairs::PolySigs(ExpectedFound::new(
|
||||
a_is_expected,
|
||||
ty::Binder::dummy(a),
|
||||
ty::Binder::dummy(b),
|
||||
@ -449,7 +502,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> {
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: PolySigs(ExpectedFound::new(a_is_expected, a, b)),
|
||||
values: ValuePairs::PolySigs(ExpectedFound::new(a_is_expected, a, b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -463,7 +516,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)),
|
||||
values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -477,7 +530,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)),
|
||||
values: ValuePairs::ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1707,6 +1707,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
ValuePairs::ExistentialProjection(_) => {
|
||||
(false, Mismatch::Fixed("existential projection"))
|
||||
}
|
||||
ValuePairs::Dummy => {
|
||||
bug!("do not expect to report a type error from a ValuePairs::Dummy")
|
||||
}
|
||||
};
|
||||
let Some(vals) = self.values_str(values) else {
|
||||
// Derived error. Cancel the emitter.
|
||||
@ -2250,12 +2253,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
values: ValuePairs<'tcx>,
|
||||
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
|
||||
match values {
|
||||
infer::Regions(exp_found) => self.expected_found_str(exp_found),
|
||||
infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
|
||||
infer::Aliases(exp_found) => self.expected_found_str(exp_found),
|
||||
infer::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
|
||||
infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
|
||||
infer::TraitRefs(exp_found) => {
|
||||
ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
|
||||
ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found),
|
||||
ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found),
|
||||
ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
|
||||
ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
|
||||
ValuePairs::TraitRefs(exp_found) => {
|
||||
let pretty_exp_found = ty::error::ExpectedFound {
|
||||
expected: exp_found.expected.print_trait_sugared(),
|
||||
found: exp_found.found.print_trait_sugared(),
|
||||
@ -2267,7 +2270,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
ret => ret,
|
||||
}
|
||||
}
|
||||
infer::PolySigs(exp_found) => {
|
||||
ValuePairs::PolySigs(exp_found) => {
|
||||
let exp_found = self.resolve_vars_if_possible(exp_found);
|
||||
if exp_found.references_error() {
|
||||
return None;
|
||||
@ -2275,6 +2278,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, &exp_found.found);
|
||||
Some((exp, fnd, None))
|
||||
}
|
||||
ValuePairs::Dummy => {
|
||||
bug!("do not expect to report a type error from a ValuePairs::Dummy")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,9 +9,8 @@ pub use rustc_middle::ty::IntVarValue;
|
||||
pub use BoundRegionConversionTime::*;
|
||||
pub use RegionVariableOrigin::*;
|
||||
pub use SubregionOrigin::*;
|
||||
pub use ValuePairs::*;
|
||||
|
||||
use crate::infer::relate::RelateResult;
|
||||
use crate::infer::relate::{Relate, RelateResult};
|
||||
use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine};
|
||||
use error_reporting::TypeErrCtxt;
|
||||
use free_regions::RegionRelations;
|
||||
@ -35,6 +34,7 @@ use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey};
|
||||
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::select;
|
||||
use rustc_middle::traits::solve::{Goal, NoSolution};
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::fold::BoundVarReplacerDelegate;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
@ -44,7 +44,7 @@ use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use snapshot::undo_log::InferCtxtUndoLogs;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::fmt;
|
||||
@ -352,6 +352,13 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
|
||||
match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_ct(&self, ct: ConstVid) -> Option<ty::UniverseIndex> {
|
||||
// Same issue as with `universe_of_ty`
|
||||
match self.probe_const_var(ct) {
|
||||
@ -360,19 +367,12 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
|
||||
match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
fn root_ty_var(&self, var: TyVid) -> TyVid {
|
||||
self.root_var(var)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
|
||||
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
|
||||
}
|
||||
|
||||
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.defining_opaque_types
|
||||
fn root_const_var(&self, var: ConstVid) -> ConstVid {
|
||||
self.root_const_var(var)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> {
|
||||
@ -405,6 +405,72 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
|
||||
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
|
||||
}
|
||||
|
||||
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.defining_opaque_types
|
||||
}
|
||||
|
||||
fn next_ty_infer(&self) -> Ty<'tcx> {
|
||||
self.next_ty_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn next_const_infer(&self) -> ty::Const<'tcx> {
|
||||
self.next_const_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
|
||||
self.fresh_args_for_item(DUMMY_SP, def_id)
|
||||
}
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
) -> T {
|
||||
self.instantiate_binder_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U {
|
||||
self.enter_forall(value, f)
|
||||
}
|
||||
|
||||
fn relate<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs)
|
||||
}
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.at(&ObligationCause::dummy(), param_env)
|
||||
.eq_structurally_relating_aliases_no_trace(lhs, rhs)
|
||||
}
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.resolve_vars_if_possible(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// See the `error_reporting` module for more details.
|
||||
@ -417,6 +483,7 @@ pub enum ValuePairs<'tcx> {
|
||||
PolySigs(ExpectedFound<ty::PolyFnSig<'tcx>>),
|
||||
ExistentialTraitRef(ExpectedFound<ty::PolyExistentialTraitRef<'tcx>>),
|
||||
ExistentialProjection(ExpectedFound<ty::PolyExistentialProjection<'tcx>>),
|
||||
Dummy,
|
||||
}
|
||||
|
||||
impl<'tcx> ValuePairs<'tcx> {
|
||||
@ -1812,7 +1879,7 @@ impl<'tcx> TypeTrace<'tcx> {
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1824,7 +1891,7 @@ impl<'tcx> TypeTrace<'tcx> {
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
|
||||
values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1836,9 +1903,13 @@ impl<'tcx> TypeTrace<'tcx> {
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
}
|
||||
}
|
||||
|
||||
fn dummy(cause: &ObligationCause<'tcx>) -> TypeTrace<'tcx> {
|
||||
TypeTrace { cause: cause.clone(), values: ValuePairs::Dummy }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> SubregionOrigin<'tcx> {
|
||||
|
@ -204,6 +204,23 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
|
||||
fn def_id(self) -> DefId {
|
||||
self.did()
|
||||
}
|
||||
|
||||
fn is_phantom_data(self) -> bool {
|
||||
self.is_phantom_data()
|
||||
}
|
||||
|
||||
fn all_field_tys(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> ty::EarlyBinder<'tcx, impl Iterator<Item = Ty<'tcx>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.all_fields().map(move |field| tcx.type_of(field.did).skip_binder()),
|
||||
)
|
||||
}
|
||||
|
||||
fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
|
||||
self.sized_constraint(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)]
|
||||
|
@ -70,9 +70,9 @@ use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use rustc_type_ir::lang_items::TraitSolverLangItem;
|
||||
use rustc_type_ir::TyKind::*;
|
||||
use rustc_type_ir::WithCachedTypeInfo;
|
||||
use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
|
||||
use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
@ -154,7 +154,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
|
||||
type VariancesOf = &'tcx [ty::Variance];
|
||||
|
||||
fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf {
|
||||
fn variances_of(self, def_id: DefId) -> Self::VariancesOf {
|
||||
self.variances_of(def_id)
|
||||
}
|
||||
|
||||
@ -198,7 +198,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
|
||||
fn trait_ref_and_own_args_for_alias(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
def_id: DefId,
|
||||
args: Self::GenericArgs,
|
||||
) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) {
|
||||
assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
|
||||
@ -246,7 +246,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
self.mk_type_list_from_iter(args)
|
||||
}
|
||||
|
||||
fn parent(self, def_id: Self::DefId) -> Self::DefId {
|
||||
fn parent(self, def_id: DefId) -> DefId {
|
||||
self.parent(def_id)
|
||||
}
|
||||
|
||||
@ -259,15 +259,85 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
fn features(self) -> Self::Features {
|
||||
self.features()
|
||||
}
|
||||
|
||||
fn bound_coroutine_hidden_types(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> impl IntoIterator<Item = ty::EarlyBinder<'tcx, ty::Binder<'tcx, Ty<'tcx>>>> {
|
||||
self.bound_coroutine_hidden_types(def_id)
|
||||
}
|
||||
|
||||
fn fn_sig(self, def_id: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
|
||||
self.fn_sig(def_id)
|
||||
}
|
||||
|
||||
fn coroutine_movability(self, def_id: DefId) -> rustc_ast::Movability {
|
||||
self.coroutine_movability(def_id)
|
||||
}
|
||||
|
||||
fn coroutine_for_closure(self, def_id: DefId) -> DefId {
|
||||
self.coroutine_for_closure(def_id)
|
||||
}
|
||||
|
||||
fn generics_require_sized_self(self, def_id: DefId) -> bool {
|
||||
self.generics_require_sized_self(def_id)
|
||||
}
|
||||
|
||||
fn item_bounds(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
self.item_bounds(def_id).map_bound(IntoIterator::into_iter)
|
||||
}
|
||||
|
||||
fn super_predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.super_predicates_of(def_id).instantiate_identity(self).predicates.into_iter(),
|
||||
)
|
||||
}
|
||||
|
||||
fn has_target_features(self, def_id: DefId) -> bool {
|
||||
!self.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
}
|
||||
|
||||
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId {
|
||||
self.require_lang_item(
|
||||
match lang_item {
|
||||
TraitSolverLangItem::Future => hir::LangItem::Future,
|
||||
TraitSolverLangItem::FutureOutput => hir::LangItem::FutureOutput,
|
||||
TraitSolverLangItem::AsyncFnKindHelper => hir::LangItem::AsyncFnKindHelper,
|
||||
TraitSolverLangItem::AsyncFnKindUpvars => hir::LangItem::AsyncFnKindUpvars,
|
||||
},
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
|
||||
self.associated_items(def_id)
|
||||
.in_definition_order()
|
||||
.filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type))
|
||||
.map(|assoc_item| assoc_item.def_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi {
|
||||
fn rust() -> Self {
|
||||
abi::Abi::Rust
|
||||
}
|
||||
|
||||
fn is_rust(self) -> bool {
|
||||
matches!(self, abi::Abi::Rust)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety {
|
||||
fn safe() -> Self {
|
||||
hir::Safety::Safe
|
||||
}
|
||||
|
||||
fn is_safe(self) -> bool {
|
||||
matches!(self, hir::Safety::Safe)
|
||||
}
|
||||
@ -281,6 +351,10 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu
|
||||
fn generic_const_exprs(self) -> bool {
|
||||
self.generic_const_exprs
|
||||
}
|
||||
|
||||
fn coroutine_clone(self) -> bool {
|
||||
self.coroutine_clone
|
||||
}
|
||||
}
|
||||
|
||||
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
|
||||
|
@ -41,6 +41,8 @@ pub struct GenericArg<'tcx> {
|
||||
marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>,
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::GenericArg<TyCtxt<'tcx>> for GenericArg<'tcx> {}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> {
|
||||
fn type_at(self, i: usize) -> Ty<'tcx> {
|
||||
self.type_at(i)
|
||||
|
@ -488,6 +488,8 @@ pub struct Term<'tcx> {
|
||||
marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>,
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Term<TyCtxt<'tcx>> for Term<'tcx> {}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::IntoKind for Term<'tcx> {
|
||||
type Kind = TermKind<'tcx>;
|
||||
|
||||
|
@ -49,6 +49,18 @@ impl<'tcx> rustc_type_ir::inherent::Predicate<TyCtxt<'tcx>> for Predicate<'tcx>
|
||||
fn is_coinductive(self, interner: TyCtxt<'tcx>) -> bool {
|
||||
self.is_coinductive(interner)
|
||||
}
|
||||
|
||||
fn allow_normalization(self) -> bool {
|
||||
self.allow_normalization()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::IntoKind for Predicate<'tcx> {
|
||||
type Kind = ty::Binder<'tcx, ty::PredicateKind<'tcx>>;
|
||||
|
||||
fn kind(self) -> Self::Kind {
|
||||
self.kind()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> {
|
||||
@ -120,6 +132,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||
/// unsoundly accept some programs. See #91068.
|
||||
#[inline]
|
||||
pub fn allow_normalization(self) -> bool {
|
||||
// Keep this in sync with the one in `rustc_type_ir::inherent`!
|
||||
match self.kind().skip_binder() {
|
||||
PredicateKind::Clause(ClauseKind::WellFormed(_))
|
||||
| PredicateKind::AliasRelate(..)
|
||||
|
@ -786,6 +786,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
|
||||
tcx.types.bool
|
||||
}
|
||||
|
||||
fn new_u8(tcx: TyCtxt<'tcx>) -> Self {
|
||||
tcx.types.u8
|
||||
}
|
||||
|
||||
fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Self {
|
||||
Ty::new_infer(tcx, infer)
|
||||
}
|
||||
|
@ -635,7 +635,9 @@ symbols! {
|
||||
coroutine,
|
||||
coroutine_clone,
|
||||
coroutine_resume,
|
||||
coroutine_return,
|
||||
coroutine_state,
|
||||
coroutine_yield,
|
||||
coroutines,
|
||||
cosf128,
|
||||
cosf16,
|
||||
|
@ -1,14 +1,14 @@
|
||||
//! Code which is used by built-in goals that match "structurally", such a auto
|
||||
//! traits, `Copy`/`Clone`.
|
||||
|
||||
use rustc_ast_ir::{Movability, Mutability};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_hir::{def_id::DefId, Movability, Mutability};
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::traits::solve::Goal;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, Upcast};
|
||||
use rustc_next_trait_solver::solve::{Goal, NoSolution};
|
||||
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::lang_items::TraitSolverLangItem;
|
||||
use rustc_type_ir::{self as ty, InferCtxtLike, Interner, Upcast};
|
||||
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
|
||||
use crate::solve::EvalCtxt;
|
||||
|
||||
@ -17,12 +17,16 @@ use crate::solve::EvalCtxt;
|
||||
// For types with an "existential" binder, i.e. coroutine witnesses, we also
|
||||
// instantiate the binder with placeholders eagerly.
|
||||
#[instrument(level = "trace", skip(ecx), ret)]
|
||||
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||
ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
|
||||
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<Infcx, I>(
|
||||
ecx: &EvalCtxt<'_, Infcx>,
|
||||
ty: I::Ty,
|
||||
) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
let tcx = ecx.interner();
|
||||
match *ty.kind() {
|
||||
match ty.kind() {
|
||||
ty::Uint(_)
|
||||
| ty::Int(_)
|
||||
| ty::Bool
|
||||
@ -34,7 +38,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||
| ty::Char => Ok(vec![]),
|
||||
|
||||
// Treat `str` like it's defined as `struct str([u8]);`
|
||||
ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, tcx.types.u8))]),
|
||||
ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, Ty::new_u8(tcx)))]),
|
||||
|
||||
ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
@ -43,7 +47,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||
| ty::Placeholder(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(_) => {
|
||||
bug!("unexpected type `{ty}`")
|
||||
panic!("unexpected type `{ty:?}`")
|
||||
}
|
||||
|
||||
ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => {
|
||||
@ -56,7 +60,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||
|
||||
ty::Tuple(tys) => {
|
||||
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
|
||||
Ok(tys.iter().map(ty::Binder::dummy).collect())
|
||||
Ok(tys.into_iter().map(ty::Binder::dummy).collect())
|
||||
}
|
||||
|
||||
ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]),
|
||||
@ -76,31 +80,38 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||
ty::CoroutineWitness(def_id, args) => Ok(ecx
|
||||
.interner()
|
||||
.bound_coroutine_hidden_types(def_id)
|
||||
.map(|bty| bty.instantiate(tcx, args))
|
||||
.into_iter()
|
||||
.map(|bty| bty.instantiate(tcx, &args))
|
||||
.collect()),
|
||||
|
||||
// For `PhantomData<T>`, we pass `T`.
|
||||
ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![ty::Binder::dummy(args.type_at(0))]),
|
||||
|
||||
ty::Adt(def, args) => {
|
||||
Ok(def.all_fields().map(|f| ty::Binder::dummy(f.ty(tcx, args))).collect())
|
||||
}
|
||||
ty::Adt(def, args) => Ok(def
|
||||
.all_field_tys(tcx)
|
||||
.iter_instantiated(tcx, &args)
|
||||
.map(ty::Binder::dummy)
|
||||
.collect()),
|
||||
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
|
||||
// We can resolve the `impl Trait` to its concrete type,
|
||||
// which enforces a DAG between the functions requiring
|
||||
// the auto trait bounds in question.
|
||||
Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, args))])
|
||||
Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, &args))])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(ecx), ret)]
|
||||
pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||
ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
|
||||
match *ty.kind() {
|
||||
pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<Infcx, I>(
|
||||
ecx: &EvalCtxt<'_, Infcx>,
|
||||
ty: I::Ty,
|
||||
) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
match ty.kind() {
|
||||
// impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, !
|
||||
// impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure
|
||||
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||
@ -133,7 +144,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||
|
||||
ty::Bound(..)
|
||||
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||
bug!("unexpected type `{ty}`")
|
||||
panic!("unexpected type `{ty:?}`")
|
||||
}
|
||||
|
||||
// impl Sized for ()
|
||||
@ -151,7 +162,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||
// if the ADT is sized for all possible args.
|
||||
ty::Adt(def, args) => {
|
||||
if let Some(sized_crit) = def.sized_constraint(ecx.interner()) {
|
||||
Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), args))])
|
||||
Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), &args))])
|
||||
} else {
|
||||
Ok(vec![])
|
||||
}
|
||||
@ -160,11 +171,15 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(ecx), ret)]
|
||||
pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||
ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
|
||||
match *ty.kind() {
|
||||
pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<Infcx, I>(
|
||||
ecx: &EvalCtxt<'_, Infcx>,
|
||||
ty: I::Ty,
|
||||
) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
match ty.kind() {
|
||||
// impl Copy/Clone for FnDef, FnPtr
|
||||
ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]),
|
||||
|
||||
@ -196,11 +211,11 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||
|
||||
ty::Bound(..)
|
||||
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||
bug!("unexpected type `{ty}`")
|
||||
panic!("unexpected type `{ty:?}`")
|
||||
}
|
||||
|
||||
// impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone
|
||||
ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()),
|
||||
ty::Tuple(tys) => Ok(tys.into_iter().map(ty::Binder::dummy).collect()),
|
||||
|
||||
// impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone
|
||||
ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]),
|
||||
@ -212,7 +227,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||
ty::Coroutine(def_id, args) => match ecx.interner().coroutine_movability(def_id) {
|
||||
Movability::Static => Err(NoSolution),
|
||||
Movability::Movable => {
|
||||
if ecx.interner().features().coroutine_clone {
|
||||
if ecx.interner().features().coroutine_clone() {
|
||||
let coroutine = args.as_coroutine();
|
||||
Ok(vec![
|
||||
ty::Binder::dummy(coroutine.tupled_upvars_ty()),
|
||||
@ -228,27 +243,26 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||
ty::CoroutineWitness(def_id, args) => Ok(ecx
|
||||
.interner()
|
||||
.bound_coroutine_hidden_types(def_id)
|
||||
.map(|bty| bty.instantiate(ecx.interner(), args))
|
||||
.into_iter()
|
||||
.map(|bty| bty.instantiate(ecx.interner(), &args))
|
||||
.collect()),
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a binder of the tupled inputs types and output type from a builtin callable type.
|
||||
pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Interner>(
|
||||
tcx: I,
|
||||
self_ty: I::Ty,
|
||||
goal_kind: ty::ClosureKind,
|
||||
) -> Result<Option<ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, NoSolution> {
|
||||
match *self_ty.kind() {
|
||||
) -> Result<Option<ty::Binder<I, (I::Ty, I::Ty)>>, NoSolution> {
|
||||
match self_ty.kind() {
|
||||
// keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
|
||||
ty::FnDef(def_id, args) => {
|
||||
let sig = tcx.fn_sig(def_id);
|
||||
if sig.skip_binder().is_fn_trait_compatible()
|
||||
&& tcx.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
{
|
||||
if sig.skip_binder().is_fn_trait_compatible() && !tcx.has_target_features(def_id) {
|
||||
Ok(Some(
|
||||
sig.instantiate(tcx, args)
|
||||
.map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())),
|
||||
sig.instantiate(tcx, &args)
|
||||
.map_bound(|sig| (Ty::new_tup(tcx, &sig.inputs()), sig.output())),
|
||||
))
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
@ -257,7 +271,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
||||
// keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
|
||||
ty::FnPtr(sig) => {
|
||||
if sig.is_fn_trait_compatible() {
|
||||
Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output()))))
|
||||
Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, &sig.inputs()), sig.output()))))
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
@ -311,7 +325,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
||||
tcx,
|
||||
goal_kind,
|
||||
// No captures by ref, so this doesn't matter.
|
||||
tcx.lifetimes.re_static,
|
||||
Region::new_static(tcx),
|
||||
def_id,
|
||||
args,
|
||||
sig,
|
||||
@ -326,7 +340,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
||||
coroutine_closure_to_ambiguous_coroutine(
|
||||
tcx,
|
||||
goal_kind, // No captures by ref, so this doesn't matter.
|
||||
tcx.lifetimes.re_static,
|
||||
Region::new_static(tcx),
|
||||
def_id,
|
||||
args,
|
||||
sig,
|
||||
@ -362,22 +376,24 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
||||
|
||||
ty::Bound(..)
|
||||
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||
bug!("unexpected type `{self_ty}`")
|
||||
panic!("unexpected type `{self_ty:?}`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Relevant types for an async callable, including its inputs, output,
|
||||
/// and the return type you get from awaiting the output.
|
||||
#[derive(Copy, Clone, Debug, TypeVisitable, TypeFoldable)]
|
||||
pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> {
|
||||
pub tupled_inputs_ty: Ty<'tcx>,
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(Clone(bound = ""), Copy(bound = ""), Debug(bound = ""))]
|
||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
|
||||
pub(in crate::solve) struct AsyncCallableRelevantTypes<I: Interner> {
|
||||
pub tupled_inputs_ty: I::Ty,
|
||||
/// Type returned by calling the closure
|
||||
/// i.e. `f()`.
|
||||
pub output_coroutine_ty: Ty<'tcx>,
|
||||
pub output_coroutine_ty: I::Ty,
|
||||
/// Type returned by `await`ing the output
|
||||
/// i.e. `f().await`.
|
||||
pub coroutine_return_ty: Ty<'tcx>,
|
||||
pub coroutine_return_ty: I::Ty,
|
||||
}
|
||||
|
||||
// Returns a binder of the tupled inputs types, output type, and coroutine type
|
||||
@ -385,16 +401,13 @@ pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> {
|
||||
// the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper`
|
||||
// which enforces the closure is actually callable with the given trait. When we
|
||||
// know the kind already, we can short-circuit this check.
|
||||
pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I: Interner>(
|
||||
tcx: I,
|
||||
self_ty: I::Ty,
|
||||
goal_kind: ty::ClosureKind,
|
||||
env_region: ty::Region<'tcx>,
|
||||
) -> Result<
|
||||
(ty::Binder<'tcx, AsyncCallableRelevantTypes<'tcx>>, Vec<ty::Predicate<'tcx>>),
|
||||
NoSolution,
|
||||
> {
|
||||
match *self_ty.kind() {
|
||||
env_region: I::Region,
|
||||
) -> Result<(ty::Binder<I, AsyncCallableRelevantTypes<I>>, Vec<I::Predicate>), NoSolution> {
|
||||
match self_ty.kind() {
|
||||
ty::CoroutineClosure(def_id, args) => {
|
||||
let args = args.as_coroutine_closure();
|
||||
let kind_ty = args.kind_ty();
|
||||
@ -421,7 +434,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
||||
nested.push(
|
||||
ty::TraitRef::new(
|
||||
tcx,
|
||||
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None),
|
||||
tcx.require_lang_item(TraitSolverLangItem::AsyncFnKindHelper),
|
||||
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
|
||||
)
|
||||
.upcast(tcx),
|
||||
@ -445,7 +458,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
||||
ty::FnDef(..) | ty::FnPtr(..) => {
|
||||
let bound_sig = self_ty.fn_sig(tcx);
|
||||
let sig = bound_sig.skip_binder();
|
||||
let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
|
||||
let future_trait_def_id = tcx.require_lang_item(TraitSolverLangItem::Future);
|
||||
// `FnDef` and `FnPtr` only implement `AsyncFn*` when their
|
||||
// return type implements `Future`.
|
||||
let nested = vec![
|
||||
@ -453,11 +466,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
||||
.rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]))
|
||||
.upcast(tcx),
|
||||
];
|
||||
let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None);
|
||||
let future_output_def_id = tcx.require_lang_item(TraitSolverLangItem::FutureOutput);
|
||||
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
|
||||
Ok((
|
||||
bound_sig.rebind(AsyncCallableRelevantTypes {
|
||||
tupled_inputs_ty: Ty::new_tup(tcx, sig.inputs()),
|
||||
tupled_inputs_ty: Ty::new_tup(tcx, &sig.inputs()),
|
||||
output_coroutine_ty: sig.output(),
|
||||
coroutine_return_ty: future_output_ty,
|
||||
}),
|
||||
@ -468,7 +481,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
||||
let args = args.as_closure();
|
||||
let bound_sig = args.sig();
|
||||
let sig = bound_sig.skip_binder();
|
||||
let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
|
||||
let future_trait_def_id = tcx.require_lang_item(TraitSolverLangItem::Future);
|
||||
// `Closure`s only implement `AsyncFn*` when their return type
|
||||
// implements `Future`.
|
||||
let mut nested = vec![
|
||||
@ -486,7 +499,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
||||
}
|
||||
} else {
|
||||
let async_fn_kind_trait_def_id =
|
||||
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
||||
tcx.require_lang_item(TraitSolverLangItem::AsyncFnKindHelper);
|
||||
// When we don't know the closure kind (and therefore also the closure's upvars,
|
||||
// which are computed at the same time), we must delay the computation of the
|
||||
// generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
|
||||
@ -504,7 +517,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
||||
);
|
||||
}
|
||||
|
||||
let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None);
|
||||
let future_output_def_id = tcx.require_lang_item(TraitSolverLangItem::FutureOutput);
|
||||
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
|
||||
Ok((
|
||||
bound_sig.rebind(AsyncCallableRelevantTypes {
|
||||
@ -542,21 +555,21 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
||||
|
||||
ty::Bound(..)
|
||||
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||
bug!("unexpected type `{self_ty}`")
|
||||
panic!("unexpected type `{self_ty:?}`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a coroutine-closure, project to its returned coroutine when we are *certain*
|
||||
/// that the closure's kind is compatible with the goal.
|
||||
fn coroutine_closure_to_certain_coroutine<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn coroutine_closure_to_certain_coroutine<I: Interner>(
|
||||
tcx: I,
|
||||
goal_kind: ty::ClosureKind,
|
||||
goal_region: ty::Region<'tcx>,
|
||||
def_id: DefId,
|
||||
args: ty::CoroutineClosureArgs<TyCtxt<'tcx>>,
|
||||
sig: ty::CoroutineClosureSignature<TyCtxt<'tcx>>,
|
||||
) -> Ty<'tcx> {
|
||||
goal_region: I::Region,
|
||||
def_id: I::DefId,
|
||||
args: ty::CoroutineClosureArgs<I>,
|
||||
sig: ty::CoroutineClosureSignature<I>,
|
||||
) -> I::Ty {
|
||||
sig.to_coroutine_given_kind_and_upvars(
|
||||
tcx,
|
||||
args.parent_args(),
|
||||
@ -573,20 +586,20 @@ fn coroutine_closure_to_certain_coroutine<'tcx>(
|
||||
/// yet what the closure's upvars are.
|
||||
///
|
||||
/// Note that we do not also push a `AsyncFnKindHelper` goal here.
|
||||
fn coroutine_closure_to_ambiguous_coroutine<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn coroutine_closure_to_ambiguous_coroutine<I: Interner>(
|
||||
tcx: I,
|
||||
goal_kind: ty::ClosureKind,
|
||||
goal_region: ty::Region<'tcx>,
|
||||
def_id: DefId,
|
||||
args: ty::CoroutineClosureArgs<TyCtxt<'tcx>>,
|
||||
sig: ty::CoroutineClosureSignature<TyCtxt<'tcx>>,
|
||||
) -> Ty<'tcx> {
|
||||
let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None);
|
||||
goal_region: I::Region,
|
||||
def_id: I::DefId,
|
||||
args: ty::CoroutineClosureArgs<I>,
|
||||
sig: ty::CoroutineClosureSignature<I>,
|
||||
) -> I::Ty {
|
||||
let upvars_projection_def_id = tcx.require_lang_item(TraitSolverLangItem::AsyncFnKindUpvars);
|
||||
let tupled_upvars_ty = Ty::new_projection(
|
||||
tcx,
|
||||
upvars_projection_def_id,
|
||||
[
|
||||
ty::GenericArg::from(args.kind_ty()),
|
||||
I::GenericArg::from(args.kind_ty()),
|
||||
Ty::from_closure_kind(tcx, goal_kind).into(),
|
||||
goal_region.into(),
|
||||
sig.tupled_inputs_ty.into(),
|
||||
@ -643,41 +656,44 @@ fn coroutine_closure_to_ambiguous_coroutine<'tcx>(
|
||||
// This is unsound in general and once that is fixed, we don't need to
|
||||
// normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9
|
||||
// for more details.
|
||||
pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
|
||||
ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
) -> Vec<Goal<'tcx, ty::Predicate<'tcx>>> {
|
||||
pub(in crate::solve) fn predicates_for_object_candidate<Infcx, I>(
|
||||
ecx: &EvalCtxt<'_, Infcx>,
|
||||
param_env: I::ParamEnv,
|
||||
trait_ref: ty::TraitRef<I>,
|
||||
object_bounds: I::BoundExistentialPredicates,
|
||||
) -> Vec<Goal<I, I::Predicate>>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
let tcx = ecx.interner();
|
||||
let mut requirements = vec![];
|
||||
requirements.extend(
|
||||
tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.args).predicates,
|
||||
);
|
||||
for item in tcx.associated_items(trait_ref.def_id).in_definition_order() {
|
||||
// FIXME(associated_const_equality): Also add associated consts to
|
||||
// the requirements here.
|
||||
if item.kind == ty::AssocKind::Type {
|
||||
// associated types that require `Self: Sized` do not show up in the built-in
|
||||
// implementation of `Trait for dyn Trait`, and can be dropped here.
|
||||
if tcx.generics_require_sized_self(item.def_id) {
|
||||
continue;
|
||||
}
|
||||
requirements
|
||||
.extend(tcx.super_predicates_of(trait_ref.def_id).iter_instantiated(tcx, &trait_ref.args));
|
||||
|
||||
requirements
|
||||
.extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, trait_ref.args));
|
||||
// FIXME(associated_const_equality): Also add associated consts to
|
||||
// the requirements here.
|
||||
for associated_type_def_id in tcx.associated_type_def_ids(trait_ref.def_id) {
|
||||
// associated types that require `Self: Sized` do not show up in the built-in
|
||||
// implementation of `Trait for dyn Trait`, and can be dropped here.
|
||||
if tcx.generics_require_sized_self(associated_type_def_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
requirements.extend(
|
||||
tcx.item_bounds(associated_type_def_id).iter_instantiated(tcx, &trait_ref.args),
|
||||
);
|
||||
}
|
||||
|
||||
let mut replace_projection_with = FxHashMap::default();
|
||||
for bound in object_bound {
|
||||
for bound in object_bounds {
|
||||
if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() {
|
||||
let proj = proj.with_self_ty(tcx, trait_ref.self_ty());
|
||||
let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj));
|
||||
assert_eq!(
|
||||
old_ty,
|
||||
None,
|
||||
"{} has two generic parameters: {} and {}",
|
||||
"{:?} has two generic parameters: {:?} and {:?}",
|
||||
proj.projection_term,
|
||||
proj.term,
|
||||
old_ty.unwrap()
|
||||
@ -696,20 +712,22 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
|
||||
.collect()
|
||||
}
|
||||
|
||||
struct ReplaceProjectionWith<'a, 'tcx> {
|
||||
ecx: &'a EvalCtxt<'a, InferCtxt<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
|
||||
nested: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
struct ReplaceProjectionWith<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> {
|
||||
ecx: &'a EvalCtxt<'a, Infcx>,
|
||||
param_env: I::ParamEnv,
|
||||
mapping: FxHashMap<I::DefId, ty::Binder<I, ty::ProjectionPredicate<I>>>,
|
||||
nested: Vec<Goal<I, I::Predicate>>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
|
||||
for ReplaceProjectionWith<'_, Infcx, I>
|
||||
{
|
||||
fn interner(&self) -> I {
|
||||
self.ecx.interner()
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
|
||||
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
|
||||
if let ty::Alias(ty::Projection, alias_ty) = ty.kind()
|
||||
&& let Some(replacement) = self.mapping.get(&alias_ty.def_id)
|
||||
{
|
||||
// We may have a case where our object type's projection bound is higher-ranked,
|
||||
|
@ -1,9 +1,6 @@
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::at::ToTrace;
|
||||
use rustc_infer::infer::{
|
||||
BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt,
|
||||
};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
@ -15,11 +12,13 @@ use rustc_middle::traits::solve::{
|
||||
use rustc_middle::ty::AliasRelationDirection;
|
||||
use rustc_middle::ty::TypeFolder;
|
||||
use rustc_middle::ty::{
|
||||
self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_type_ir::fold::TypeSuperFoldable;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||
use rustc_type_ir::{self as ir, CanonicalVarValues, Interner};
|
||||
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
use std::ops::ControlFlow;
|
||||
@ -456,28 +455,6 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) {
|
||||
goal.predicate = goal
|
||||
.predicate
|
||||
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
|
||||
self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal);
|
||||
self.nested_goals.normalizes_to_goals.push(goal);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(super) fn add_goal(
|
||||
&mut self,
|
||||
source: GoalSource,
|
||||
mut goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
) {
|
||||
goal.predicate = goal
|
||||
.predicate
|
||||
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
|
||||
self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal);
|
||||
self.nested_goals.goals.push((source, goal));
|
||||
}
|
||||
|
||||
// Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning
|
||||
// the certainty of all the goals.
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
@ -600,27 +577,61 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
pub(super) fn interner(&self) -> I {
|
||||
self.infcx.interner()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
pub(super) fn next_ty_infer(&mut self) -> Ty<'tcx> {
|
||||
let ty = self.infcx.next_ty_var(DUMMY_SP);
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
pub(super) fn add_normalizes_to_goal(
|
||||
&mut self,
|
||||
mut goal: ir::solve::Goal<I, ir::NormalizesTo<I>>,
|
||||
) {
|
||||
goal.predicate = goal
|
||||
.predicate
|
||||
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
|
||||
self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal);
|
||||
self.nested_goals.normalizes_to_goals.push(goal);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(super) fn add_goal(
|
||||
&mut self,
|
||||
source: GoalSource,
|
||||
mut goal: ir::solve::Goal<I, I::Predicate>,
|
||||
) {
|
||||
goal.predicate = goal
|
||||
.predicate
|
||||
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
|
||||
self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal);
|
||||
self.nested_goals.goals.push((source, goal));
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, goals))]
|
||||
pub(super) fn add_goals(
|
||||
&mut self,
|
||||
source: GoalSource,
|
||||
goals: impl IntoIterator<Item = ir::solve::Goal<I, I::Predicate>>,
|
||||
) {
|
||||
for goal in goals {
|
||||
self.add_goal(source, goal);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn next_ty_infer(&mut self) -> I::Ty {
|
||||
let ty = self.infcx.next_ty_infer();
|
||||
self.inspect.add_var_value(ty);
|
||||
ty
|
||||
}
|
||||
|
||||
pub(super) fn next_const_infer(&mut self) -> ty::Const<'tcx> {
|
||||
let ct = self.infcx.next_const_var(DUMMY_SP);
|
||||
pub(super) fn next_const_infer(&mut self) -> I::Const {
|
||||
let ct = self.infcx.next_const_infer();
|
||||
self.inspect.add_var_value(ct);
|
||||
ct
|
||||
}
|
||||
|
||||
/// Returns a ty infer or a const infer depending on whether `kind` is a `Ty` or `Const`.
|
||||
/// If `kind` is an integer inference variable this will still return a ty infer var.
|
||||
pub(super) fn next_term_infer_of_kind(&mut self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> {
|
||||
match kind.unpack() {
|
||||
ty::TermKind::Ty(_) => self.next_ty_infer().into(),
|
||||
ty::TermKind::Const(_) => self.next_const_infer().into(),
|
||||
pub(super) fn next_term_infer_of_kind(&mut self, kind: I::Term) -> I::Term {
|
||||
match kind.kind() {
|
||||
ir::TermKind::Ty(_) => self.next_ty_infer().into(),
|
||||
ir::TermKind::Const(_) => self.next_const_infer().into(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,18 +642,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
pub(super) fn term_is_fully_unconstrained(
|
||||
&self,
|
||||
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
|
||||
goal: ir::solve::Goal<I, ir::NormalizesTo<I>>,
|
||||
) -> bool {
|
||||
let universe_of_term = match goal.predicate.term.unpack() {
|
||||
ty::TermKind::Ty(ty) => {
|
||||
if let &ty::Infer(ty::TyVar(vid)) = ty.kind() {
|
||||
let universe_of_term = match goal.predicate.term.kind() {
|
||||
ir::TermKind::Ty(ty) => {
|
||||
if let ir::Infer(ir::TyVar(vid)) = ty.kind() {
|
||||
self.infcx.universe_of_ty(vid).unwrap()
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ty::TermKind::Const(ct) => {
|
||||
if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
|
||||
ir::TermKind::Const(ct) => {
|
||||
if let ir::ConstKind::Infer(ir::InferConst::Var(vid)) = ct.kind() {
|
||||
self.infcx.universe_of_ct(vid).unwrap()
|
||||
} else {
|
||||
return false;
|
||||
@ -650,14 +661,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
}
|
||||
};
|
||||
|
||||
struct ContainsTermOrNotNameable<'a, 'tcx> {
|
||||
term: ty::Term<'tcx>,
|
||||
universe_of_term: ty::UniverseIndex,
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
struct ContainsTermOrNotNameable<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> {
|
||||
term: I::Term,
|
||||
universe_of_term: ir::UniverseIndex,
|
||||
infcx: &'a Infcx,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ContainsTermOrNotNameable<'a, 'tcx> {
|
||||
fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> {
|
||||
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> {
|
||||
fn check_nameable(&self, universe: ir::UniverseIndex) -> ControlFlow<()> {
|
||||
if self.universe_of_term.can_name(universe) {
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
@ -666,21 +677,23 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsTermOrNotNameable<'_, 'tcx> {
|
||||
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeVisitor<I>
|
||||
for ContainsTermOrNotNameable<'_, Infcx, I>
|
||||
{
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
match *t.kind() {
|
||||
ty::Infer(ty::TyVar(vid)) => {
|
||||
if let ty::TermKind::Ty(term) = self.term.unpack()
|
||||
&& let Some(term_vid) = term.ty_vid()
|
||||
&& self.infcx.root_var(vid) == self.infcx.root_var(term_vid)
|
||||
fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
|
||||
match t.kind() {
|
||||
ir::Infer(ir::TyVar(vid)) => {
|
||||
if let ir::TermKind::Ty(term) = self.term.kind()
|
||||
&& let ir::Infer(ir::TyVar(term_vid)) = term.kind()
|
||||
&& self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid)
|
||||
{
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
self.check_nameable(self.infcx.universe_of_ty(vid).unwrap())
|
||||
}
|
||||
}
|
||||
ty::Placeholder(p) => self.check_nameable(p.universe),
|
||||
ir::Placeholder(p) => self.check_nameable(p.universe()),
|
||||
_ => {
|
||||
if t.has_non_region_infer() || t.has_placeholders() {
|
||||
t.super_visit_with(self)
|
||||
@ -691,11 +704,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result {
|
||||
fn visit_const(&mut self, c: I::Const) -> Self::Result {
|
||||
match c.kind() {
|
||||
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
|
||||
if let ty::TermKind::Const(term) = self.term.unpack()
|
||||
&& let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
|
||||
ir::ConstKind::Infer(ir::InferConst::Var(vid)) => {
|
||||
if let ir::TermKind::Const(term) = self.term.kind()
|
||||
&& let ir::ConstKind::Infer(ir::InferConst::Var(term_vid)) = term.kind()
|
||||
&& self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid)
|
||||
{
|
||||
ControlFlow::Break(())
|
||||
@ -703,7 +716,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
self.check_nameable(self.infcx.universe_of_ct(vid).unwrap())
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe),
|
||||
ir::ConstKind::Placeholder(p) => self.check_nameable(p.universe()),
|
||||
_ => {
|
||||
if c.has_non_region_infer() || c.has_placeholders() {
|
||||
c.super_visit_with(self)
|
||||
@ -725,23 +738,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, param_env), ret)]
|
||||
pub(super) fn eq<T: ToTrace<'tcx>>(
|
||||
pub(super) fn eq<T: Relate<I>>(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
param_env: I::ParamEnv,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
self.infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
// New solver ignores DefineOpaqueTypes, so choose Yes for consistency
|
||||
.eq(DefineOpaqueTypes::Yes, lhs, rhs)
|
||||
.map(|InferOk { value: (), obligations }| {
|
||||
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
|
||||
})
|
||||
.map_err(|e| {
|
||||
trace!(?e, "failed to equate");
|
||||
NoSolution
|
||||
})
|
||||
self.relate(param_env, lhs, ir::Variance::Invariant, rhs)
|
||||
}
|
||||
|
||||
/// This should be used when relating a rigid alias with another type.
|
||||
@ -752,10 +755,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
#[instrument(level = "trace", skip(self, param_env), ret)]
|
||||
pub(super) fn relate_rigid_alias_non_alias(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
alias: ty::AliasTerm<'tcx>,
|
||||
variance: ty::Variance,
|
||||
term: ty::Term<'tcx>,
|
||||
param_env: I::ParamEnv,
|
||||
alias: ir::AliasTerm<I>,
|
||||
variance: ir::Variance,
|
||||
term: I::Term,
|
||||
) -> Result<(), NoSolution> {
|
||||
// NOTE: this check is purely an optimization, the structural eq would
|
||||
// always fail if the term is not an inference variable.
|
||||
@ -770,12 +773,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// Alternatively we could modify `Equate` for this case by adding another
|
||||
// variant to `StructurallyRelateAliases`.
|
||||
let identity_args = self.fresh_args_for_item(alias.def_id);
|
||||
let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args);
|
||||
let rigid_ctor = ir::AliasTerm::new(tcx, alias.def_id, identity_args);
|
||||
let ctor_term = rigid_ctor.to_term(tcx);
|
||||
let InferOk { value: (), obligations } = self
|
||||
.infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq_structurally_relating_aliases(term, ctor_term)?;
|
||||
let obligations =
|
||||
self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?;
|
||||
debug_assert!(obligations.is_empty());
|
||||
self.relate(param_env, alias, variance, rigid_ctor)
|
||||
} else {
|
||||
@ -787,58 +788,38 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// unconstrained "return value" or when we're sure that all aliases in
|
||||
/// the types are rigid.
|
||||
#[instrument(level = "trace", skip(self, param_env), ret)]
|
||||
pub(super) fn eq_structurally_relating_aliases<T: ToTrace<'tcx>>(
|
||||
pub(super) fn eq_structurally_relating_aliases<T: Relate<I>>(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
param_env: I::ParamEnv,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
let cause = ObligationCause::dummy();
|
||||
let InferOk { value: (), obligations } =
|
||||
self.infcx.at(&cause, param_env).eq_structurally_relating_aliases(lhs, rhs)?;
|
||||
assert!(obligations.is_empty());
|
||||
let result = self.infcx.eq_structurally_relating_aliases(param_env, lhs, rhs)?;
|
||||
assert_eq!(result, vec![]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, param_env), ret)]
|
||||
pub(super) fn sub<T: ToTrace<'tcx>>(
|
||||
pub(super) fn sub<T: Relate<I>>(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
param_env: I::ParamEnv,
|
||||
sub: T,
|
||||
sup: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
self.infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
// New solver ignores DefineOpaqueTypes, so choose Yes for consistency
|
||||
.sub(DefineOpaqueTypes::Yes, sub, sup)
|
||||
.map(|InferOk { value: (), obligations }| {
|
||||
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
|
||||
})
|
||||
.map_err(|e| {
|
||||
trace!(?e, "failed to subtype");
|
||||
NoSolution
|
||||
})
|
||||
self.relate(param_env, sub, ir::Variance::Covariant, sup)
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, param_env), ret)]
|
||||
pub(super) fn relate<T: ToTrace<'tcx>>(
|
||||
pub(super) fn relate<T: Relate<I>>(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
param_env: I::ParamEnv,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
variance: ir::Variance,
|
||||
rhs: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
self.infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
// New solver ignores DefineOpaqueTypes, so choose Yes for consistency
|
||||
.relate(DefineOpaqueTypes::Yes, lhs, variance, rhs)
|
||||
.map(|InferOk { value: (), obligations }| {
|
||||
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
|
||||
})
|
||||
.map_err(|e| {
|
||||
trace!(?e, "failed to relate");
|
||||
NoSolution
|
||||
})
|
||||
let goals = self.infcx.relate(param_env, lhs, variance, rhs)?;
|
||||
self.add_goals(GoalSource::Misc, goals);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Equates two values returning the nested goals without adding them
|
||||
@ -847,58 +828,47 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// If possible, try using `eq` instead which automatically handles nested
|
||||
/// goals correctly.
|
||||
#[instrument(level = "trace", skip(self, param_env), ret)]
|
||||
pub(super) fn eq_and_get_goals<T: ToTrace<'tcx>>(
|
||||
pub(super) fn eq_and_get_goals<T: Relate<I>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
param_env: I::ParamEnv,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
// New solver ignores DefineOpaqueTypes, so choose Yes for consistency
|
||||
.eq(DefineOpaqueTypes::Yes, lhs, rhs)
|
||||
.map(|InferOk { value: (), obligations }| {
|
||||
obligations.into_iter().map(|o| o.into()).collect()
|
||||
})
|
||||
.map_err(|e| {
|
||||
trace!(?e, "failed to equate");
|
||||
NoSolution
|
||||
})
|
||||
) -> Result<Vec<ir::solve::Goal<I, I::Predicate>>, NoSolution> {
|
||||
self.infcx.relate(param_env, lhs, ir::Variance::Invariant, rhs)
|
||||
}
|
||||
|
||||
pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
|
||||
pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
value: ir::Binder<I, T>,
|
||||
) -> T {
|
||||
self.infcx.instantiate_binder_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
value,
|
||||
)
|
||||
self.infcx.instantiate_binder_with_infer(value)
|
||||
}
|
||||
|
||||
pub(super) fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
|
||||
pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
value: ir::Binder<I, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U {
|
||||
self.infcx.enter_forall(value, f)
|
||||
}
|
||||
|
||||
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
T: TypeFoldable<I>,
|
||||
{
|
||||
self.infcx.resolve_vars_if_possible(value)
|
||||
}
|
||||
|
||||
pub(super) fn fresh_args_for_item(&mut self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
|
||||
let args = self.infcx.fresh_args_for_item(DUMMY_SP, def_id);
|
||||
pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs {
|
||||
let args = self.infcx.fresh_args_for_item(def_id);
|
||||
for arg in args {
|
||||
self.inspect.add_var_value(arg);
|
||||
}
|
||||
args
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) {
|
||||
self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
|
||||
}
|
||||
@ -1096,28 +1066,36 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
///
|
||||
/// This is a performance optimization to more eagerly detect cycles during trait
|
||||
/// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs.
|
||||
struct ReplaceAliasWithInfer<'me, 'a, 'tcx> {
|
||||
ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
struct ReplaceAliasWithInfer<'me, 'a, Infcx, I>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
ecx: &'me mut EvalCtxt<'a, Infcx>,
|
||||
param_env: I::ParamEnv,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
impl<Infcx, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, Infcx, I>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
fn interner(&self) -> I {
|
||||
self.ecx.interner()
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *ty.kind() {
|
||||
ty::Alias(..) if !ty.has_escaping_bound_vars() => {
|
||||
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
|
||||
match ty.kind() {
|
||||
ir::Alias(..) if !ty.has_escaping_bound_vars() => {
|
||||
let infer_ty = self.ecx.next_ty_infer();
|
||||
let normalizes_to = ty::PredicateKind::AliasRelate(
|
||||
let normalizes_to = ir::PredicateKind::AliasRelate(
|
||||
ty.into(),
|
||||
infer_ty.into(),
|
||||
AliasRelationDirection::Equate,
|
||||
);
|
||||
self.ecx.add_goal(
|
||||
GoalSource::Misc,
|
||||
Goal::new(self.interner(), self.param_env, normalizes_to),
|
||||
ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to),
|
||||
);
|
||||
infer_ty
|
||||
}
|
||||
@ -1125,18 +1103,18 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
fn fold_const(&mut self, ct: I::Const) -> I::Const {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
|
||||
ir::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
|
||||
let infer_ct = self.ecx.next_const_infer();
|
||||
let normalizes_to = ty::PredicateKind::AliasRelate(
|
||||
let normalizes_to = ir::PredicateKind::AliasRelate(
|
||||
ct.into(),
|
||||
infer_ct.into(),
|
||||
AliasRelationDirection::Equate,
|
||||
);
|
||||
self.ecx.add_goal(
|
||||
GoalSource::Misc,
|
||||
Goal::new(self.interner(), self.param_env, normalizes_to),
|
||||
ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to),
|
||||
);
|
||||
infer_ct
|
||||
}
|
||||
@ -1144,7 +1122,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
||||
fn fold_predicate(&mut self, predicate: I::Predicate) -> I::Predicate {
|
||||
if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate }
|
||||
}
|
||||
}
|
||||
|
@ -34,10 +34,11 @@ use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
|
||||
/// trees. At the end of trait solving `ProofTreeBuilder::finalize`
|
||||
/// is called to recursively convert the whole structure to a
|
||||
/// finished proof tree.
|
||||
pub(in crate::solve) struct ProofTreeBuilder<
|
||||
pub(in crate::solve) struct ProofTreeBuilder<Infcx, I = <Infcx as InferCtxtLike>::Interner>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
I: Interner = <Infcx as InferCtxtLike>::Interner,
|
||||
> {
|
||||
I: Interner,
|
||||
{
|
||||
_infcx: PhantomData<Infcx>,
|
||||
state: Option<Box<DebugSolver<I>>>,
|
||||
}
|
||||
|
@ -235,17 +235,6 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
#[instrument(level = "trace", skip(self, goals))]
|
||||
fn add_goals(
|
||||
&mut self,
|
||||
source: GoalSource,
|
||||
goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) {
|
||||
for goal in goals {
|
||||
self.add_goal(source, goal);
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`.
|
||||
///
|
||||
/// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`.
|
||||
|
@ -17,7 +17,7 @@ use rustc_middle::ty::NormalizesTo;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{TypeVisitableExt, Upcast};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
|
||||
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
|
||||
|
||||
mod anon_const;
|
||||
mod inherent;
|
||||
@ -719,13 +719,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
|
||||
let coroutine = args.as_coroutine();
|
||||
|
||||
let name = tcx.associated_item(goal.predicate.def_id()).name;
|
||||
let term = if name == sym::Return {
|
||||
let lang_items = tcx.lang_items();
|
||||
let term = if Some(goal.predicate.def_id()) == lang_items.coroutine_return() {
|
||||
coroutine.return_ty().into()
|
||||
} else if name == sym::Yield {
|
||||
} else if Some(goal.predicate.def_id()) == lang_items.coroutine_yield() {
|
||||
coroutine.yield_ty().into()
|
||||
} else {
|
||||
bug!("unexpected associated item `<{self_ty} as Coroutine>::{name}`")
|
||||
bug!(
|
||||
"unexpected associated item `<{self_ty} as Coroutine>::{}`",
|
||||
tcx.item_name(goal.predicate.def_id())
|
||||
)
|
||||
};
|
||||
|
||||
Self::probe_and_consider_implied_clause(
|
||||
|
@ -1373,15 +1373,16 @@ fn confirm_coroutine_candidate<'cx, 'tcx>(
|
||||
coroutine_sig,
|
||||
);
|
||||
|
||||
let name = tcx.associated_item(obligation.predicate.def_id).name;
|
||||
let ty = if name == sym::Return {
|
||||
let lang_items = tcx.lang_items();
|
||||
let ty = if Some(obligation.predicate.def_id) == lang_items.coroutine_return() {
|
||||
return_ty
|
||||
} else if name == sym::Yield {
|
||||
} else if Some(obligation.predicate.def_id) == lang_items.coroutine_yield() {
|
||||
yield_ty
|
||||
} else {
|
||||
span_bug!(
|
||||
tcx.def_span(obligation.predicate.def_id),
|
||||
"unexpected associated type: `Coroutine::{name}`"
|
||||
"unexpected associated type: `Coroutine::{}`",
|
||||
tcx.item_name(obligation.predicate.def_id),
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,23 +1,75 @@
|
||||
use crate::{ConstVid, EffectVid, FloatVid, IntVid, Interner, RegionVid, TyVid, UniverseIndex};
|
||||
use crate::fold::TypeFoldable;
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::{Goal, NoSolution};
|
||||
use crate::{self as ty, Interner};
|
||||
|
||||
pub trait InferCtxtLike {
|
||||
pub trait InferCtxtLike: Sized {
|
||||
type Interner: Interner;
|
||||
|
||||
fn interner(&self) -> Self::Interner;
|
||||
|
||||
fn universe_of_ty(&self, ty: TyVid) -> Option<UniverseIndex>;
|
||||
fn universe_of_lt(&self, lt: RegionVid) -> Option<UniverseIndex>;
|
||||
fn universe_of_ct(&self, ct: ConstVid) -> Option<UniverseIndex>;
|
||||
fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_int_var(&self, vid: IntVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> <Self::Interner as Interner>::Const;
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid;
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid;
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_float_var(
|
||||
&self,
|
||||
vid: ty::FloatVid,
|
||||
) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_ct_var(
|
||||
&self,
|
||||
vid: ty::ConstVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_effect_var(
|
||||
&self,
|
||||
vid: EffectVid,
|
||||
vid: ty::EffectVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> <Self::Interner as Interner>::Region;
|
||||
fn opportunistic_resolve_lt_var(
|
||||
&self,
|
||||
vid: ty::RegionVid,
|
||||
) -> <Self::Interner as Interner>::Region;
|
||||
|
||||
fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
|
||||
|
||||
fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
|
||||
fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
|
||||
fn fresh_args_for_item(
|
||||
&self,
|
||||
def_id: <Self::Interner as Interner>::DefId,
|
||||
) -> <Self::Interner as Interner>::GenericArgs;
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
) -> T;
|
||||
|
||||
fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U;
|
||||
|
||||
fn relate<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<Self::Interner>;
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
||||
{
|
||||
fn new_bool(interner: I) -> Self;
|
||||
|
||||
fn new_u8(interner: I) -> Self;
|
||||
|
||||
fn new_infer(interner: I, var: ty::InferTy) -> Self;
|
||||
|
||||
fn new_var(interner: I, var: ty::TyVid) -> Self;
|
||||
@ -39,6 +41,18 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
||||
|
||||
fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self;
|
||||
|
||||
fn new_projection(
|
||||
interner: I,
|
||||
def_id: I::DefId,
|
||||
args: impl IntoIterator<Item: Into<I::GenericArg>>,
|
||||
) -> Self {
|
||||
Ty::new_alias(
|
||||
interner,
|
||||
ty::AliasTyKind::Projection,
|
||||
ty::AliasTy::new(interner, def_id, args),
|
||||
)
|
||||
}
|
||||
|
||||
fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self;
|
||||
|
||||
fn new_adt(interner: I, adt_def: I::AdtDef, args: I::GenericArgs) -> Self;
|
||||
@ -75,6 +89,12 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
||||
It: Iterator<Item = T>,
|
||||
T: CollectAndApply<Self, Self>;
|
||||
|
||||
fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
|
||||
|
||||
fn new_fn_ptr(interner: I, sig: ty::Binder<I, ty::FnSig<I>>) -> Self;
|
||||
|
||||
fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self;
|
||||
|
||||
fn tuple_fields(self) -> I::Tys;
|
||||
|
||||
fn to_opt_closure_kind(self) -> Option<ty::ClosureKind>;
|
||||
@ -83,11 +103,29 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
||||
|
||||
fn from_coroutine_closure_kind(interner: I, kind: ty::ClosureKind) -> Self;
|
||||
|
||||
fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
|
||||
fn is_ty_var(self) -> bool {
|
||||
matches!(self.kind(), ty::Infer(ty::TyVar(_)))
|
||||
}
|
||||
|
||||
fn new_fn_ptr(interner: I, sig: ty::Binder<I, ty::FnSig<I>>) -> Self;
|
||||
|
||||
fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self;
|
||||
fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> {
|
||||
match self.kind() {
|
||||
ty::FnPtr(sig) => sig,
|
||||
ty::FnDef(def_id, args) => interner.fn_sig(def_id).instantiate(interner, &args),
|
||||
ty::Error(_) => {
|
||||
// ignore errors (#54954)
|
||||
ty::Binder::dummy(ty::FnSig {
|
||||
inputs_and_output: Default::default(),
|
||||
c_variadic: false,
|
||||
safety: I::Safety::safe(),
|
||||
abi: I::Abi::rust(),
|
||||
})
|
||||
}
|
||||
ty::Closure(..) => panic!(
|
||||
"to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`",
|
||||
),
|
||||
_ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Tys<I: Interner<Tys = Self>>:
|
||||
@ -103,12 +141,16 @@ pub trait Tys<I: Interner<Tys = Self>>:
|
||||
fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty);
|
||||
}
|
||||
|
||||
pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq + TypeVisitable<I> {
|
||||
pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq + Relate<I> {
|
||||
fn rust() -> Self;
|
||||
|
||||
/// Whether this ABI is `extern "Rust"`.
|
||||
fn is_rust(self) -> bool;
|
||||
}
|
||||
|
||||
pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq + TypeVisitable<I> {
|
||||
pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq + Relate<I> {
|
||||
fn safe() -> Self;
|
||||
|
||||
fn is_safe(self) -> bool;
|
||||
|
||||
fn prefix_str(self) -> &'static str;
|
||||
@ -122,7 +164,6 @@ pub trait Region<I: Interner<Region = Self>>:
|
||||
+ Into<I::GenericArg>
|
||||
+ IntoKind<Kind = ty::RegionKind<I>>
|
||||
+ Flags
|
||||
+ TypeVisitable<I>
|
||||
+ Relate<I>
|
||||
{
|
||||
fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self;
|
||||
@ -158,12 +199,57 @@ pub trait Const<I: Interner<Const = Self>>:
|
||||
fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>) -> Self;
|
||||
|
||||
fn new_expr(interner: I, expr: I::ExprConst) -> Self;
|
||||
|
||||
fn is_ct_var(self) -> bool {
|
||||
matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_)))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GenericsOf<I: Interner<GenericsOf = Self>> {
|
||||
fn count(&self) -> usize;
|
||||
}
|
||||
|
||||
pub trait GenericArg<I: Interner<GenericArg = Self>>:
|
||||
Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ IntoKind<Kind = ty::GenericArgKind<I>>
|
||||
+ TypeVisitable<I>
|
||||
+ Relate<I>
|
||||
+ From<I::Ty>
|
||||
+ From<I::Region>
|
||||
+ From<I::Const>
|
||||
{
|
||||
}
|
||||
|
||||
pub trait Term<I: Interner<Term = Self>>:
|
||||
Copy + Debug + Hash + Eq + IntoKind<Kind = ty::TermKind<I>> + TypeFoldable<I> + Relate<I>
|
||||
{
|
||||
fn as_type(&self) -> Option<I::Ty> {
|
||||
if let ty::TermKind::Ty(ty) = self.kind() { Some(ty) } else { None }
|
||||
}
|
||||
|
||||
fn expect_type(&self) -> I::Ty {
|
||||
self.as_type().expect("expected a type, but found a const")
|
||||
}
|
||||
|
||||
fn as_const(&self) -> Option<I::Const> {
|
||||
if let ty::TermKind::Const(c) = self.kind() { Some(c) } else { None }
|
||||
}
|
||||
|
||||
fn expect_const(&self) -> I::Const {
|
||||
self.as_const().expect("expected a const, but found a type")
|
||||
}
|
||||
|
||||
fn is_infer(self) -> bool {
|
||||
match self.kind() {
|
||||
ty::TermKind::Ty(ty) => ty.is_ty_var(),
|
||||
ty::TermKind::Const(ct) => ct.is_ct_var(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
|
||||
Copy
|
||||
+ Debug
|
||||
@ -172,7 +258,6 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
|
||||
+ IntoIterator<Item = I::GenericArg>
|
||||
+ Deref<Target: Deref<Target = [I::GenericArg]>>
|
||||
+ Default
|
||||
+ TypeFoldable<I>
|
||||
+ Relate<I>
|
||||
{
|
||||
fn type_at(self, i: usize) -> I::Ty;
|
||||
@ -188,6 +273,16 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
|
||||
fn split_closure_args(self) -> ty::ClosureArgsParts<I>;
|
||||
fn split_coroutine_closure_args(self) -> ty::CoroutineClosureArgsParts<I>;
|
||||
fn split_coroutine_args(self) -> ty::CoroutineArgsParts<I>;
|
||||
|
||||
fn as_closure(self) -> ty::ClosureArgs<I> {
|
||||
ty::ClosureArgs { args: self }
|
||||
}
|
||||
fn as_coroutine_closure(self) -> ty::CoroutineClosureArgs<I> {
|
||||
ty::CoroutineClosureArgs { args: self }
|
||||
}
|
||||
fn as_coroutine(self) -> ty::CoroutineArgs<I> {
|
||||
ty::CoroutineArgs { args: self }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Predicate<I: Interner<Predicate = Self>>:
|
||||
@ -198,9 +293,20 @@ pub trait Predicate<I: Interner<Predicate = Self>>:
|
||||
+ TypeSuperVisitable<I>
|
||||
+ TypeSuperFoldable<I>
|
||||
+ Flags
|
||||
+ UpcastFrom<I, ty::PredicateKind<I>>
|
||||
+ UpcastFrom<I, ty::Binder<I, ty::PredicateKind<I>>>
|
||||
+ UpcastFrom<I, ty::ClauseKind<I>>
|
||||
+ UpcastFrom<I, ty::Binder<I, ty::ClauseKind<I>>>
|
||||
+ UpcastFrom<I, I::Clause>
|
||||
+ UpcastFrom<I, ty::NormalizesTo<I>>
|
||||
+ UpcastFrom<I, ty::TraitRef<I>>
|
||||
+ UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
|
||||
+ IntoKind<Kind = ty::Binder<I, ty::PredicateKind<I>>>
|
||||
{
|
||||
fn is_coinductive(self, interner: I) -> bool;
|
||||
|
||||
// FIXME: Eventually uplift the impl out of rustc and make this defaulted.
|
||||
fn allow_normalization(self) -> bool;
|
||||
}
|
||||
|
||||
pub trait Clause<I: Interner<Clause = Self>>:
|
||||
@ -208,6 +314,7 @@ pub trait Clause<I: Interner<Clause = Self>>:
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ TypeFoldable<I>
|
||||
// FIXME: Remove these, uplift the `Upcast` impls.
|
||||
+ UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
|
||||
+ UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
|
||||
@ -242,8 +349,17 @@ pub trait ParamLike {
|
||||
|
||||
pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
|
||||
fn def_id(self) -> I::DefId;
|
||||
|
||||
fn is_phantom_data(self) -> bool;
|
||||
|
||||
// FIXME: perhaps use `all_fields` and expose `FieldDef`.
|
||||
fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl Iterator<Item = I::Ty>>;
|
||||
|
||||
fn sized_constraint(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>;
|
||||
}
|
||||
|
||||
pub trait Features<I: Interner>: Copy {
|
||||
fn generic_const_exprs(self) -> bool;
|
||||
|
||||
fn coroutine_clone(self) -> bool;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use rustc_ast_ir::Movability;
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
@ -6,6 +7,7 @@ use std::ops::Deref;
|
||||
use crate::fold::TypeFoldable;
|
||||
use crate::inherent::*;
|
||||
use crate::ir_print::IrPrint;
|
||||
use crate::lang_items::TraitSolverLangItem;
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::inspect::CanonicalGoalEvaluationStep;
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
@ -31,20 +33,8 @@ pub trait Interner:
|
||||
|
||||
type GenericArgs: GenericArgs<Self>;
|
||||
type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>;
|
||||
type GenericArg: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ IntoKind<Kind = ty::GenericArgKind<Self>>
|
||||
+ TypeVisitable<Self>
|
||||
+ Relate<Self>;
|
||||
type Term: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ IntoKind<Kind = ty::TermKind<Self>>
|
||||
+ TypeFoldable<Self>
|
||||
+ Relate<Self>;
|
||||
type GenericArg: GenericArg<Self>;
|
||||
type Term: Term<Self>;
|
||||
|
||||
type BoundVarKinds: Copy
|
||||
+ Debug
|
||||
@ -74,11 +64,16 @@ pub trait Interner:
|
||||
|
||||
// Things stored inside of tys
|
||||
type ErrorGuaranteed: Copy + Debug + Hash + Eq;
|
||||
type BoundExistentialPredicates: Copy + Debug + Hash + Eq + Relate<Self>;
|
||||
type BoundExistentialPredicates: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ Relate<Self>
|
||||
+ IntoIterator<Item = ty::Binder<Self, ty::ExistentialPredicate<Self>>>;
|
||||
type AllocId: Copy + Debug + Hash + Eq;
|
||||
type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>;
|
||||
type Safety: Safety<Self> + TypeFoldable<Self> + Relate<Self>;
|
||||
type Abi: Abi<Self> + TypeFoldable<Self> + Relate<Self>;
|
||||
type Safety: Safety<Self>;
|
||||
type Abi: Abi<Self>;
|
||||
|
||||
// Kinds of consts
|
||||
type Const: Const<Self>;
|
||||
@ -153,6 +148,38 @@ pub trait Interner:
|
||||
|
||||
type Features: Features<Self>;
|
||||
fn features(self) -> Self::Features;
|
||||
|
||||
fn bound_coroutine_hidden_types(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
) -> impl IntoIterator<Item = ty::EarlyBinder<Self, ty::Binder<Self, Self::Ty>>>;
|
||||
|
||||
fn fn_sig(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
) -> ty::EarlyBinder<Self, ty::Binder<Self, ty::FnSig<Self>>>;
|
||||
|
||||
fn coroutine_movability(self, def_id: Self::DefId) -> Movability;
|
||||
|
||||
fn coroutine_for_closure(self, def_id: Self::DefId) -> Self::DefId;
|
||||
|
||||
fn generics_require_sized_self(self, def_id: Self::DefId) -> bool;
|
||||
|
||||
fn item_bounds(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
|
||||
|
||||
fn super_predicates_of(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
|
||||
|
||||
fn has_target_features(self, def_id: Self::DefId) -> bool;
|
||||
|
||||
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId;
|
||||
|
||||
fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
|
||||
}
|
||||
|
||||
/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
|
||||
|
8
compiler/rustc_type_ir/src/lang_items.rs
Normal file
8
compiler/rustc_type_ir/src/lang_items.rs
Normal file
@ -0,0 +1,8 @@
|
||||
/// Lang items used by the new trait solver. This can be mapped to whatever internal
|
||||
/// representation of `LangItem`s used in the underlying compiler implementation.
|
||||
pub enum TraitSolverLangItem {
|
||||
Future,
|
||||
FutureOutput,
|
||||
AsyncFnKindHelper,
|
||||
AsyncFnKindUpvars,
|
||||
}
|
@ -32,6 +32,7 @@ pub mod error;
|
||||
pub mod fold;
|
||||
pub mod inherent;
|
||||
pub mod ir_print;
|
||||
pub mod lang_items;
|
||||
pub mod lift;
|
||||
pub mod relate;
|
||||
pub mod solve;
|
||||
|
@ -76,6 +76,7 @@ pub trait Coroutine<R = ()> {
|
||||
/// values which are allowed to be returned each time a coroutine yields.
|
||||
/// For example an iterator-as-a-coroutine would likely have this type as
|
||||
/// `T`, the type being iterated over.
|
||||
#[cfg_attr(not(bootstrap), lang = "coroutine_yield")]
|
||||
type Yield;
|
||||
|
||||
/// The type of value this coroutine returns.
|
||||
@ -84,6 +85,7 @@ pub trait Coroutine<R = ()> {
|
||||
/// `return` statement or implicitly as the last expression of a coroutine
|
||||
/// literal. For example futures would use this as `Result<T, E>` as it
|
||||
/// represents a completed future.
|
||||
#[cfg_attr(not(bootstrap), lang = "coroutine_return")]
|
||||
type Return;
|
||||
|
||||
/// Resumes the execution of this coroutine.
|
||||
|
Loading…
Reference in New Issue
Block a user