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:
bors 2023-01-19 02:09:45 +00:00
commit 6ba6d22bdf
58 changed files with 738 additions and 241 deletions

View File

@ -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(()))
}
}
}

View File

@ -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),
}

View File

@ -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)]

View File

@ -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(()),
}
}
}

View File

@ -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)]

View File

@ -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),
}

View File

@ -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> {

View File

@ -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),
}

View File

@ -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> {

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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),
}

View File

@ -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(())
}
}

View File

@ -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(())
}
}

View File

@ -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)

View File

@ -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() {

View File

@ -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(())
}
},
)

View File

@ -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.

View File

@ -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)*
)
)

View File

@ -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(())
}
}

View File

@ -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

View File

@ -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)
}

View File

@ -2468,7 +2468,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
if not_previously_inserted {
ty.super_visit_with(self)
} else {
ControlFlow::CONTINUE
ControlFlow::Continue(())
}
}
}

View File

@ -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(())
}
}

View File

@ -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) }
}
}

View File

@ -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(())
}
}

View File

@ -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)]

View File

@ -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 {

View File

@ -1,5 +1,4 @@
#![feature(array_windows)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]

View File

@ -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),
}

View File

@ -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(())
}
}
}

View File

@ -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) => (),
}
}
}
}

View File

@ -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,
)
}
}

View File

@ -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)]

View File

@ -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);
}
}

View File

@ -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>>,

View File

@ -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())
}
}
}

View File

@ -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(())
}
}

View File

@ -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(())
}
}
}

View File

@ -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(())
}
}
}

View File

@ -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(&param, 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(&param, 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)
}

View File

@ -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
}

View File

@ -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),
}

View File

@ -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) {

View File

@ -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)]

View File

@ -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"]

View File

@ -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);

View File

@ -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();

View File

@ -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() {

View File

@ -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

View File

@ -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' },
],
};

View File

@ -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' },

View File

@ -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' },
],
};

View File

@ -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' },
],
};

View 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() {}

View 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

View 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();
}

View 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() {}