Auto merge of #116640 - matthiaskrgr:rollup-xt9r5ir, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #116219 (Relate alias ty with variance) - #116315 (Do not check for impossible predicates in const-prop lint.) - #116436 (Structurally normalize for closure) - #116597 (Prevent showing methods from blanket impls of not available foreign traits to show up in the search results) - #116627 (small cleanup) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
475c71da07
14 changed files with 132 additions and 108 deletions
|
@ -1623,12 +1623,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
.lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder),
|
||||
bounded_ty: self
|
||||
.lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
|
||||
self.lower_param_bound(
|
||||
bound,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
)
|
||||
})),
|
||||
bounds: self.lower_param_bounds(
|
||||
bounds,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
span: self.lower_span(*span),
|
||||
origin: PredicateOrigin::WhereClause,
|
||||
}),
|
||||
|
|
|
@ -56,7 +56,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// closure sooner rather than later, so first examine the expected
|
||||
// type, and see if can glean a closure kind from there.
|
||||
let (expected_sig, expected_kind) = match expected.to_option(self) {
|
||||
Some(ty) => self.deduce_closure_signature(ty),
|
||||
Some(ty) => {
|
||||
self.deduce_closure_signature(self.try_structurally_resolve_type(expr_span, ty))
|
||||
}
|
||||
None => (None, None),
|
||||
};
|
||||
let body = self.tcx.hir().body(closure.body);
|
||||
|
@ -688,8 +690,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn")
|
||||
});
|
||||
|
||||
let closure_span = self.tcx.def_span(expr_def_id);
|
||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
|
||||
let ret_ty = self.try_structurally_resolve_type(closure_span, ret_ty);
|
||||
|
||||
let get_future_output = |predicate: ty::Predicate<'tcx>, span| {
|
||||
// Search for a pending obligation like
|
||||
|
@ -711,8 +714,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let span = self.tcx.def_span(expr_def_id);
|
||||
|
||||
let output_ty = match *ret_ty.kind() {
|
||||
ty::Infer(ty::TyVar(ret_vid)) => {
|
||||
self.obligations_for_self_ty(ret_vid).find_map(|obligation| {
|
||||
|
@ -726,17 +727,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
|
||||
ty::Error(_) => return None,
|
||||
_ => span_bug!(
|
||||
span,
|
||||
closure_span,
|
||||
"async fn generator return type not an inference variable: {ret_ty}"
|
||||
),
|
||||
};
|
||||
|
||||
let output_ty = self.normalize(span, output_ty);
|
||||
let output_ty = self.normalize(closure_span, output_ty);
|
||||
|
||||
// async fn that have opaque types in their return type need to redo the conversion to inference variables
|
||||
// as they fetch the still opaque version from the signature.
|
||||
let InferOk { value: output_ty, obligations } = self
|
||||
.replace_opaque_types_with_inference_vars(output_ty, body_def_id, span, self.param_env);
|
||||
.replace_opaque_types_with_inference_vars(
|
||||
output_ty,
|
||||
body_def_id,
|
||||
closure_span,
|
||||
self.param_env,
|
||||
);
|
||||
self.register_predicates(obligations);
|
||||
|
||||
Some(output_ty)
|
||||
|
|
|
@ -56,7 +56,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
|||
// performing trait matching (which then performs equality
|
||||
// unification).
|
||||
|
||||
relate::relate_args(self, a_arg, b_arg)
|
||||
relate::relate_args_invariantly(self, a_arg, b_arg)
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
|
|
|
@ -183,7 +183,7 @@ where
|
|||
// Avoid fetching the variance if we are in an invariant
|
||||
// context; no need, and it can induce dependency cycles
|
||||
// (e.g., #41849).
|
||||
relate::relate_args(self, a_subst, b_subst)
|
||||
relate::relate_args_invariantly(self, a_subst, b_subst)
|
||||
} else {
|
||||
let tcx = self.tcx();
|
||||
let opt_variances = tcx.variances_of(item_def_id);
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::ty::error::{ExpectedFound, TypeError};
|
|||
use crate::ty::{self, Expr, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable};
|
||||
use crate::ty::{GenericArg, GenericArgKind, GenericArgsRef};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_target::spec::abi;
|
||||
use std::iter;
|
||||
|
@ -134,7 +135,7 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn relate_args<'tcx, R: TypeRelation<'tcx>>(
|
||||
pub fn relate_args_invariantly<'tcx, R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a_arg: GenericArgsRef<'tcx>,
|
||||
b_arg: GenericArgsRef<'tcx>,
|
||||
|
@ -273,7 +274,20 @@ impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> {
|
|||
if a.def_id != b.def_id {
|
||||
Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id)))
|
||||
} else {
|
||||
let args = relation.relate(a.args, b.args)?;
|
||||
let args = match relation.tcx().def_kind(a.def_id) {
|
||||
DefKind::OpaqueTy => relate_args_with_variances(
|
||||
relation,
|
||||
a.def_id,
|
||||
relation.tcx().variances_of(a.def_id),
|
||||
a.args,
|
||||
b.args,
|
||||
false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
|
||||
)?,
|
||||
DefKind::AssocTy | DefKind::AssocConst | DefKind::TyAlias => {
|
||||
relate_args_invariantly(relation, a.args, b.args)?
|
||||
}
|
||||
def => bug!("unknown alias DefKind: {def:?}"),
|
||||
};
|
||||
Ok(relation.tcx().mk_alias_ty(a.def_id, args))
|
||||
}
|
||||
}
|
||||
|
@ -315,7 +329,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
|
|||
if a.def_id != b.def_id {
|
||||
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
|
||||
} else {
|
||||
let args = relate_args(relation, a.args, b.args)?;
|
||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||
Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args))
|
||||
}
|
||||
}
|
||||
|
@ -331,7 +345,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> {
|
|||
if a.def_id != b.def_id {
|
||||
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
|
||||
} else {
|
||||
let args = relate_args(relation, a.args, b.args)?;
|
||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||
Ok(ty::ExistentialTraitRef { def_id: a.def_id, args })
|
||||
}
|
||||
}
|
||||
|
@ -449,7 +463,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||
// All Generator types with the same id represent
|
||||
// the (anonymous) type of the same generator expression. So
|
||||
// all of their regions should be equated.
|
||||
let args = relation.relate(a_args, b_args)?;
|
||||
let args = relate_args_invariantly(relation, a_args, b_args)?;
|
||||
Ok(Ty::new_generator(tcx, a_id, args, movability))
|
||||
}
|
||||
|
||||
|
@ -459,7 +473,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||
// All GeneratorWitness types with the same id represent
|
||||
// the (anonymous) type of the same generator expression. So
|
||||
// all of their regions should be equated.
|
||||
let args = relation.relate(a_args, b_args)?;
|
||||
let args = relate_args_invariantly(relation, a_args, b_args)?;
|
||||
Ok(Ty::new_generator_witness(tcx, a_id, args))
|
||||
}
|
||||
|
||||
|
@ -467,7 +481,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||
// All Closure types with the same id represent
|
||||
// the (anonymous) type of the same closure expression. So
|
||||
// all of their regions should be equated.
|
||||
let args = relation.relate(a_args, b_args)?;
|
||||
let args = relate_args_invariantly(relation, a_args, b_args)?;
|
||||
Ok(Ty::new_closure(tcx, a_id, &args))
|
||||
}
|
||||
|
||||
|
@ -536,24 +550,6 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||
Ok(Ty::new_fn_ptr(tcx, fty))
|
||||
}
|
||||
|
||||
// The args of opaque types may not all be invariant, so we have
|
||||
// to treat them separately from other aliases.
|
||||
(
|
||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, args: a_args, .. }),
|
||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, args: b_args, .. }),
|
||||
) if a_def_id == b_def_id => {
|
||||
let opt_variances = tcx.variances_of(a_def_id);
|
||||
let args = relate_args_with_variances(
|
||||
relation,
|
||||
a_def_id,
|
||||
opt_variances,
|
||||
a_args,
|
||||
b_args,
|
||||
false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
|
||||
)?;
|
||||
Ok(Ty::new_opaque(tcx, a_def_id, args))
|
||||
}
|
||||
|
||||
// Alias tend to mostly already be handled downstream due to normalization.
|
||||
(&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => {
|
||||
let alias_ty = relation.relate(a_data, b_data)?;
|
||||
|
@ -709,7 +705,7 @@ impl<'tcx> Relate<'tcx> for ty::ClosureArgs<'tcx> {
|
|||
a: ty::ClosureArgs<'tcx>,
|
||||
b: ty::ClosureArgs<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::ClosureArgs<'tcx>> {
|
||||
let args = relate_args(relation, a.args, b.args)?;
|
||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||
Ok(ty::ClosureArgs { args })
|
||||
}
|
||||
}
|
||||
|
@ -720,7 +716,7 @@ impl<'tcx> Relate<'tcx> for ty::GeneratorArgs<'tcx> {
|
|||
a: ty::GeneratorArgs<'tcx>,
|
||||
b: ty::GeneratorArgs<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::GeneratorArgs<'tcx>> {
|
||||
let args = relate_args(relation, a.args, b.args)?;
|
||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||
Ok(ty::GeneratorArgs { args })
|
||||
}
|
||||
}
|
||||
|
@ -731,7 +727,7 @@ impl<'tcx> Relate<'tcx> for GenericArgsRef<'tcx> {
|
|||
a: GenericArgsRef<'tcx>,
|
||||
b: GenericArgsRef<'tcx>,
|
||||
) -> RelateResult<'tcx, GenericArgsRef<'tcx>> {
|
||||
relate_args(relation, a, b)
|
||||
relate_args_invariantly(relation, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -835,19 +831,6 @@ impl<'tcx> Relate<'tcx> for Term<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: ty::ProjectionPredicate<'tcx>,
|
||||
b: ty::ProjectionPredicate<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
|
||||
Ok(ty::ProjectionPredicate {
|
||||
projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
|
||||
term: relation.relate(a.term, b.term)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Error handling
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ use rustc_middle::ty::{
|
|||
};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
use crate::const_prop::CanConstProp;
|
||||
use crate::const_prop::ConstPropMachine;
|
||||
|
@ -35,9 +34,9 @@ use crate::MirLint;
|
|||
/// Severely regress performance.
|
||||
const MAX_ALLOC_LIMIT: u64 = 1024;
|
||||
|
||||
pub struct ConstProp;
|
||||
pub struct ConstPropLint;
|
||||
|
||||
impl<'tcx> MirLint<'tcx> for ConstProp {
|
||||
impl<'tcx> MirLint<'tcx> for ConstPropLint {
|
||||
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
if body.tainted_by_errors.is_some() {
|
||||
return;
|
||||
|
@ -49,61 +48,25 @@ impl<'tcx> MirLint<'tcx> for ConstProp {
|
|||
}
|
||||
|
||||
let def_id = body.source.def_id().expect_local();
|
||||
let is_fn_like = tcx.def_kind(def_id).is_fn_like();
|
||||
let is_assoc_const = tcx.def_kind(def_id) == DefKind::AssocConst;
|
||||
let def_kind = tcx.def_kind(def_id);
|
||||
let is_fn_like = def_kind.is_fn_like();
|
||||
let is_assoc_const = def_kind == DefKind::AssocConst;
|
||||
|
||||
// Only run const prop on functions, methods, closures and associated constants
|
||||
if !is_fn_like && !is_assoc_const {
|
||||
// skip anon_const/statics/consts because they'll be evaluated by miri anyway
|
||||
trace!("ConstProp skipped for {:?}", def_id);
|
||||
trace!("ConstPropLint skipped for {:?}", def_id);
|
||||
return;
|
||||
}
|
||||
|
||||
let is_generator = tcx.type_of(def_id.to_def_id()).instantiate_identity().is_generator();
|
||||
// FIXME(welseywiser) const prop doesn't work on generators because of query cycles
|
||||
// computing their layout.
|
||||
if is_generator {
|
||||
trace!("ConstProp skipped for generator {:?}", def_id);
|
||||
if let DefKind::Generator = def_kind {
|
||||
trace!("ConstPropLint skipped for generator {:?}", def_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it's even possible to satisfy the 'where' clauses
|
||||
// for this item.
|
||||
// This branch will never be taken for any normal function.
|
||||
// However, it's possible to `#!feature(trivial_bounds)]` to write
|
||||
// a function with impossible to satisfy clauses, e.g.:
|
||||
// `fn foo() where String: Copy {}`
|
||||
//
|
||||
// We don't usually need to worry about this kind of case,
|
||||
// since we would get a compilation error if the user tried
|
||||
// to call it. However, since we can do const propagation
|
||||
// even without any calls to the function, we need to make
|
||||
// sure that it even makes sense to try to evaluate the body.
|
||||
// If there are unsatisfiable where clauses, then all bets are
|
||||
// off, and we just give up.
|
||||
//
|
||||
// We manually filter the predicates, skipping anything that's not
|
||||
// "global". We are in a potentially generic context
|
||||
// (e.g. we are evaluating a function without substituting generic
|
||||
// parameters, so this filtering serves two purposes:
|
||||
//
|
||||
// 1. We skip evaluating any predicates that we would
|
||||
// never be able prove are unsatisfiable (e.g. `<T as Foo>`
|
||||
// 2. We avoid trying to normalize predicates involving generic
|
||||
// parameters (e.g. `<T as Foo>::MyItem`). This can confuse
|
||||
// the normalization code (leading to cycle errors), since
|
||||
// it's usually never invoked in this way.
|
||||
let predicates = tcx
|
||||
.predicates_of(def_id.to_def_id())
|
||||
.predicates
|
||||
.iter()
|
||||
.filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
|
||||
if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) {
|
||||
trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id);
|
||||
return;
|
||||
}
|
||||
|
||||
trace!("ConstProp starting for {:?}", def_id);
|
||||
trace!("ConstPropLint starting for {:?}", def_id);
|
||||
|
||||
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
|
||||
// constants, instead of just checking for const-folding succeeding.
|
||||
|
@ -112,7 +75,7 @@ impl<'tcx> MirLint<'tcx> for ConstProp {
|
|||
let mut linter = ConstPropagator::new(body, tcx);
|
||||
linter.visit_body(body);
|
||||
|
||||
trace!("ConstProp done for {:?}", def_id);
|
||||
trace!("ConstPropLint done for {:?}", def_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -496,7 +496,7 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
&elaborate_box_derefs::ElaborateBoxDerefs,
|
||||
&generator::StateTransform,
|
||||
&add_retag::AddRetag,
|
||||
&Lint(const_prop_lint::ConstProp),
|
||||
&Lint(const_prop_lint::ConstPropLint),
|
||||
];
|
||||
pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial)));
|
||||
}
|
||||
|
@ -554,8 +554,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
&const_prop::ConstProp,
|
||||
&gvn::GVN,
|
||||
&dataflow_const_prop::DataflowConstProp,
|
||||
//
|
||||
// Const-prop runs unconditionally, but doesn't mutate the MIR at mir-opt-level=0.
|
||||
&const_debuginfo::ConstDebugInfo,
|
||||
&o1(simplify_branches::SimplifyConstCondition::AfterConstProp),
|
||||
&early_otherwise_branch::EarlyOtherwiseBranch,
|
||||
|
|
|
@ -221,16 +221,23 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
|
|||
_ => self.cache.stripped_mod,
|
||||
};
|
||||
|
||||
#[inline]
|
||||
fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool {
|
||||
let krate = def_id.krate;
|
||||
|
||||
cache.masked_crates.contains(&krate) || tcx.is_private_dep(krate)
|
||||
}
|
||||
|
||||
// If the impl is from a masked crate or references something from a
|
||||
// masked crate then remove it completely.
|
||||
if let clean::ImplItem(ref i) = *item.kind &&
|
||||
(self.cache.masked_crates.contains(&item.item_id.krate())
|
||||
|| i.trait_
|
||||
.as_ref()
|
||||
.map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate))
|
||||
.map_or(false, |t| is_from_private_dep(self.tcx, self.cache, t.def_id()))
|
||||
|| i.for_
|
||||
.def_id(self.cache)
|
||||
.map_or(false, |d| self.cache.masked_crates.contains(&d.krate)))
|
||||
.map_or(false, |d| is_from_private_dep(self.tcx, self.cache, d)))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
|
15
tests/rustdoc-js/auxiliary/equivalent.rs
Normal file
15
tests/rustdoc-js/auxiliary/equivalent.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use std::borrow::Borrow;
|
||||
|
||||
pub trait Equivalent<K: ?Sized> {
|
||||
fn equivalent(&self, key: &K) -> bool;
|
||||
}
|
||||
|
||||
impl<Q: ?Sized, K: ?Sized> Equivalent<K> for Q
|
||||
where
|
||||
Q: Eq,
|
||||
K: Borrow<Q>,
|
||||
{
|
||||
fn equivalent(&self, key: &K) -> bool {
|
||||
PartialEq::eq(self, key.borrow())
|
||||
}
|
||||
}
|
9
tests/rustdoc-js/search-non-local-trait-impl.js
Normal file
9
tests/rustdoc-js/search-non-local-trait-impl.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
// exact-check
|
||||
|
||||
// This test ensures that methods from blanket impls of not available foreign traits
|
||||
// don't show up in the search results.
|
||||
|
||||
const EXPECTED = {
|
||||
'query': 'equivalent',
|
||||
'others': [],
|
||||
};
|
8
tests/rustdoc-js/search-non-local-trait-impl.rs
Normal file
8
tests/rustdoc-js/search-non-local-trait-impl.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
// aux-crate:priv:equivalent=equivalent.rs
|
||||
// compile-flags: -Zunstable-options --extern equivalent
|
||||
// edition:2018
|
||||
|
||||
extern crate equivalent;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct LayoutError;
|
14
tests/ui/impl-trait/in-trait/opaque-variances.rs
Normal file
14
tests/ui/impl-trait/in-trait/opaque-variances.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// check-pass
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
|
||||
fn foo<'a: 'a>(x: &'a Vec<i32>) -> impl Sized {
|
||||
()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// in NLL, we want to make sure that the `'a` subst of `foo` does not get
|
||||
// related between `x` and the RHS of the assignment. That would require
|
||||
// that the temp is live for the lifetime of the variable `x`, which of
|
||||
// course is not necessary since `'a` is not captured by the RPIT.
|
||||
let x = foo(&Vec::new());
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
// compile-flags: -Ztrait-solver=next
|
||||
// check-pass
|
||||
|
||||
#![feature(return_position_impl_trait_in_trait)]
|
||||
|
||||
trait Foo {
|
||||
fn test() -> impl Fn(u32) -> u32 {
|
||||
|x| x.count_ones()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,11 @@
|
|||
// compile-flags: -Ztrait-solver=next
|
||||
// check-pass
|
||||
// edition:2021
|
||||
|
||||
#![feature(async_fn_in_trait)]
|
||||
|
||||
trait Foo {
|
||||
async fn bar() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Reference in a new issue