mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Auto merge of #107052 - compiler-errors:rollup-vxr22g5, r=compiler-errors
Rollup of 8 pull requests Successful merges: - #105796 (rustdoc: simplify JS search routine by not messing with lev distance) - #106753 (Make sure that RPITITs are not considered suggestable) - #106917 (Encode const mir for closures if they're const) - #107004 (Implement some candidates for the new solver (redux)) - #107023 (Stop using `BREAK` & `CONTINUE` in compiler) - #107030 (Correct typo) - #107042 (rustdoc: fix corner cases with "?" JS keyboard command) - #107045 (rustdoc: remove redundant CSS rule `#settings .setting-line`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
6ba6d22bdf
@ -225,7 +225,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||
/// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer
|
||||
/// may not have an address.
|
||||
///
|
||||
/// If `ptr` does have a known address, then we return `CONTINUE` and the function call should
|
||||
/// If `ptr` does have a known address, then we return `Continue(())` and the function call should
|
||||
/// proceed as normal.
|
||||
///
|
||||
/// If `ptr` doesn't have an address, but its underlying allocation's alignment is at most
|
||||
@ -273,18 +273,18 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||
ret,
|
||||
StackPopUnwind::NotAllowed,
|
||||
)?;
|
||||
Ok(ControlFlow::BREAK)
|
||||
Ok(ControlFlow::Break(()))
|
||||
} else {
|
||||
// Not alignable in const, return `usize::MAX`.
|
||||
let usize_max = Scalar::from_machine_usize(self.machine_usize_max(), self);
|
||||
self.write_scalar(usize_max, dest)?;
|
||||
self.return_to_block(ret)?;
|
||||
Ok(ControlFlow::BREAK)
|
||||
Ok(ControlFlow::Break(()))
|
||||
}
|
||||
}
|
||||
Err(_addr) => {
|
||||
// The pointer has an address, continue with function call.
|
||||
Ok(ControlFlow::CONTINUE)
|
||||
Ok(ControlFlow::Continue(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ where
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if !ty.needs_subst() {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
match *ty.kind() {
|
||||
@ -48,7 +48,7 @@ where
|
||||
return subst.visit_with(self);
|
||||
}
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ Rust MIR: a lowered representation of Rust.
|
||||
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(let_chains)]
|
||||
|
@ -317,12 +317,12 @@ where
|
||||
_node: G::Node,
|
||||
_prior_status: Option<NodeStatus>,
|
||||
) -> ControlFlow<Self::BreakVal> {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
/// Called after all nodes reachable from this one have been examined.
|
||||
fn node_settled(&mut self, _node: G::Node) -> ControlFlow<Self::BreakVal> {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
/// Behave as if no edges exist from `source` to `target`.
|
||||
@ -346,8 +346,8 @@ where
|
||||
prior_status: Option<NodeStatus>,
|
||||
) -> ControlFlow<Self::BreakVal> {
|
||||
match prior_status {
|
||||
Some(NodeStatus::Visited) => ControlFlow::BREAK,
|
||||
_ => ControlFlow::CONTINUE,
|
||||
Some(NodeStatus::Visited) => ControlFlow::Break(()),
|
||||
_ => ControlFlow::Continue(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(auto_traits)]
|
||||
#![feature(cell_leak)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(extend_one)]
|
||||
#![feature(hash_raw_entry)]
|
||||
#![feature(hasher_prefixfree_extras)]
|
||||
|
@ -267,7 +267,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
debug!(?t, "root_visit_ty");
|
||||
if t == self.opaque_identity_ty {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
|
||||
tcx: self.tcx,
|
||||
@ -282,7 +282,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||
if self.references_parent_regions {
|
||||
ControlFlow::Break(t)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1439,7 +1439,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E
|
||||
match *t.kind() {
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
|
||||
self.0.push(def);
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => t.super_visit_with(self),
|
||||
}
|
||||
|
@ -1428,7 +1428,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
ControlFlow::BREAK
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
|
@ -416,13 +416,13 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
|
||||
if t != self.self_ty_root {
|
||||
for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) {
|
||||
match tcx.impl_polarity(impl_def_id) {
|
||||
ImplPolarity::Negative => return ControlFlow::BREAK,
|
||||
ImplPolarity::Negative => return ControlFlow::Break(()),
|
||||
ImplPolarity::Reservation => {}
|
||||
// FIXME(@lcnr): That's probably not good enough, idk
|
||||
//
|
||||
// We might just want to take the rustdoc code and somehow avoid
|
||||
// explicit impls for `Self`.
|
||||
ImplPolarity::Positive => return ControlFlow::CONTINUE,
|
||||
ImplPolarity::Positive => return ControlFlow::Continue(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -440,7 +440,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => t.super_visit_with(self),
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
|
||||
match *t.kind() {
|
||||
ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => {
|
||||
// projections are not injective
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
ty::Param(data) => {
|
||||
self.parameters.push(Parameter::from(data));
|
||||
@ -76,7 +76,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
|
||||
if let ty::ReEarlyBound(data) = *r {
|
||||
self.parameters.push(Parameter::from(data));
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
|
@ -92,7 +92,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
||||
a.visit_with(self)?;
|
||||
}
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
substs.visit_with(self)
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if t == self.expected_ty {
|
||||
ControlFlow::BREAK
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
@ -543,7 +543,7 @@ impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
|
||||
if let Some(def_id) = preds.principal_def_id() {
|
||||
self.0.insert(def_id);
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => t.super_visit_with(self),
|
||||
}
|
||||
|
@ -849,7 +849,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
|
||||
t.super_visit_with(self);
|
||||
self.target_index.shift_out(1);
|
||||
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
@ -863,7 +863,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -440,16 +440,16 @@ where
|
||||
t: &ty::Binder<'tcx, T>,
|
||||
) -> ControlFlow<Self::BreakTy> {
|
||||
t.super_visit_with(self);
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match *r {
|
||||
// ignore bound regions, keep visiting
|
||||
ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
|
||||
ty::ReLateBound(_, _) => ControlFlow::Continue(()),
|
||||
_ => {
|
||||
(self.op)(r);
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -457,7 +457,7 @@ where
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
// We're only interested in types involving regions
|
||||
if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
match ty.kind() {
|
||||
@ -507,7 +507,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
|
||||
} else if !t.has_non_region_infer() {
|
||||
// All const/type variables in inference types must already be resolved,
|
||||
// no need to visit the contents.
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
// Otherwise, keep visiting.
|
||||
t.super_visit_with(self)
|
||||
@ -178,7 +178,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
|
||||
} else if !ct.has_non_region_infer() {
|
||||
// All const/type variables in inference types must already be resolved,
|
||||
// no need to visit the contents.
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
// Otherwise, keep visiting.
|
||||
ct.super_visit_with(self)
|
||||
|
@ -1147,7 +1147,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if !ty.has_opaque_types() {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
if let ty::Alias(ty::Opaque, ..) = ty.kind() {
|
||||
|
@ -26,7 +26,7 @@ pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
|
||||
__visitor: &mut __V
|
||||
) -> ::std::ops::ControlFlow<__V::BreakTy> {
|
||||
match *self { #body_visit }
|
||||
::std::ops::ControlFlow::CONTINUE
|
||||
::std::ops::ControlFlow::Continue(())
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@ -888,8 +888,8 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Static(..)
|
||||
| DefKind::Const => (true, false),
|
||||
// Full-fledged functions
|
||||
DefKind::AssocFn | DefKind::Fn => {
|
||||
// Full-fledged functions + closures
|
||||
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
|
||||
let generics = tcx.generics_of(def_id);
|
||||
let needs_inline = (generics.requires_monomorphization(tcx)
|
||||
|| tcx.codegen_fn_attrs(def_id).requests_inline())
|
||||
@ -900,15 +900,6 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
|
||||
let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir;
|
||||
(is_const_fn, needs_inline || always_encode_mir)
|
||||
}
|
||||
// Closures can't be const fn.
|
||||
DefKind::Closure => {
|
||||
let generics = tcx.generics_of(def_id);
|
||||
let needs_inline = (generics.requires_monomorphization(tcx)
|
||||
|| tcx.codegen_fn_attrs(def_id).requests_inline())
|
||||
&& tcx.sess.opts.output_types.should_codegen();
|
||||
let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir;
|
||||
(false, needs_inline || always_encode_mir)
|
||||
}
|
||||
// Generators require optimized MIR to compute layout.
|
||||
DefKind::Generator => (false, true),
|
||||
// The others don't have MIR.
|
||||
|
@ -93,7 +93,7 @@ macro_rules! TrivialTypeTraversalImpls {
|
||||
_: &mut F)
|
||||
-> ::std::ops::ControlFlow<F::BreakTy>
|
||||
{
|
||||
::std::ops::ControlFlow::CONTINUE
|
||||
::std::ops::ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
)+
|
||||
@ -219,7 +219,7 @@ macro_rules! EnumTypeTraversalImpl {
|
||||
$($crate::ty::visit::TypeVisitable::visit_with(
|
||||
$variant_arg, $visitor
|
||||
)?;)*
|
||||
::std::ops::ControlFlow::CONTINUE
|
||||
::std::ops::ControlFlow::Continue(())
|
||||
}
|
||||
$($output)*
|
||||
)
|
||||
@ -237,7 +237,7 @@ macro_rules! EnumTypeTraversalImpl {
|
||||
$($crate::ty::visit::TypeVisitable::visit_with(
|
||||
$variant_arg, $visitor
|
||||
)?;)*
|
||||
::std::ops::ControlFlow::CONTINUE
|
||||
::std::ops::ControlFlow::Continue(())
|
||||
}
|
||||
$($output)*
|
||||
)
|
||||
@ -251,7 +251,7 @@ macro_rules! EnumTypeTraversalImpl {
|
||||
@VisitVariants($this, $visitor)
|
||||
input($($input)*)
|
||||
output(
|
||||
$variant => { ::std::ops::ControlFlow::CONTINUE }
|
||||
$variant => { ::std::ops::ControlFlow::Continue(()) }
|
||||
$($output)*
|
||||
)
|
||||
)
|
||||
|
@ -4,6 +4,6 @@ use super::*;
|
||||
|
||||
impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> {
|
||||
fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,13 @@ use std::ops::ControlFlow;
|
||||
|
||||
use crate::ty::{
|
||||
visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, InferConst, InferTy, Opaque,
|
||||
PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
|
||||
PolyTraitPredicate, Projection, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
|
||||
};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::WherePredicate;
|
||||
use rustc_span::Span;
|
||||
@ -443,7 +444,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
|
||||
type BreakTy = ();
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match t.kind() {
|
||||
match *t.kind() {
|
||||
Infer(InferTy::TyVar(_)) if self.infer_suggestable => {}
|
||||
|
||||
FnDef(..)
|
||||
@ -458,9 +459,9 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
|
||||
}
|
||||
|
||||
Alias(Opaque, AliasTy { def_id, .. }) => {
|
||||
let parent = self.tcx.parent(*def_id);
|
||||
if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
|
||||
&& let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = self.tcx.type_of(parent).kind()
|
||||
let parent = self.tcx.parent(def_id);
|
||||
if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent)
|
||||
&& let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *self.tcx.type_of(parent).kind()
|
||||
&& parent_opaque_def_id == def_id
|
||||
{
|
||||
// Okay
|
||||
@ -469,6 +470,12 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Alias(Projection, AliasTy { def_id, .. }) => {
|
||||
if self.tcx.def_kind(def_id) != DefKind::AssocTy {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
}
|
||||
|
||||
Param(param) => {
|
||||
// FIXME: It would be nice to make this not use string manipulation,
|
||||
// but it's pretty hard to do this, since `ty::ParamTy` is missing
|
||||
|
@ -2357,6 +2357,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
self.trait_def(trait_def_id).has_auto_impl
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a trait alias.
|
||||
pub fn trait_is_alias(self, trait_def_id: DefId) -> bool {
|
||||
self.def_kind(trait_def_id) == DefKind::TraitAlias
|
||||
}
|
||||
|
||||
pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
|
||||
self.trait_is_auto(trait_def_id) || self.lang_items().sized_trait() == Some(trait_def_id)
|
||||
}
|
||||
|
@ -2468,7 +2468,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
|
||||
if not_previously_inserted {
|
||||
ty.super_visit_with(self)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -367,7 +367,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::AdtDef<'tcx> {
|
||||
|
||||
impl<'tcx> TypeVisitable<'tcx> for ty::AdtDef<'tcx> {
|
||||
fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -714,7 +714,7 @@ impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> {
|
||||
| ty::Placeholder(..)
|
||||
| ty::Param(..)
|
||||
| ty::Never
|
||||
| ty::Foreign(..) => ControlFlow::CONTINUE,
|
||||
| ty::Foreign(..) => ControlFlow::Continue(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -742,7 +742,7 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Region<'tcx> {
|
||||
|
||||
impl<'tcx> TypeSuperVisitable<'tcx> for ty::Region<'tcx> {
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -844,7 +844,7 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
|
||||
|
||||
impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> {
|
||||
fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2011,7 +2011,7 @@ impl<'tcx> Ty<'tcx> {
|
||||
type BreakTy = ();
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if self.0 == t { ControlFlow::BREAK } else { t.super_visit_with(self) }
|
||||
if self.0 == t { ControlFlow::Break(()) } else { t.super_visit_with(self) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,13 +294,13 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match *r {
|
||||
ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => {
|
||||
if (self.callback)(r) {
|
||||
ControlFlow::BREAK
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -311,7 +311,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
|
||||
ty.super_visit_with(self)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -394,7 +394,7 @@ impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> {
|
||||
if t.outer_exclusive_binder() < self.binder_index
|
||||
|| !self.visited.insert((self.binder_index, t))
|
||||
{
|
||||
return ControlFlow::BREAK;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
match *t.kind() {
|
||||
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
|
||||
@ -512,7 +512,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
|
||||
if t.outer_exclusive_binder() > self.outer_index {
|
||||
ControlFlow::Break(FoundEscapingVars)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -524,7 +524,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
|
||||
if r.bound_at_or_above_binder(self.outer_index) {
|
||||
ControlFlow::Break(FoundEscapingVars)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -547,7 +547,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
|
||||
if predicate.outer_exclusive_binder() > self.outer_index {
|
||||
ControlFlow::Break(FoundEscapingVars)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -575,7 +575,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
||||
if flags.intersects(self.flags) {
|
||||
ControlFlow::Break(FoundFlags)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -585,7 +585,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
||||
if flags.intersects(self.flags) {
|
||||
ControlFlow::Break(FoundFlags)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -596,7 +596,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
||||
if flags.intersects(self.flags) {
|
||||
ControlFlow::Break(FoundFlags)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -605,7 +605,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
||||
if predicate.flags().intersects(self.flags) {
|
||||
ControlFlow::Break(FoundFlags)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -653,7 +653,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
|
||||
// in the normalized form
|
||||
if self.just_constrained {
|
||||
if let ty::Alias(..) = t.kind() {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
}
|
||||
|
||||
@ -666,7 +666,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
|
||||
// in the normalized form
|
||||
if self.just_constrained {
|
||||
if let ty::ConstKind::Unevaluated(..) = c.kind() {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
}
|
||||
|
||||
@ -679,7 +679,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
|
||||
self.regions.insert(br.kind);
|
||||
}
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -726,6 +726,6 @@ impl<'tcx> TypeVisitor<'tcx> for MaxUniverse {
|
||||
);
|
||||
}
|
||||
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
#![feature(assert_matches)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
|
@ -118,7 +118,7 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
|
||||
// A diverging InlineAsm is treated as non-recursing
|
||||
TerminatorKind::InlineAsm { destination, .. } => {
|
||||
if destination.is_some() {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
ControlFlow::Break(NonRecursive)
|
||||
}
|
||||
@ -132,7 +132,7 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
|
||||
| TerminatorKind::FalseEdge { .. }
|
||||
| TerminatorKind::FalseUnwind { .. }
|
||||
| TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::SwitchInt { .. } => ControlFlow::CONTINUE,
|
||||
| TerminatorKind::SwitchInt { .. } => ControlFlow::Continue(()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
|
||||
|
@ -1,5 +1,4 @@
|
||||
#![feature(array_windows)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![recursion_limit = "256"]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
|
@ -300,20 +300,20 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if !c.has_non_region_param() {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
match c.kind() {
|
||||
ty::ConstKind::Param(param) => {
|
||||
debug!(?param);
|
||||
self.unused_parameters.mark_used(param.index);
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs })
|
||||
if matches!(self.tcx.def_kind(def.did), DefKind::AnonConst) =>
|
||||
{
|
||||
self.visit_child_body(def.did, substs);
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => c.super_visit_with(self),
|
||||
}
|
||||
@ -322,7 +322,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if !ty.has_non_region_param() {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
match *ty.kind() {
|
||||
@ -330,18 +330,18 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
debug!(?def_id);
|
||||
// Avoid cycle errors with generators.
|
||||
if def_id == self.def_id {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
// Consider any generic parameters used by any closures/generators as used in the
|
||||
// parent.
|
||||
self.visit_child_body(def_id, substs);
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
ty::Param(param) => {
|
||||
debug!(?param);
|
||||
self.unused_parameters.mark_used(param.index);
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(let_chains)]
|
||||
@ -112,7 +111,11 @@ where
|
||||
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<V::BreakTy> {
|
||||
let TraitRef { def_id, substs, .. } = trait_ref;
|
||||
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?;
|
||||
if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
|
||||
if self.def_id_visitor.shallow() {
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
substs.visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<V::BreakTy> {
|
||||
@ -131,7 +134,7 @@ where
|
||||
};
|
||||
self.visit_trait(trait_ref)?;
|
||||
if self.def_id_visitor.shallow() {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
assoc_substs.iter().try_for_each(|subst| subst.visit_with(self))
|
||||
}
|
||||
@ -155,7 +158,7 @@ where
|
||||
ty,
|
||||
_region,
|
||||
))) => ty.visit_with(self),
|
||||
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::CONTINUE,
|
||||
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::Continue(()),
|
||||
ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self),
|
||||
ty::PredicateKind::WellFormed(arg) => arg.visit_with(self),
|
||||
_ => bug!("unexpected predicate: {:?}", predicate),
|
||||
@ -189,7 +192,7 @@ where
|
||||
| ty::Generator(def_id, ..) => {
|
||||
self.def_id_visitor.visit_def_id(def_id, "type", &ty)?;
|
||||
if self.def_id_visitor.shallow() {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
// Default type visitor doesn't visit signatures of fn types.
|
||||
// Something like `fn() -> Priv {my_func}` is considered a private type even if
|
||||
@ -214,7 +217,7 @@ where
|
||||
// as visible/reachable even if both `Type` and `Trait` are private.
|
||||
// Ideally, associated types should be substituted in the same way as
|
||||
// free type aliases, but this isn't done yet.
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
// This will also visit substs if necessary, so we don't need to recurse.
|
||||
return self.visit_projection_ty(proj);
|
||||
@ -274,7 +277,7 @@ where
|
||||
}
|
||||
|
||||
if self.def_id_visitor.shallow() {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
@ -319,7 +322,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL>
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
self.min = VL::new_min(self, def_id);
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -881,7 +884,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx>
|
||||
self.ev.update(def_id, self.level);
|
||||
}
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1368,9 +1371,9 @@ impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
||||
descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<Self::BreakTy> {
|
||||
if self.check_def_id(def_id, kind, descr) {
|
||||
ControlFlow::BREAK
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1865,9 +1868,9 @@ impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
|
||||
descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<Self::BreakTy> {
|
||||
if self.check_def_id(def_id, kind, descr) {
|
||||
ControlFlow::BREAK
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
//! Code shared by trait and projection goals for candidate assembly.
|
||||
|
||||
use super::infcx_ext::InferCtxtExt;
|
||||
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal};
|
||||
use super::{CanonicalResponse, EvalCtxt, Goal, QueryResult};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::util::elaborate_predicates;
|
||||
use rustc_middle::ty::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use std::fmt::Debug;
|
||||
@ -89,19 +90,35 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy {
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
impl_def_id: DefId,
|
||||
) -> Result<Certainty, NoSolution>;
|
||||
|
||||
fn consider_builtin_sized_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Certainty, NoSolution>;
|
||||
) -> QueryResult<'tcx>;
|
||||
|
||||
fn consider_assumption(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Predicate<'tcx>,
|
||||
) -> Result<Certainty, NoSolution>;
|
||||
) -> QueryResult<'tcx>;
|
||||
|
||||
fn consider_auto_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
|
||||
fn consider_trait_alias_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
|
||||
fn consider_builtin_sized_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
|
||||
fn consider_builtin_copy_clone_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
|
||||
&mut self,
|
||||
@ -119,6 +136,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
|
||||
self.assemble_alias_bound_candidates(goal, &mut candidates);
|
||||
|
||||
self.assemble_object_bound_candidates(goal, &mut candidates);
|
||||
|
||||
candidates
|
||||
}
|
||||
|
||||
@ -180,9 +199,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
tcx.for_each_relevant_impl(
|
||||
goal.predicate.trait_def_id(tcx),
|
||||
goal.predicate.self_ty(),
|
||||
|impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id)
|
||||
.and_then(|certainty| self.make_canonical_response(certainty))
|
||||
{
|
||||
|impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) {
|
||||
Ok(result) => candidates
|
||||
.push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
|
||||
Err(NoSolution) => (),
|
||||
@ -197,13 +214,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
) {
|
||||
let lang_items = self.tcx().lang_items();
|
||||
let trait_def_id = goal.predicate.trait_def_id(self.tcx());
|
||||
let result = if lang_items.sized_trait() == Some(trait_def_id) {
|
||||
let result = if self.tcx().trait_is_auto(trait_def_id) {
|
||||
G::consider_auto_trait_candidate(self, goal)
|
||||
} else if self.tcx().trait_is_alias(trait_def_id) {
|
||||
G::consider_trait_alias_candidate(self, goal)
|
||||
} else if lang_items.sized_trait() == Some(trait_def_id) {
|
||||
G::consider_builtin_sized_candidate(self, goal)
|
||||
} else if lang_items.copy_trait() == Some(trait_def_id)
|
||||
|| lang_items.clone_trait() == Some(trait_def_id)
|
||||
{
|
||||
G::consider_builtin_copy_clone_candidate(self, goal)
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
};
|
||||
|
||||
match result.and_then(|certainty| self.make_canonical_response(certainty)) {
|
||||
match result {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
|
||||
}
|
||||
@ -217,9 +242,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
candidates: &mut Vec<Candidate<'tcx>>,
|
||||
) {
|
||||
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
|
||||
match G::consider_assumption(self, goal, assumption)
|
||||
.and_then(|certainty| self.make_canonical_response(certainty))
|
||||
{
|
||||
match G::consider_assumption(self, goal, assumption) {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
|
||||
}
|
||||
@ -268,9 +291,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
.subst_iter_copied(self.tcx(), alias_ty.substs)
|
||||
.enumerate()
|
||||
{
|
||||
match G::consider_assumption(self, goal, assumption)
|
||||
.and_then(|certainty| self.make_canonical_response(certainty))
|
||||
{
|
||||
match G::consider_assumption(self, goal, assumption) {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::AliasBound(i), result })
|
||||
}
|
||||
@ -278,4 +299,52 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<'tcx>>,
|
||||
) {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let bounds = match *self_ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(_)
|
||||
| ty::Alias(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(_)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::Param(_)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Infer(_)
|
||||
| ty::Error(_) => return,
|
||||
ty::Bound(..) => bug!("unexpected bound type: {goal:?}"),
|
||||
ty::Dynamic(bounds, ..) => bounds,
|
||||
};
|
||||
|
||||
let tcx = self.tcx();
|
||||
for assumption in
|
||||
elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)))
|
||||
{
|
||||
match G::consider_assumption(self, goal, assumption.predicate) {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
|
||||
}
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
use rustc_infer::infer::at::ToTrace;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{InferCtxt, InferOk};
|
||||
use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, Ty, TypeFoldable};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
use super::Goal;
|
||||
@ -25,6 +25,11 @@ pub(super) trait InferCtxtExt<'tcx> {
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>;
|
||||
|
||||
fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
) -> T;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
@ -59,4 +64,15 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
NoSolution
|
||||
})
|
||||
}
|
||||
|
||||
fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
) -> T {
|
||||
self.replace_bound_vars_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
LateBoundRegionConversionTime::HigherRankedType,
|
||||
value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -313,6 +313,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn evaluate_all_and_make_canonical_response(
|
||||
&mut self,
|
||||
goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty))
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(infcx), ret)]
|
||||
|
@ -23,7 +23,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
&mut self,
|
||||
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
// To only compute normalization ones for each projection we only
|
||||
// To only compute normalization once for each projection we only
|
||||
// normalize if the expected term is an unconstrained inference variable.
|
||||
//
|
||||
// E.g. for `<T as Trait>::Assoc = u32` we recursively compute the goal
|
||||
@ -191,7 +191,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
|
||||
impl_def_id: DefId,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
) -> QueryResult<'tcx> {
|
||||
let tcx = ecx.tcx();
|
||||
|
||||
let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
|
||||
@ -229,7 +229,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||
impl_def_id
|
||||
)? else {
|
||||
let certainty = Certainty::Maybe(MaybeCause::Ambiguity);
|
||||
return Ok(trait_ref_certainty.unify_and(certainty));
|
||||
return ecx.make_canonical_response(trait_ref_certainty.unify_and(certainty));
|
||||
};
|
||||
|
||||
if !assoc_def.item.defaultness(tcx).has_value() {
|
||||
@ -286,27 +286,70 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||
let rhs_certainty =
|
||||
ecx.evaluate_all(nested_goals).expect("failed to unify with unconstrained term");
|
||||
|
||||
Ok(trait_ref_certainty.unify_and(rhs_certainty))
|
||||
ecx.make_canonical_response(trait_ref_certainty.unify_and(rhs_certainty))
|
||||
})
|
||||
}
|
||||
|
||||
fn consider_assumption(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Predicate<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() {
|
||||
ecx.infcx.probe(|_| {
|
||||
let assumption_projection_pred =
|
||||
ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred);
|
||||
let nested_goals = ecx.infcx.eq(
|
||||
goal.param_env,
|
||||
goal.predicate.projection_ty,
|
||||
assumption_projection_pred.projection_ty,
|
||||
)?;
|
||||
let subst_certainty = ecx.evaluate_all(nested_goals)?;
|
||||
|
||||
// The term of our goal should be fully unconstrained, so this should never fail.
|
||||
//
|
||||
// It can however be ambiguous when the resolved type is a projection.
|
||||
let nested_goals = ecx
|
||||
.infcx
|
||||
.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
|
||||
.expect("failed to unify with unconstrained term");
|
||||
let rhs_certainty = ecx
|
||||
.evaluate_all(nested_goals)
|
||||
.expect("failed to unify with unconstrained term");
|
||||
|
||||
ecx.make_canonical_response(subst_certainty.unify_and(rhs_certainty))
|
||||
})
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
|
||||
fn consider_auto_trait_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
bug!("auto traits do not have associated types: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_trait_alias_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
bug!("trait aliases do not have associated types: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_sized_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
) -> QueryResult<'tcx> {
|
||||
bug!("`Sized` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_assumption(
|
||||
fn consider_builtin_copy_clone_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
_goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Predicate<'tcx>,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
if let Some(_poly_projection_pred) = assumption.to_opt_poly_projection_pred() {
|
||||
unimplemented!()
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,14 +4,17 @@ use std::iter;
|
||||
|
||||
use super::assembly::{self, Candidate, CandidateSource};
|
||||
use super::infcx_ext::InferCtxtExt;
|
||||
use super::{Certainty, EvalCtxt, Goal, QueryResult};
|
||||
use super::{EvalCtxt, Goal, QueryResult};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
use rustc_middle::ty::TraitPredicate;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
mod structural_traits;
|
||||
|
||||
impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn self_ty(self) -> Ty<'tcx> {
|
||||
self.self_ty()
|
||||
@ -29,7 +32,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||
impl_def_id: DefId,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
) -> QueryResult<'tcx> {
|
||||
let tcx = ecx.tcx();
|
||||
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
@ -53,31 +56,104 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
.into_iter()
|
||||
.map(|pred| goal.with(tcx, pred));
|
||||
nested_goals.extend(where_clause_bounds);
|
||||
ecx.evaluate_all(nested_goals)
|
||||
ecx.evaluate_all_and_make_canonical_response(nested_goals)
|
||||
})
|
||||
}
|
||||
|
||||
fn consider_builtin_sized_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
_goal: Goal<'tcx, Self>,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn consider_assumption(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
_goal: Goal<'tcx, Self>,
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Predicate<'tcx>,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
if let Some(_poly_trait_pred) = assumption.to_opt_poly_trait_pred() {
|
||||
unimplemented!()
|
||||
) -> QueryResult<'tcx> {
|
||||
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() {
|
||||
// FIXME: Constness and polarity
|
||||
ecx.infcx.probe(|_| {
|
||||
let assumption_trait_pred =
|
||||
ecx.infcx.instantiate_bound_vars_with_infer(poly_trait_pred);
|
||||
let nested_goals = ecx.infcx.eq(
|
||||
goal.param_env,
|
||||
goal.predicate.trait_ref,
|
||||
assumption_trait_pred.trait_ref,
|
||||
)?;
|
||||
ecx.evaluate_all_and_make_canonical_response(nested_goals)
|
||||
})
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
|
||||
fn consider_auto_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||
goal,
|
||||
structural_traits::instantiate_constituent_tys_for_auto_trait,
|
||||
)
|
||||
}
|
||||
|
||||
fn consider_trait_alias_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let tcx = ecx.tcx();
|
||||
|
||||
ecx.infcx.probe(|_| {
|
||||
let nested_obligations = tcx
|
||||
.predicates_of(goal.predicate.def_id())
|
||||
.instantiate(tcx, goal.predicate.trait_ref.substs);
|
||||
ecx.evaluate_all_and_make_canonical_response(
|
||||
nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)).collect(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn consider_builtin_sized_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||
goal,
|
||||
structural_traits::instantiate_constituent_tys_for_sized_trait,
|
||||
)
|
||||
}
|
||||
|
||||
fn consider_builtin_copy_clone_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||
goal,
|
||||
structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
/// Convenience function for traits that are structural, i.e. that only
|
||||
/// have nested subgoals that only change the self type. Unlike other
|
||||
/// evaluate-like helpers, this does a probe, so it doesn't need to be
|
||||
/// wrapped in one.
|
||||
fn probe_and_evaluate_goal_for_constituent_tys(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||
constituent_tys: impl Fn(&InferCtxt<'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
|
||||
) -> QueryResult<'tcx> {
|
||||
self.infcx.probe(|_| {
|
||||
self.evaluate_all_and_make_canonical_response(
|
||||
constituent_tys(self.infcx, goal.predicate.self_ty())?
|
||||
.into_iter()
|
||||
.map(|ty| {
|
||||
goal.with(
|
||||
self.tcx(),
|
||||
ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn compute_trait_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||
|
@ -0,0 +1,179 @@
|
||||
use rustc_hir::{Movability, Mutability};
|
||||
use rustc_infer::{infer::InferCtxt, traits::query::NoSolution};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
||||
// Calculates the constituent types of a type for `auto trait` purposes.
|
||||
//
|
||||
// For types with an "existential" binder, i.e. generator witnesses, we also
|
||||
// instantiate the binder with placeholders eagerly.
|
||||
pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
||||
let tcx = infcx.tcx;
|
||||
match *ty.kind() {
|
||||
ty::Uint(_)
|
||||
| ty::Int(_)
|
||||
| ty::Bool
|
||||
| ty::Float(_)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(_)
|
||||
| ty::Str
|
||||
| ty::Error(_)
|
||||
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||
| ty::Never
|
||||
| ty::Char => Ok(vec![]),
|
||||
|
||||
ty::Placeholder(..)
|
||||
| ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Alias(ty::Projection, ..)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(ty::TyVar(_)) => {
|
||||
// FIXME: Do we need to mark anything as ambiguous here? Yeah?
|
||||
Err(NoSolution)
|
||||
}
|
||||
|
||||
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
|
||||
|
||||
ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
|
||||
Ok(vec![element_ty])
|
||||
}
|
||||
|
||||
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
|
||||
|
||||
ty::Tuple(ref tys) => {
|
||||
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
|
||||
Ok(tys.iter().collect())
|
||||
}
|
||||
|
||||
ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
|
||||
|
||||
ty::Generator(_, ref substs, _) => {
|
||||
let generator_substs = substs.as_generator();
|
||||
Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()])
|
||||
}
|
||||
|
||||
ty::GeneratorWitness(types) => {
|
||||
Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
|
||||
}
|
||||
|
||||
// For `PhantomData<T>`, we pass `T`.
|
||||
ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]),
|
||||
|
||||
ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()),
|
||||
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||
// 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![tcx.bound_type_of(def_id).subst(tcx, substs)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
||||
match *ty.kind() {
|
||||
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||
| ty::Uint(_)
|
||||
| ty::Int(_)
|
||||
| ty::Bool
|
||||
| ty::Float(_)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(_)
|
||||
| ty::RawPtr(..)
|
||||
| ty::Char
|
||||
| ty::Ref(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::Array(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Never
|
||||
| ty::Dynamic(_, _, ty::DynStar)
|
||||
| ty::Error(_) => Ok(vec![]),
|
||||
|
||||
ty::Str
|
||||
| ty::Slice(_)
|
||||
| ty::Dynamic(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Alias(..)
|
||||
| ty::Param(_) => Err(NoSolution),
|
||||
|
||||
ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
|
||||
|
||||
ty::Placeholder(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
|
||||
|
||||
ty::Tuple(tys) => Ok(tys.to_vec()),
|
||||
|
||||
ty::Adt(def, substs) => {
|
||||
let sized_crit = def.sized_constraint(infcx.tcx);
|
||||
Ok(sized_crit
|
||||
.0
|
||||
.iter()
|
||||
.map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs))
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
||||
match *ty.kind() {
|
||||
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(_)
|
||||
| ty::Error(_) => Ok(vec![]),
|
||||
|
||||
// Implementations are provided in core
|
||||
ty::Uint(_)
|
||||
| ty::Int(_)
|
||||
| ty::Bool
|
||||
| ty::Float(_)
|
||||
| ty::Char
|
||||
| ty::RawPtr(..)
|
||||
| ty::Never
|
||||
| ty::Ref(_, _, Mutability::Not)
|
||||
| ty::Array(..) => Err(NoSolution),
|
||||
|
||||
ty::Dynamic(..)
|
||||
| ty::Str
|
||||
| ty::Slice(_)
|
||||
| ty::Generator(_, _, Movability::Static)
|
||||
| ty::Foreign(..)
|
||||
| ty::Ref(_, _, Mutability::Mut)
|
||||
| ty::Adt(_, _)
|
||||
| ty::Alias(_, _)
|
||||
| ty::Param(_) => Err(NoSolution),
|
||||
|
||||
ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
|
||||
|
||||
ty::Placeholder(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
|
||||
|
||||
ty::Tuple(tys) => Ok(tys.to_vec()),
|
||||
|
||||
ty::Closure(_, substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
|
||||
|
||||
ty::Generator(_, substs, Movability::Movable) => {
|
||||
if infcx.tcx.features().generator_clone {
|
||||
let generator = substs.as_generator();
|
||||
Ok(vec![generator.tupled_upvars_ty(), generator.witness()])
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
|
||||
ty::GeneratorWitness(types) => {
|
||||
Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
|
||||
}
|
||||
}
|
||||
}
|
@ -614,12 +614,12 @@ impl<'tcx> OrphanChecker<'tcx> {
|
||||
|
||||
fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> {
|
||||
self.non_local_tys.push((t, self.in_self_ty));
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> {
|
||||
if self.search_first_local_ty {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t))
|
||||
}
|
||||
@ -641,7 +641,7 @@ enum OrphanCheckEarlyExit<'tcx> {
|
||||
impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
|
||||
type BreakTy = OrphanCheckEarlyExit<'tcx>;
|
||||
fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
@ -756,6 +756,6 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
|
||||
/// parameters, allowing uncovered const parameters in impls seems more useful
|
||||
/// than allowing `impl<T> Trait<local_fn_ptr, T> for i32` to compile.
|
||||
fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ fn satisfied_from_param_env<'tcx>(
|
||||
// If we start allowing directly writing `ConstKind::Expr` without an intermediate anon const
|
||||
// this will be incorrect. It might be worth investigating making `predicates_of` elaborate
|
||||
// all of the `ConstEvaluatable` bounds rather than having a visitor here.
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2932,7 +2932,7 @@ impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor {
|
||||
if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -493,7 +493,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI
|
||||
&& let param_def_id = self.generics.type_param(param, self.tcx).def_id
|
||||
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
|
||||
{
|
||||
return ControlFlow::BREAK;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
@ -502,7 +502,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI
|
||||
&& let param_def_id = self.generics.region_param(¶m, self.tcx).def_id
|
||||
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
|
||||
{
|
||||
return ControlFlow::BREAK;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
r.super_visit_with(self)
|
||||
}
|
||||
@ -511,7 +511,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI
|
||||
&& let param_def_id = self.generics.const_param(¶m, self.tcx).def_id
|
||||
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
|
||||
{
|
||||
return ControlFlow::BREAK;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
ct.super_visit_with(self)
|
||||
}
|
||||
|
@ -783,16 +783,16 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
|
||||
match t.kind() {
|
||||
ty::Param(_) => {
|
||||
if t == self.tcx.types.self_param {
|
||||
ControlFlow::BREAK
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
ty::Alias(ty::Projection, ref data)
|
||||
if self.tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder =>
|
||||
{
|
||||
// We'll deny these later in their own pass
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
ty::Alias(ty::Projection, ref data) => {
|
||||
// This is a projected type `<Foo as SomeTrait>::X`.
|
||||
@ -820,7 +820,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
|
||||
.contains(&data.trait_ref(self.tcx).def_id);
|
||||
|
||||
if is_supertrait_of_current_trait {
|
||||
ControlFlow::CONTINUE // do not walk contained types, do not report error, do collect $200
|
||||
ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200
|
||||
} else {
|
||||
t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
|
||||
.escaping
|
||||
.max(t.outer_exclusive_binder().as_usize() - self.outer_index.as_usize());
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -145,7 +145,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
@ -153,7 +153,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
|
||||
ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
|
||||
self.escaping =
|
||||
self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
|
||||
ControlFlow::CONTINUE
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => ct.super_visit_with(self),
|
||||
}
|
||||
|
@ -107,25 +107,25 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
|
||||
ty::FnDef(..) => {
|
||||
// Types of formals and return in `fn(_) -> _` are also irrelevant;
|
||||
// so we do not recur into them via `super_visit_with`
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
ty::Array(_, n)
|
||||
if { n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } =>
|
||||
{
|
||||
// rust-lang/rust#62336: ignore type of contents
|
||||
// for empty array.
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => {
|
||||
// These primitive types are always structural match.
|
||||
//
|
||||
// `Never` is kind of special here, but as it is not inhabitable, this should be fine.
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
ty::FnPtr(..) => {
|
||||
if !self.adt_const_param {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
} else {
|
||||
return ControlFlow::Break(ty);
|
||||
}
|
||||
@ -147,7 +147,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
|
||||
// Even though `NonStructural` does not implement `PartialEq`,
|
||||
// structural equality on `T` does not recur into the raw
|
||||
// pointer. Therefore, one can still use `C` in a pattern.
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
} else {
|
||||
return ControlFlow::Break(ty);
|
||||
}
|
||||
@ -155,7 +155,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
|
||||
|
||||
ty::Float(_) => {
|
||||
if !self.adt_const_param {
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
} else {
|
||||
return ControlFlow::Break(ty);
|
||||
}
|
||||
@ -172,13 +172,13 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
|
||||
self.tcx.sess.delay_span_bug(self.span, "ty::Error in structural-match check");
|
||||
// We still want to check other types after encountering an error,
|
||||
// as this may still emit relevant errors.
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
};
|
||||
|
||||
if !self.seen.insert(adt_def.did()) {
|
||||
debug!("Search already seen adt_def: {:?}", adt_def);
|
||||
return ControlFlow::CONTINUE;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
if !self.type_marked_structural(ty) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![feature(alloc_layout_extra, control_flow_enum, decl_macro, iterator_try_reduce, never_type)]
|
||||
#![feature(alloc_layout_extra, decl_macro, iterator_try_reduce, never_type)]
|
||||
#![allow(dead_code, unused_variables)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![feature(let_chains)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(never_type)]
|
||||
#![feature(box_patterns)]
|
||||
#![recursion_limit = "256"]
|
||||
|
@ -1,5 +1,5 @@
|
||||
.setting-line {
|
||||
margin: 0.6em 0 0.6em 0.3em;
|
||||
margin: 1.2em 0.6em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@ -55,10 +55,6 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#settings .setting-line {
|
||||
margin: 1.2em 0.6em;
|
||||
}
|
||||
|
||||
.setting-line .radio-line input:checked {
|
||||
box-shadow: inset 0 0 0 3px var(--main-background-color);
|
||||
background-color: var(--settings-input-color);
|
||||
|
@ -390,7 +390,8 @@ function loadCss(cssUrl) {
|
||||
}
|
||||
|
||||
if (document.activeElement.tagName === "INPUT" &&
|
||||
document.activeElement.type !== "checkbox") {
|
||||
document.activeElement.type !== "checkbox" &&
|
||||
document.activeElement.type !== "radio") {
|
||||
switch (getVirtualKey(ev)) {
|
||||
case "Escape":
|
||||
handleEscape(ev);
|
||||
@ -1082,6 +1083,9 @@ function loadCss(cssUrl) {
|
||||
* Show the help popup menu.
|
||||
*/
|
||||
function showHelp() {
|
||||
// Prevent `blur` events from being dispatched as a result of closing
|
||||
// other modals.
|
||||
getHelpButton().querySelector("a").focus();
|
||||
const menu = getHelpMenu(true);
|
||||
if (menu.style.display === "none") {
|
||||
window.hideAllModals();
|
||||
|
@ -781,7 +781,29 @@ function initSearch(rawSearchIndex) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Sort by non levenshtein results and then levenshtein results by the distance
|
||||
// sort by index of keyword in item name (no literal occurrence goes later)
|
||||
a = (aaa.index < 0);
|
||||
b = (bbb.index < 0);
|
||||
if (a !== b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Sort by distance in the path part, if specified
|
||||
// (less changes required to match means higher rankings)
|
||||
a = aaa.path_lev;
|
||||
b = bbb.path_lev;
|
||||
if (a !== b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// (later literal occurrence, if any, goes later)
|
||||
a = aaa.index;
|
||||
b = bbb.index;
|
||||
if (a !== b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Sort by distance in the name part, the last part of the path
|
||||
// (less changes required to match means higher rankings)
|
||||
a = (aaa.lev);
|
||||
b = (bbb.lev);
|
||||
@ -810,19 +832,6 @@ function initSearch(rawSearchIndex) {
|
||||
return (a > b ? +1 : -1);
|
||||
}
|
||||
|
||||
// sort by index of keyword in item name (no literal occurrence goes later)
|
||||
a = (aaa.index < 0);
|
||||
b = (bbb.index < 0);
|
||||
if (a !== b) {
|
||||
return a - b;
|
||||
}
|
||||
// (later literal occurrence, if any, goes later)
|
||||
a = aaa.index;
|
||||
b = bbb.index;
|
||||
if (a !== b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// special precedence for primitive and keyword pages
|
||||
if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) ||
|
||||
(aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) {
|
||||
@ -1230,15 +1239,19 @@ function initSearch(rawSearchIndex) {
|
||||
* * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
|
||||
* * `index` is an `integer`` used to sort by the position of the word in the item's name.
|
||||
* * `lev` is the main metric used to sort the search results.
|
||||
* * `path_lev` is zero if a single-component search query is used, otherwise it's the
|
||||
* distance computed for everything other than the last path component.
|
||||
*
|
||||
* @param {Results} results
|
||||
* @param {string} fullId
|
||||
* @param {integer} id
|
||||
* @param {integer} index
|
||||
* @param {integer} lev
|
||||
* @param {integer} path_lev
|
||||
*/
|
||||
function addIntoResults(results, fullId, id, index, lev) {
|
||||
if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
|
||||
function addIntoResults(results, fullId, id, index, lev, path_lev) {
|
||||
const inBounds = lev <= MAX_LEV_DISTANCE || index !== -1;
|
||||
if (lev === 0 || (!parsedQuery.literalSearch && inBounds)) {
|
||||
if (results[fullId] !== undefined) {
|
||||
const result = results[fullId];
|
||||
if (result.dontValidate || result.lev <= lev) {
|
||||
@ -1250,6 +1263,7 @@ function initSearch(rawSearchIndex) {
|
||||
index: index,
|
||||
dontValidate: parsedQuery.literalSearch,
|
||||
lev: lev,
|
||||
path_lev: path_lev,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1280,68 +1294,68 @@ function initSearch(rawSearchIndex) {
|
||||
if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
|
||||
return;
|
||||
}
|
||||
let lev, lev_add = 0, index = -1;
|
||||
let lev, index = -1, path_lev = 0;
|
||||
const fullId = row.id;
|
||||
const searchWord = searchWords[pos];
|
||||
|
||||
const in_args = findArg(row, elem, parsedQuery.typeFilter);
|
||||
const returned = checkReturned(row, elem, parsedQuery.typeFilter);
|
||||
|
||||
addIntoResults(results_in_args, fullId, pos, index, in_args);
|
||||
addIntoResults(results_returned, fullId, pos, index, returned);
|
||||
// path_lev is 0 because no parent path information is currently stored
|
||||
// in the search index
|
||||
addIntoResults(results_in_args, fullId, pos, -1, in_args, 0);
|
||||
addIntoResults(results_returned, fullId, pos, -1, returned, 0);
|
||||
|
||||
if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
|
||||
return;
|
||||
}
|
||||
const searchWord = searchWords[pos];
|
||||
|
||||
if (parsedQuery.literalSearch) {
|
||||
if (searchWord === elem.name) {
|
||||
addIntoResults(results_others, fullId, pos, -1, 0);
|
||||
}
|
||||
return;
|
||||
const row_index = row.normalizedName.indexOf(elem.pathLast);
|
||||
const word_index = searchWord.indexOf(elem.pathLast);
|
||||
|
||||
// lower indexes are "better" matches
|
||||
// rank based on the "best" match
|
||||
if (row_index === -1) {
|
||||
index = word_index;
|
||||
} else if (word_index === -1) {
|
||||
index = row_index;
|
||||
} else if (word_index < row_index) {
|
||||
index = word_index;
|
||||
} else {
|
||||
index = row_index;
|
||||
}
|
||||
|
||||
// No need to check anything else if it's a "pure" generics search.
|
||||
if (elem.name.length === 0) {
|
||||
if (row.type !== null) {
|
||||
lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1);
|
||||
addIntoResults(results_others, fullId, pos, index, lev);
|
||||
// path_lev is 0 because we know it's empty
|
||||
addIntoResults(results_others, fullId, pos, index, lev, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (elem.fullPath.length > 1) {
|
||||
lev = checkPath(elem.pathWithoutLast, row);
|
||||
if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
|
||||
path_lev = checkPath(elem.pathWithoutLast, row);
|
||||
if (path_lev > MAX_LEV_DISTANCE) {
|
||||
return;
|
||||
} else if (lev > 0) {
|
||||
lev_add = lev / 10;
|
||||
}
|
||||
}
|
||||
|
||||
if (searchWord.indexOf(elem.pathLast) > -1 ||
|
||||
row.normalizedName.indexOf(elem.pathLast) > -1
|
||||
) {
|
||||
index = row.normalizedName.indexOf(elem.pathLast);
|
||||
}
|
||||
lev = levenshtein(searchWord, elem.pathLast);
|
||||
if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) {
|
||||
if (elem.pathLast.length < 6) {
|
||||
lev = 1;
|
||||
} else {
|
||||
lev = 0;
|
||||
if (parsedQuery.literalSearch) {
|
||||
if (searchWord === elem.name) {
|
||||
addIntoResults(results_others, fullId, pos, index, 0, path_lev);
|
||||
}
|
||||
}
|
||||
lev += lev_add;
|
||||
if (lev > MAX_LEV_DISTANCE) {
|
||||
return;
|
||||
} else if (index !== -1 && elem.fullPath.length < 2) {
|
||||
lev -= 1;
|
||||
}
|
||||
if (lev < 0) {
|
||||
lev = 0;
|
||||
|
||||
lev = levenshtein(searchWord, elem.pathLast);
|
||||
|
||||
if (index === -1 && lev + path_lev > MAX_LEV_DISTANCE) {
|
||||
return;
|
||||
}
|
||||
addIntoResults(results_others, fullId, pos, index, lev);
|
||||
|
||||
addIntoResults(results_others, fullId, pos, index, lev, path_lev);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1386,7 +1400,7 @@ function initSearch(rawSearchIndex) {
|
||||
return;
|
||||
}
|
||||
const lev = Math.round(totalLev / nbLev);
|
||||
addIntoResults(results, row.id, pos, 0, lev);
|
||||
addIntoResults(results, row.id, pos, 0, lev, 0);
|
||||
}
|
||||
|
||||
function innerRunQuery() {
|
||||
|
@ -8,6 +8,10 @@ assert-false: "#settings"
|
||||
click: "#settings-menu"
|
||||
wait-for: "#settings"
|
||||
assert-css: ("#settings", {"display": "block"})
|
||||
|
||||
// Store the line margin to compare with the settings.html later.
|
||||
store-css: (setting_line_margin, ".setting-line", "margin")
|
||||
|
||||
// Let's close it by clicking on the same button.
|
||||
click: "#settings-menu"
|
||||
wait-for-css: ("#settings", {"display": "none"})
|
||||
@ -203,6 +207,25 @@ press-key: "?"
|
||||
wait-for-css: ("#help-button .popover", {"display": "block"})
|
||||
assert-css: ("#settings-menu .popover", {"display": "none"})
|
||||
|
||||
// Now switch back to the settings popover, and make sure the keyboard
|
||||
// shortcut works when a check box is selected.
|
||||
click: "#settings-menu > a"
|
||||
wait-for-css: ("#settings-menu .popover", {"display": "block"})
|
||||
focus: "#auto-hide-large-items"
|
||||
press-key: "?"
|
||||
wait-for-css: ("#settings-menu .popover", {"display": "none"})
|
||||
wait-for-css: ("#help-button .popover", {"display": "block"})
|
||||
|
||||
// Now switch back to the settings popover, and make sure the keyboard
|
||||
// shortcut works when a check box is selected.
|
||||
click: "#settings-menu > a"
|
||||
wait-for-css: ("#settings-menu .popover", {"display": "block"})
|
||||
wait-for-css: ("#help-button .popover", {"display": "none"})
|
||||
focus: "#theme-system-preference"
|
||||
press-key: "?"
|
||||
wait-for-css: ("#settings-menu .popover", {"display": "none"})
|
||||
wait-for-css: ("#help-button .popover", {"display": "block"})
|
||||
|
||||
// Now we go to the settings page to check that the CSS is loaded as expected.
|
||||
goto: "file://" + |DOC_PATH| + "/settings.html"
|
||||
wait-for: "#settings"
|
||||
@ -211,6 +234,9 @@ assert-css: (".setting-line", {"position": "relative"})
|
||||
assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
|
||||
compare-elements-position: (".sub form", "#settings", ("x"))
|
||||
|
||||
// Check that setting-line has the same margin in this mode as in the popover.
|
||||
assert-css: (".setting-line", {"margin": |setting_line_margin|})
|
||||
|
||||
// We now check the display with JS disabled.
|
||||
assert-false: "noscript section"
|
||||
javascript: false
|
||||
|
@ -3,8 +3,8 @@ const QUERY = 'macro:print';
|
||||
const EXPECTED = {
|
||||
'others': [
|
||||
{ 'path': 'std', 'name': 'print' },
|
||||
{ 'path': 'std', 'name': 'eprint' },
|
||||
{ 'path': 'std', 'name': 'println' },
|
||||
{ 'path': 'std', 'name': 'eprint' },
|
||||
{ 'path': 'std', 'name': 'eprintln' },
|
||||
],
|
||||
};
|
||||
|
@ -6,8 +6,8 @@ const FILTER_CRATE = 'std';
|
||||
const EXPECTED = {
|
||||
'others': [
|
||||
{ 'path': 'std', 'name': 'print' },
|
||||
{ 'path': 'std', 'name': 'eprint' },
|
||||
{ 'path': 'std', 'name': 'println' },
|
||||
{ 'path': 'std', 'name': 'eprint' },
|
||||
{ 'path': 'std', 'name': 'eprintln' },
|
||||
{ 'path': 'std::pin', 'name': 'pin' },
|
||||
{ 'path': 'std::future', 'name': 'join' },
|
||||
|
@ -3,7 +3,8 @@ const QUERY = 'Vec::new';
|
||||
const EXPECTED = {
|
||||
'others': [
|
||||
{ 'path': 'std::vec::Vec', 'name': 'new' },
|
||||
{ 'path': 'std::vec::Vec', 'name': 'ne' },
|
||||
{ 'path': 'alloc::vec::Vec', 'name': 'ne' },
|
||||
{ 'path': 'alloc::vec::Vec', 'name': 'new' },
|
||||
{ 'path': 'std::vec::Vec', 'name': 'new_in' },
|
||||
{ 'path': 'alloc::vec::Vec', 'name': 'new_in' },
|
||||
],
|
||||
};
|
||||
|
@ -4,7 +4,6 @@ const EXPECTED = {
|
||||
'others': [
|
||||
{ 'path': 'search_short_types', 'name': 'P' },
|
||||
{ 'path': 'search_short_types::VeryLongTypeName', 'name': 'p' },
|
||||
{ 'path': 'search_short_types', 'name': 'Ap' },
|
||||
{ 'path': 'search_short_types::VeryLongTypeName', 'name': 'ap' },
|
||||
{ 'path': 'search_short_types', 'name': 'Pa' },
|
||||
],
|
||||
};
|
||||
|
21
tests/ui/async-await/in-trait/missing-send-bound.rs
Normal file
21
tests/ui/async-await/in-trait/missing-send-bound.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// edition:2021
|
||||
|
||||
#![feature(async_fn_in_trait)]
|
||||
//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
|
||||
trait Foo {
|
||||
async fn bar();
|
||||
}
|
||||
|
||||
async fn test<T: Foo>() {
|
||||
T::bar().await;
|
||||
}
|
||||
|
||||
fn test2<T: Foo>() {
|
||||
assert_is_send(test::<T>());
|
||||
//~^ ERROR future cannot be sent between threads safely
|
||||
}
|
||||
|
||||
fn assert_is_send(_: impl Send) {}
|
||||
|
||||
fn main() {}
|
29
tests/ui/async-await/in-trait/missing-send-bound.stderr
Normal file
29
tests/ui/async-await/in-trait/missing-send-bound.stderr
Normal file
@ -0,0 +1,29 @@
|
||||
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/missing-send-bound.rs:3:12
|
||||
|
|
||||
LL | #![feature(async_fn_in_trait)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: future cannot be sent between threads safely
|
||||
--> $DIR/missing-send-bound.rs:15:20
|
||||
|
|
||||
LL | assert_is_send(test::<T>());
|
||||
| ^^^^^^^^^^^ future returned by `test` is not `Send`
|
||||
|
|
||||
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`
|
||||
note: future is not `Send` as it awaits another future which is not `Send`
|
||||
--> $DIR/missing-send-bound.rs:11:5
|
||||
|
|
||||
LL | T::bar().await;
|
||||
| ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send`
|
||||
note: required by a bound in `assert_is_send`
|
||||
--> $DIR/missing-send-bound.rs:19:27
|
||||
|
|
||||
LL | fn assert_is_send(_: impl Send) {}
|
||||
| ^^^^ required by this bound in `assert_is_send`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
8
tests/ui/consts/auxiliary/closure-in-foreign-crate.rs
Normal file
8
tests/ui/consts/auxiliary/closure-in-foreign-crate.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#![crate_type = "lib"]
|
||||
#![feature(const_closures, const_trait_impl)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
pub const fn test() {
|
||||
let cl = const || {};
|
||||
cl();
|
||||
}
|
8
tests/ui/consts/closure-in-foreign-crate.rs
Normal file
8
tests/ui/consts/closure-in-foreign-crate.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// aux-build:closure-in-foreign-crate.rs
|
||||
// build-pass
|
||||
|
||||
extern crate closure_in_foreign_crate;
|
||||
|
||||
const _: () = closure_in_foreign_crate::test();
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user