1
Fork 0

Merge branch 'rust-lang:master' into master

This commit is contained in:
Takashi Idobe 2021-09-24 08:31:03 -05:00 committed by GitHub
commit cb1c06fdd8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 934 additions and 258 deletions

View file

@ -4,7 +4,7 @@ use crate::type_::Type;
use rustc_codegen_ssa::traits::*;
use rustc_middle::bug;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Ty, TypeFoldable};
use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
use rustc_target::abi::{Int, Pointer, F32, F64};
@ -43,7 +43,8 @@ fn uncached_llvm_type<'a, 'tcx>(
// in problematically distinct types due to HRTB and subtyping (see #47638).
// ty::Dynamic(..) |
ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str => {
let mut name = with_no_trimmed_paths(|| layout.ty.to_string());
let mut name =
with_no_visible_paths(|| with_no_trimmed_paths(|| layout.ty.to_string()));
if let (&ty::Adt(def, _), &Variants::Single { index }) =
(layout.ty.kind(), &layout.variants)
{

View file

@ -15,7 +15,7 @@ use rustc_index::vec::Idx;
use rustc_middle::mir::AssertKind;
use rustc_middle::mir::{self, SwitchTargets};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol};
@ -476,15 +476,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false),
};
if do_panic {
let msg_str = with_no_trimmed_paths(|| {
if layout.abi.is_uninhabited() {
// Use this error even for the other intrinsics as it is more precise.
format!("attempted to instantiate uninhabited type `{}`", ty)
} else if intrinsic == ZeroValid {
format!("attempted to zero-initialize type `{}`, which is invalid", ty)
} else {
format!("attempted to leave type `{}` uninitialized, which is invalid", ty)
}
let msg_str = with_no_visible_paths(|| {
with_no_trimmed_paths(|| {
if layout.abi.is_uninhabited() {
// Use this error even for the other intrinsics as it is more precise.
format!("attempted to instantiate uninhabited type `{}`", ty)
} else if intrinsic == ZeroValid {
format!("attempted to zero-initialize type `{}`, which is invalid", ty)
} else {
format!(
"attempted to leave type `{}` uninitialized, which is invalid",
ty
)
}
})
});
let msg = bx.const_str(Symbol::intern(&msg_str));
let location = self.get_caller_location(bx, source_info).immediate();

View file

@ -22,6 +22,7 @@
// is also useful to track which value is the "expected" value in
// terms of error reporting.
use super::equate::Equate;
use super::glb::Glb;
use super::lub::Lub;
use super::sub::Sub;
@ -29,7 +30,6 @@ use super::type_variable::TypeVariableValue;
use super::unify_key::replace_if_possible;
use super::unify_key::{ConstVarValue, ConstVariableValue};
use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use super::{equate::Equate, type_variable::Diverging};
use super::{InferCtxt, MiscVariable, TypeTrace};
use crate::traits::{Obligation, PredicateObligations};
@ -645,7 +645,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
.inner
.borrow_mut()
.type_variables()
.new_var(self.for_universe, Diverging::NotDiverging, origin);
.new_var(self.for_universe, origin);
let u = self.tcx().mk_ty_var(new_var_id);
// Record that we replaced `vid` with `new_var_id` as part of a generalization
@ -885,11 +885,12 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
let origin =
*self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var(
self.for_universe,
Diverging::NotDiverging,
origin,
);
let new_var_id = self
.infcx
.inner
.borrow_mut()
.type_variables()
.new_var(self.for_universe, origin);
let u = self.tcx().mk_ty_var(new_var_id);
debug!(
"ConstInferUnifier: replacing original vid={:?} with new={:?}",

View file

@ -7,7 +7,7 @@
//! inference graph arose so that we can explain to the user what gave
//! rise to a particular error.
//!
//! The basis of the system are the "origin" types. An "origin" is the
//! The system is based around a set of "origin" types. An "origin" is the
//! reason that a constraint or inference variable arose. There are
//! different "origin" enums for different kinds of constraints/variables
//! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has

View file

@ -46,7 +46,7 @@ use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, Veri
use self::region_constraints::{
RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
};
use self::type_variable::{Diverging, TypeVariableOrigin, TypeVariableOriginKind};
use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
pub mod at;
pub mod canonical;
@ -702,17 +702,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
t.fold_with(&mut self.freshener())
}
/// Returns whether `ty` is a diverging type variable or not.
/// (If `ty` is not a type variable at all, returns not diverging.)
///
/// No attempt is made to resolve `ty`.
pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging {
match *ty.kind() {
ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid),
_ => Diverging::NotDiverging,
}
}
/// Returns the origin of the type variable identified by `vid`, or `None`
/// if this is not a type variable.
///
@ -1071,12 +1060,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
})
}
pub fn next_ty_var_id(&self, diverging: Diverging, origin: TypeVariableOrigin) -> TyVid {
self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin)
/// Number of type variables created so far.
pub fn num_ty_vars(&self) -> usize {
self.inner.borrow_mut().type_variables().num_vars()
}
pub fn next_ty_var_id(&self, origin: TypeVariableOrigin) -> TyVid {
self.inner.borrow_mut().type_variables().new_var(self.universe(), origin)
}
pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::NotDiverging, origin))
self.tcx.mk_ty_var(self.next_ty_var_id(origin))
}
pub fn next_ty_var_in_universe(
@ -1084,18 +1078,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: TypeVariableOrigin,
universe: ty::UniverseIndex,
) -> Ty<'tcx> {
let vid = self.inner.borrow_mut().type_variables().new_var(
universe,
Diverging::NotDiverging,
origin,
);
let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin);
self.tcx.mk_ty_var(vid)
}
pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::Diverges, origin))
}
pub fn next_const_var(
&self,
ty: Ty<'tcx>,
@ -1207,7 +1193,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// as the substitutions for the default, `(T, U)`.
let ty_var_id = self.inner.borrow_mut().type_variables().new_var(
self.universe(),
Diverging::NotDiverging,
TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(
param.name,

View file

@ -22,7 +22,6 @@
//! constituents)
use crate::infer::combine::ConstEquateRelation;
use crate::infer::type_variable::Diverging;
use crate::infer::InferCtxt;
use crate::infer::{ConstVarValue, ConstVariableValue};
use rustc_data_structures::fx::FxHashMap;
@ -927,8 +926,7 @@ where
// Replacing with a new variable in the universe `self.universe`,
// it will be unified later with the original type variable in
// the universe `_universe`.
let new_var_id =
variables.new_var(self.universe, Diverging::NotDiverging, origin);
let new_var_id = variables.new_var(self.universe, origin);
let u = self.tcx().mk_ty_var(new_var_id);
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);

View file

@ -129,19 +129,16 @@ pub enum TypeVariableOriginKind {
SubstitutionPlaceholder,
AutoDeref,
AdjustmentType,
DivergingFn,
/// In type check, when we are type checking a function that
/// returns `-> dyn Foo`, we substitute a type variable for the
/// return type for diagnostic purposes.
DynReturnFn,
LatticeVariable,
}
pub(crate) struct TypeVariableData {
origin: TypeVariableOrigin,
diverging: Diverging,
}
#[derive(Copy, Clone, Debug)]
pub enum Diverging {
NotDiverging,
Diverges,
}
#[derive(Copy, Clone, Debug)]
@ -191,14 +188,6 @@ impl<'tcx> TypeVariableStorage<'tcx> {
}
impl<'tcx> TypeVariableTable<'_, 'tcx> {
/// Returns the diverges flag given when `vid` was created.
///
/// Note that this function does not return care whether
/// `vid` has been unified with something else or not.
pub fn var_diverges(&self, vid: ty::TyVid) -> Diverging {
self.storage.values.get(vid.index()).diverging
}
/// Returns the origin that was given when `vid` was created.
///
/// Note that this function does not return care whether
@ -260,7 +249,6 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
pub fn new_var(
&mut self,
universe: ty::UniverseIndex,
diverging: Diverging,
origin: TypeVariableOrigin,
) -> ty::TyVid {
let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });
@ -268,13 +256,10 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
let sub_key = self.sub_relations().new_key(());
assert_eq!(eq_key.vid, sub_key);
let index = self.values().push(TypeVariableData { origin, diverging });
let index = self.values().push(TypeVariableData { origin });
assert_eq!(eq_key.vid.as_u32(), index as u32);
debug!(
"new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}",
eq_key.vid, universe, diverging, origin,
);
debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,);
eq_key.vid
}

View file

@ -1,5 +1,6 @@
use crate::infer::InferCtxt;
use crate::traits::Obligation;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness};
@ -73,6 +74,8 @@ pub trait TraitEngine<'tcx>: 'tcx {
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships>;
}
pub trait TraitEngineExt<'tcx> {

View file

@ -599,7 +599,7 @@ rustc_queries! {
desc { "computing the inferred outlives predicates for items in this crate" }
}
/// Maps from an impl/trait `DefId to a list of the `DefId`s of its items.
/// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items.
query associated_item_def_ids(key: DefId) -> &'tcx [DefId] {
desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
}

View file

@ -2090,3 +2090,16 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> {
fmt::Display::fmt(&self.name, fmt)
}
}
#[derive(Debug, Default, Copy, Clone)]
pub struct FoundRelationships {
/// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo`
/// obligation, where:
///
/// * `Foo` is not `Sized`
/// * `(): Foo` may be satisfied
pub self_in_trait: bool,
/// This is true if we identified that this Ty (`?T`) is found in a `<_ as
/// _>::AssocType = ?T`
pub output: bool,
}

View file

@ -59,6 +59,7 @@ thread_local! {
static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) };
static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
static NO_QUERIES: Cell<bool> = const { Cell::new(false) };
static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) };
}
/// Avoids running any queries during any prints that occur
@ -112,6 +113,16 @@ pub fn with_no_trimmed_paths<F: FnOnce() -> R, R>(f: F) -> R {
})
}
/// Prevent selection of visible paths. `Display` impl of DefId will prefer visible (public) reexports of types as paths.
pub fn with_no_visible_paths<F: FnOnce() -> R, R>(f: F) -> R {
NO_VISIBLE_PATH.with(|flag| {
let old = flag.replace(true);
let result = f();
flag.set(old);
result
})
}
/// The "region highlights" are used to control region printing during
/// specific error messages. When a "region highlight" is enabled, it
/// gives an alternate way to print specific regions. For now, we
@ -268,6 +279,10 @@ pub trait PrettyPrinter<'tcx>:
/// from at least one local module, and returns `true`. If the crate defining `def_id` is
/// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
fn try_print_visible_def_path(self, def_id: DefId) -> Result<(Self, bool), Self::Error> {
if NO_VISIBLE_PATH.with(|flag| flag.get()) {
return Ok((self, false));
}
let mut callers = Vec::new();
self.try_print_visible_def_path_recur(def_id, &mut callers)
}

View file

@ -1672,6 +1672,14 @@ impl<'tcx> TyS<'tcx> {
matches!(self.kind(), Infer(TyVar(_)))
}
#[inline]
pub fn ty_vid(&self) -> Option<ty::TyVid> {
match self.kind() {
&Infer(TyVar(vid)) => Some(vid),
_ => None,
}
}
#[inline]
pub fn is_ty_infer(&self) -> bool {
matches!(self.kind(), Infer(_))

View file

@ -1568,6 +1568,20 @@ impl<'a> Parser<'a> {
pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
self.parse_opt_lit().ok_or_else(|| {
if let token::Interpolated(inner) = &self.token.kind {
let expr = match inner.as_ref() {
token::NtExpr(expr) => Some(expr),
token::NtLiteral(expr) => Some(expr),
_ => None,
};
if let Some(expr) = expr {
if matches!(expr.kind, ExprKind::Err) {
self.diagnostic()
.delay_span_bug(self.token.span, &"invalid interpolated expression");
return self.diagnostic().struct_dummy();
}
}
}
let msg = format!("unexpected token: {}", super::token_descr(&self.token));
self.struct_span_err(self.token.span, &msg)
})

View file

@ -321,10 +321,13 @@ macro_rules! define_queries {
pub fn $name<$tcx>(tcx: QueryCtxt<$tcx>, key: query_keys::$name<$tcx>) -> QueryStackFrame {
let kind = dep_graph::DepKind::$name;
let name = stringify!($name);
let description = ty::print::with_forced_impl_filename_line(
// Disable visible paths printing for performance reasons.
// Showing visible path instead of any path is not that important in production.
let description = ty::print::with_no_visible_paths(
|| ty::print::with_forced_impl_filename_line(
// Force filename-line mode to avoid invoking `type_of` query.
|| queries::$name::describe(tcx, key)
);
));
let description = if tcx.sess.verbose() {
format!("{} [{}]", description, name)
} else {

View file

@ -7,16 +7,21 @@ use crate::traits::{
ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause,
PredicateObligation, SelectionError, TraitEngine,
};
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_middle::ty::{self, Ty};
pub struct FulfillmentContext<'tcx> {
obligations: FxIndexSet<PredicateObligation<'tcx>>,
relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
}
impl FulfillmentContext<'tcx> {
crate fn new() -> Self {
FulfillmentContext { obligations: FxIndexSet::default() }
FulfillmentContext {
obligations: FxIndexSet::default(),
relationships: FxHashMap::default(),
}
}
}
@ -39,6 +44,8 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
assert!(!infcx.is_in_snapshot());
let obligation = infcx.resolve_vars_if_possible(obligation);
super::relationships::update(self, infcx, &obligation);
self.obligations.insert(obligation);
}
@ -146,4 +153,8 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.obligations.iter().cloned().collect()
}
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
&mut self.relationships
}
}

View file

@ -1,4 +1,5 @@
use crate::infer::{InferCtxt, TyOrConstInferVar};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
@ -53,6 +54,9 @@ pub struct FulfillmentContext<'tcx> {
// A list of all obligations that have been registered with this
// fulfillment context.
predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
// Should this fulfillment context register type-lives-for-region
// obligations on its parent infcx? In some cases, region
// obligations are either already known to hold (normalization) or
@ -97,6 +101,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
pub fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
relationships: FxHashMap::default(),
register_region_obligations: true,
usable_in_snapshot: false,
}
@ -105,6 +110,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
pub fn new_in_snapshot() -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
relationships: FxHashMap::default(),
register_region_obligations: true,
usable_in_snapshot: true,
}
@ -113,6 +119,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
relationships: FxHashMap::default(),
register_region_obligations: false,
usable_in_snapshot: false,
}
@ -210,6 +217,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
super::relationships::update(self, infcx, &obligation);
self.predicates
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}
@ -265,6 +274,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.predicates.map_pending_obligations(|o| o.obligation.clone())
}
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
&mut self.relationships
}
}
struct FulfillProcessor<'a, 'b, 'tcx> {

View file

@ -15,6 +15,7 @@ mod object_safety;
mod on_unimplemented;
mod project;
pub mod query;
pub(crate) mod relationships;
mod select;
mod specialize;
mod structural_match;

View file

@ -0,0 +1,69 @@
use crate::infer::InferCtxt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{ObligationCause, PredicateObligation};
use rustc_infer::traits::TraitEngine;
use rustc_middle::ty::{self, ToPredicate};
pub(crate) fn update<'tcx, T>(
engine: &mut T,
infcx: &InferCtxt<'_, 'tcx>,
obligation: &PredicateObligation<'tcx>,
) where
T: TraitEngine<'tcx>,
{
// (*) binder skipped
if let ty::PredicateKind::Trait(predicate) = obligation.predicate.kind().skip_binder() {
if let Some(ty) =
infcx.shallow_resolve(predicate.self_ty()).ty_vid().map(|t| infcx.root_var(t))
{
if infcx
.tcx
.lang_items()
.sized_trait()
.map_or(false, |st| st != predicate.trait_ref.def_id)
{
let new_self_ty = infcx.tcx.types.unit;
let trait_ref = ty::TraitRef {
substs: infcx
.tcx
.mk_substs_trait(new_self_ty, &predicate.trait_ref.substs[1..]),
..predicate.trait_ref
};
// Then contstruct a new obligation with Self = () added
// to the ParamEnv, and see if it holds.
let o = rustc_infer::traits::Obligation::new(
ObligationCause::dummy(),
obligation.param_env,
obligation
.predicate
.kind()
.map_bound(|_| {
// (*) binder moved here
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: predicate.constness,
})
})
.to_predicate(infcx.tcx),
);
// Don't report overflow errors. Otherwise equivalent to may_hold.
if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) {
if result.may_apply() {
engine.relationships().entry(ty).or_default().self_in_trait = true;
}
}
}
}
}
if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one.
if let Some(vid) = predicate.ty.ty_vid() {
debug!("relationship: {:?}.output = true", vid);
engine.relationships().entry(vid).or_default().output = true;
}
}
}

View file

@ -241,32 +241,16 @@ pub(super) fn check_fn<'a, 'tcx>(
// we saw and assigning it to the expected return type. This isn't
// really expected to fail, since the coercions would have failed
// earlier when trying to find a LUB.
//
// However, the behavior around `!` is sort of complex. In the
// event that the `actual_return_ty` comes back as `!`, that
// indicates that the fn either does not return or "returns" only
// values of type `!`. In this case, if there is an expected
// return type that is *not* `!`, that should be ok. But if the
// return type is being inferred, we want to "fallback" to `!`:
//
// let x = move || panic!();
//
// To allow for that, I am creating a type variable with diverging
// fallback. This was deemed ever so slightly better than unifying
// the return value with `!` because it allows for the caller to
// make more assumptions about the return type (e.g., they could do
//
// let y: Option<u32> = Some(x());
//
// which would then cause this return type to become `u32`, not
// `!`).
let coercion = fcx.ret_coercion.take().unwrap().into_inner();
let mut actual_return_ty = coercion.complete(&fcx);
if actual_return_ty.is_never() {
actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::DivergingFn,
span,
});
debug!("actual_return_ty = {:?}", actual_return_ty);
if let ty::Dynamic(..) = declared_ret_ty.kind() {
// We have special-cased the case where the function is declared
// `-> dyn Foo` and we don't actually relate it to the
// `fcx.ret_coercion`, so just substitute a type variable.
actual_return_ty =
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
debug!("actual_return_ty replaced with {:?}", actual_return_ty);
}
fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);

View file

@ -159,24 +159,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Coercing from `!` to any type is allowed:
if a.is_never() {
// Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
// type variable, we want `?T` to fallback to `!` if not
// otherwise constrained. An example where this arises:
//
// let _: Option<?T> = Some({ return; });
//
// here, we would coerce from `!` to `?T`.
return if b.is_ty_var() {
// Micro-optimization: no need for this if `b` is
// already resolved in some way.
let diverging_ty = self.next_diverging_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::AdjustmentType,
span: self.cause.span,
});
self.coerce_from_inference_variable(diverging_ty, b, simple(Adjust::NeverToAny))
} else {
success(simple(Adjust::NeverToAny)(b), b, vec![])
};
return success(simple(Adjust::NeverToAny)(b), b, vec![]);
}
// Coercing *from* an unresolved inference variable means that

View file

@ -77,7 +77,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
!self.typeck_results.borrow().adjustments().contains_key(expr.hir_id),
"expression with never type wound up being adjusted"
);
let adj_ty = self.next_diverging_ty_var(TypeVariableOrigin {
let adj_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::AdjustmentType,
span: expr.span,
});

View file

@ -1,29 +1,52 @@
use crate::check::FnCtxt;
use rustc_infer::infer::type_variable::Diverging;
use rustc_data_structures::{
fx::FxHashMap,
graph::WithSuccessors,
graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
stable_set::FxHashSet,
};
use rustc_middle::ty::{self, Ty};
impl<'tcx> FnCtxt<'_, 'tcx> {
/// Performs type inference fallback, returning true if any fallback
/// occurs.
pub(super) fn type_inference_fallback(&self) -> bool {
debug!(
"type-inference-fallback start obligations: {:#?}",
self.fulfillment_cx.borrow_mut().pending_obligations()
);
// All type checking constraints were added, try to fallback unsolved variables.
self.select_obligations_where_possible(false, |_| {});
let mut fallback_has_occurred = false;
debug!(
"type-inference-fallback post selection obligations: {:#?}",
self.fulfillment_cx.borrow_mut().pending_obligations()
);
// Check if we have any unsolved varibales. If not, no need for fallback.
let unsolved_variables = self.unsolved_variables();
if unsolved_variables.is_empty() {
return false;
}
let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
let mut fallback_has_occurred = false;
// We do fallback in two passes, to try to generate
// better error messages.
// The first time, we do *not* replace opaque types.
for ty in &self.unsolved_variables() {
for ty in unsolved_variables {
debug!("unsolved_variable = {:?}", ty);
fallback_has_occurred |= self.fallback_if_possible(ty);
fallback_has_occurred |= self.fallback_if_possible(ty, &diverging_fallback);
}
// We now see if we can make progress. This might
// cause us to unify inference variables for opaque types,
// since we may have unified some other type variables
// during the first phase of fallback.
// This means that we only replace inference variables with their underlying
// opaque types as a last resort.
// We now see if we can make progress. This might cause us to
// unify inference variables for opaque types, since we may
// have unified some other type variables during the first
// phase of fallback. This means that we only replace
// inference variables with their underlying opaque types as a
// last resort.
//
// In code like this:
//
@ -62,36 +85,44 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
//
// - Unconstrained floats are replaced with with `f64`.
//
// - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
// is enabled. Otherwise, they are replaced with `()`.
// - Non-numerics may get replaced with `()` or `!`, depending on
// how they were categorized by `calculate_diverging_fallback`
// (and the setting of `#![feature(never_type_fallback)]`).
//
// Fallback becomes very dubious if we have encountered
// type-checking errors. In that case, fallback to Error.
//
// Fallback becomes very dubious if we have encountered type-checking errors.
// In that case, fallback to Error.
// The return value indicates whether fallback has occurred.
fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool {
fn fallback_if_possible(
&self,
ty: Ty<'tcx>,
diverging_fallback: &FxHashMap<Ty<'tcx>, Ty<'tcx>>,
) -> bool {
// Careful: we do NOT shallow-resolve `ty`. We know that `ty`
// is an unsolved variable, and we determine its fallback based
// solely on how it was created, not what other type variables
// it may have been unified with since then.
// is an unsolved variable, and we determine its fallback
// based solely on how it was created, not what other type
// variables it may have been unified with since then.
//
// The reason this matters is that other attempts at fallback may
// (in principle) conflict with this fallback, and we wish to generate
// a type error in that case. (However, this actually isn't true right now,
// because we're only using the builtin fallback rules. This would be
// true if we were using user-supplied fallbacks. But it's still useful
// to write the code to detect bugs.)
// The reason this matters is that other attempts at fallback
// may (in principle) conflict with this fallback, and we wish
// to generate a type error in that case. (However, this
// actually isn't true right now, because we're only using the
// builtin fallback rules. This would be true if we were using
// user-supplied fallbacks. But it's still useful to write the
// code to detect bugs.)
//
// (Note though that if we have a general type variable `?T` that is then unified
// with an integer type variable `?I` that ultimately never gets
// resolved to a special integral type, `?T` is not considered unsolved,
// but `?I` is. The same is true for float variables.)
// (Note though that if we have a general type variable `?T`
// that is then unified with an integer type variable `?I`
// that ultimately never gets resolved to a special integral
// type, `?T` is not considered unsolved, but `?I` is. The
// same is true for float variables.)
let fallback = match ty.kind() {
_ if self.is_tainted_by_errors() => self.tcx.ty_error(),
ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
_ => match self.type_var_diverges(ty) {
Diverging::Diverges => self.tcx.mk_diverging_default(),
Diverging::NotDiverging => return false,
_ => match diverging_fallback.get(&ty) {
Some(&fallback_ty) => fallback_ty,
None => return false,
},
};
debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
@ -105,11 +136,10 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
true
}
/// Second round of fallback: Unconstrained type variables
/// created from the instantiation of an opaque
/// type fall back to the opaque type itself. This is a
/// somewhat incomplete attempt to manage "identity passthrough"
/// for `impl Trait` types.
/// Second round of fallback: Unconstrained type variables created
/// from the instantiation of an opaque type fall back to the
/// opaque type itself. This is a somewhat incomplete attempt to
/// manage "identity passthrough" for `impl Trait` types.
///
/// For example, in this code:
///
@ -158,4 +188,274 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
return false;
}
}
/// The "diverging fallback" system is rather complicated. This is
/// a result of our need to balance 'do the right thing' with
/// backwards compatibility.
///
/// "Diverging" type variables are variables created when we
/// coerce a `!` type into an unbound type variable `?X`. If they
/// never wind up being constrained, the "right and natural" thing
/// is that `?X` should "fallback" to `!`. This means that e.g. an
/// expression like `Some(return)` will ultimately wind up with a
/// type like `Option<!>` (presuming it is not assigned or
/// constrained to have some other type).
///
/// However, the fallback used to be `()` (before the `!` type was
/// added). Moreover, there are cases where the `!` type 'leaks
/// out' from dead code into type variables that affect live
/// code. The most common case is something like this:
///
/// ```rust
/// match foo() {
/// 22 => Default::default(), // call this type `?D`
/// _ => return, // return has type `!`
/// } // call the type of this match `?M`
/// ```
///
/// Here, coercing the type `!` into `?M` will create a diverging
/// type variable `?X` where `?X <: ?M`. We also have that `?D <:
/// ?M`. If `?M` winds up unconstrained, then `?X` will
/// fallback. If it falls back to `!`, then all the type variables
/// will wind up equal to `!` -- this includes the type `?D`
/// (since `!` doesn't implement `Default`, we wind up a "trait
/// not implemented" error in code like this). But since the
/// original fallback was `()`, this code used to compile with `?D
/// = ()`. This is somewhat surprising, since `Default::default()`
/// on its own would give an error because the types are
/// insufficiently constrained.
///
/// Our solution to this dilemma is to modify diverging variables
/// so that they can *either* fallback to `!` (the default) or to
/// `()` (the backwards compatibility case). We decide which
/// fallback to use based on whether there is a coercion pattern
/// like this:
///
/// ```
/// ?Diverging -> ?V
/// ?NonDiverging -> ?V
/// ?V != ?NonDiverging
/// ```
///
/// Here `?Diverging` represents some diverging type variable and
/// `?NonDiverging` represents some non-diverging type
/// variable. `?V` can be any type variable (diverging or not), so
/// long as it is not equal to `?NonDiverging`.
///
/// Intuitively, what we are looking for is a case where a
/// "non-diverging" type variable (like `?M` in our example above)
/// is coerced *into* some variable `?V` that would otherwise
/// fallback to `!`. In that case, we make `?V` fallback to `!`,
/// along with anything that would flow into `?V`.
///
/// The algorithm we use:
/// * Identify all variables that are coerced *into* by a
/// diverging variable. Do this by iterating over each
/// diverging, unsolved variable and finding all variables
/// reachable from there. Call that set `D`.
/// * Walk over all unsolved, non-diverging variables, and find
/// any variable that has an edge into `D`.
fn calculate_diverging_fallback(
&self,
unsolved_variables: &[Ty<'tcx>],
) -> FxHashMap<Ty<'tcx>, Ty<'tcx>> {
debug!("calculate_diverging_fallback({:?})", unsolved_variables);
let relationships = self.fulfillment_cx.borrow_mut().relationships().clone();
// Construct a coercion graph where an edge `A -> B` indicates
// a type variable is that is coerced
let coercion_graph = self.create_coercion_graph();
// Extract the unsolved type inference variable vids; note that some
// unsolved variables are integer/float variables and are excluded.
let unsolved_vids = unsolved_variables.iter().filter_map(|ty| ty.ty_vid());
// Compute the diverging root vids D -- that is, the root vid of
// those type variables that (a) are the target of a coercion from
// a `!` type and (b) have not yet been solved.
//
// These variables are the ones that are targets for fallback to
// either `!` or `()`.
let diverging_roots: FxHashSet<ty::TyVid> = self
.diverging_type_vars
.borrow()
.iter()
.map(|&ty| self.infcx.shallow_resolve(ty))
.filter_map(|ty| ty.ty_vid())
.map(|vid| self.infcx.root_var(vid))
.collect();
debug!(
"calculate_diverging_fallback: diverging_type_vars={:?}",
self.diverging_type_vars.borrow()
);
debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots);
// Find all type variables that are reachable from a diverging
// type variable. These will typically default to `!`, unless
// we find later that they are *also* reachable from some
// other type variable outside this set.
let mut roots_reachable_from_diverging = DepthFirstSearch::new(&coercion_graph);
let mut diverging_vids = vec![];
let mut non_diverging_vids = vec![];
for unsolved_vid in unsolved_vids {
let root_vid = self.infcx.root_var(unsolved_vid);
debug!(
"calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}",
unsolved_vid,
root_vid,
diverging_roots.contains(&root_vid),
);
if diverging_roots.contains(&root_vid) {
diverging_vids.push(unsolved_vid);
roots_reachable_from_diverging.push_start_node(root_vid);
debug!(
"calculate_diverging_fallback: root_vid={:?} reaches {:?}",
root_vid,
coercion_graph.depth_first_search(root_vid).collect::<Vec<_>>()
);
// drain the iterator to visit all nodes reachable from this node
roots_reachable_from_diverging.complete_search();
} else {
non_diverging_vids.push(unsolved_vid);
}
}
debug!(
"calculate_diverging_fallback: roots_reachable_from_diverging={:?}",
roots_reachable_from_diverging,
);
// Find all type variables N0 that are not reachable from a
// diverging variable, and then compute the set reachable from
// N0, which we call N. These are the *non-diverging* type
// variables. (Note that this set consists of "root variables".)
let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph);
for &non_diverging_vid in &non_diverging_vids {
let root_vid = self.infcx.root_var(non_diverging_vid);
if roots_reachable_from_diverging.visited(root_vid) {
continue;
}
roots_reachable_from_non_diverging.push_start_node(root_vid);
roots_reachable_from_non_diverging.complete_search();
}
debug!(
"calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}",
roots_reachable_from_non_diverging,
);
debug!("inherited: {:#?}", self.inh.fulfillment_cx.borrow_mut().pending_obligations());
debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations());
debug!("relationships: {:#?}", relationships);
// For each diverging variable, figure out whether it can
// reach a member of N. If so, it falls back to `()`. Else
// `!`.
let mut diverging_fallback = FxHashMap::default();
diverging_fallback.reserve(diverging_vids.len());
for &diverging_vid in &diverging_vids {
let diverging_ty = self.tcx.mk_ty_var(diverging_vid);
let root_vid = self.infcx.root_var(diverging_vid);
let can_reach_non_diverging = coercion_graph
.depth_first_search(root_vid)
.any(|n| roots_reachable_from_non_diverging.visited(n));
let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false };
for (vid, rel) in relationships.iter() {
if self.infcx.root_var(*vid) == root_vid {
relationship.self_in_trait |= rel.self_in_trait;
relationship.output |= rel.output;
}
}
if relationship.self_in_trait && relationship.output {
// This case falls back to () to ensure that the code pattern in
// src/test/ui/never_type/fallback-closure-ret.rs continues to
// compile when never_type_fallback is enabled.
//
// This rule is not readily explainable from first principles,
// but is rather intended as a patchwork fix to ensure code
// which compiles before the stabilization of never type
// fallback continues to work.
//
// Typically this pattern is encountered in a function taking a
// closure as a parameter, where the return type of that closure
// (checked by `relationship.output`) is expected to implement
// some trait (checked by `relationship.self_in_trait`). This
// can come up in non-closure cases too, so we do not limit this
// rule to specifically `FnOnce`.
//
// When the closure's body is something like `panic!()`, the
// return type would normally be inferred to `!`. However, it
// needs to fall back to `()` in order to still compile, as the
// trait is specifically implemented for `()` but not `!`.
//
// For details on the requirements for these relationships to be
// set, see the relationship finding module in
// compiler/rustc_trait_selection/src/traits/relationships.rs.
debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
} else if can_reach_non_diverging {
debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
} else {
debug!("fallback to ! - all diverging: {:?}", diverging_vid);
diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default());
}
}
diverging_fallback
}
/// Returns a graph whose nodes are (unresolved) inference variables and where
/// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`.
fn create_coercion_graph(&self) -> VecGraph<ty::TyVid> {
let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations();
debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations);
let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations
.into_iter()
.filter_map(|obligation| {
// The predicates we are looking for look like `Coerce(?A -> ?B)`.
// They will have no bound variables.
obligation.predicate.kind().no_bound_vars()
})
.filter_map(|atom| {
// We consider both subtyping and coercion to imply 'flow' from
// some position in the code `a` to a different position `b`.
// This is then used to determine which variables interact with
// live code, and as such must fall back to `()` to preserve
// soundness.
//
// In practice currently the two ways that this happens is
// coercion and subtyping.
let (a, b) = if let ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) = atom {
(a, b)
} else if let ty::PredicateKind::Subtype(ty::SubtypePredicate {
a_is_expected: _,
a,
b,
}) = atom
{
(a, b)
} else {
return None;
};
let a_vid = self.root_vid(a)?;
let b_vid = self.root_vid(b)?;
Some((a_vid, b_vid))
})
.collect();
debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges);
let num_ty_vars = self.infcx.num_ty_vars();
VecGraph::new(num_ty_vars, coercion_edges)
}
/// If `ty` is an unresolved type variable, returns its root vid.
fn root_vid(&self, ty: Ty<'tcx>) -> Option<ty::TyVid> {
Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?))
}
}

View file

@ -286,6 +286,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
for a in &adj {
if let Adjust::NeverToAny = a.kind {
if a.target.is_ty_var() {
self.diverging_type_vars.borrow_mut().insert(a.target);
debug!("apply_adjustments: adding `{:?}` as diverging type var", a.target);
}
}
}
let autoborrow_mut = adj.iter().any(|adj| {
matches!(
adj,

View file

@ -1,6 +1,7 @@
use super::callee::DeferredCallResolution;
use super::MaybeInProgressTables;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def_id::{DefIdMap, LocalDefId};
use rustc_hir::HirIdMap;
@ -56,6 +57,11 @@ pub struct Inherited<'a, 'tcx> {
pub(super) constness: hir::Constness,
pub(super) body_id: Option<hir::BodyId>,
/// Whenever we introduce an adjustment from `!` into a type variable,
/// we record that type variable here. This is later used to inform
/// fallback. See the `fallback` module for details.
pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>,
}
impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> {
@ -121,6 +127,7 @@ impl Inherited<'a, 'tcx> {
deferred_call_resolutions: RefCell::new(Default::default()),
deferred_cast_checks: RefCell::new(Vec::new()),
deferred_generator_interiors: RefCell::new(Vec::new()),
diverging_type_vars: RefCell::new(Default::default()),
constness,
body_id,
}

View file

@ -1,6 +1,7 @@
use crate::structured_errors::StructuredDiagnostic;
use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId};
use rustc_hir as hir;
use rustc_middle::hir::map::fn_sig;
use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath;
use rustc_middle::ty::{self as ty, TyCtxt};
use rustc_session::Session;
@ -292,12 +293,30 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
&self,
num_params_to_take: usize,
) -> String {
let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(|node| fn_sig(node));
let is_used_in_input = |def_id| {
fn_sig.map_or(false, |fn_sig| {
fn_sig.decl.inputs.iter().any(|ty| match ty.kind {
hir::TyKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: hir::def::Res::Def(_, id), .. },
)) if *id == def_id => true,
_ => false,
})
})
};
self.gen_params
.params
.iter()
.skip(self.params_offset + self.num_provided_type_or_const_args())
.take(num_params_to_take)
.map(|param| param.name.to_string())
.map(|param| match param.kind {
// This is being infered from the item's inputs, no need to set it.
ty::GenericParamDefKind::Type { .. } if is_used_in_input(param.def_id) => {
"_".to_string()
}
_ => param.name.to_string(),
})
.collect::<Vec<_>>()
.join(", ")
}

View file

@ -1849,17 +1849,17 @@ macro_rules! int_impl {
#[doc = concat!("let a: ", stringify!($SelfT)," = 8;")]
/// let b = 3;
///
/// assert_eq!(a.div_floor(b), 2);
/// assert_eq!(a.div_floor(-b), -3);
/// assert_eq!((-a).div_floor(b), -3);
/// assert_eq!((-a).div_floor(-b), 2);
/// assert_eq!(a.unstable_div_floor(b), 2);
/// assert_eq!(a.unstable_div_floor(-b), -3);
/// assert_eq!((-a).unstable_div_floor(b), -3);
/// assert_eq!((-a).unstable_div_floor(-b), 2);
/// ```
#[unstable(feature = "int_roundings", issue = "88581")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn div_floor(self, rhs: Self) -> Self {
pub const fn unstable_div_floor(self, rhs: Self) -> Self {
let d = self / rhs;
let r = self % rhs;
if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
@ -1884,17 +1884,17 @@ macro_rules! int_impl {
#[doc = concat!("let a: ", stringify!($SelfT)," = 8;")]
/// let b = 3;
///
/// assert_eq!(a.div_ceil(b), 3);
/// assert_eq!(a.div_ceil(-b), -2);
/// assert_eq!((-a).div_ceil(b), -2);
/// assert_eq!((-a).div_ceil(-b), 3);
/// assert_eq!(a.unstable_div_ceil(b), 3);
/// assert_eq!(a.unstable_div_ceil(-b), -2);
/// assert_eq!((-a).unstable_div_ceil(b), -2);
/// assert_eq!((-a).unstable_div_ceil(-b), 3);
/// ```
#[unstable(feature = "int_roundings", issue = "88581")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn div_ceil(self, rhs: Self) -> Self {
pub const fn unstable_div_ceil(self, rhs: Self) -> Self {
let d = self / rhs;
let r = self % rhs;
if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) {
@ -1919,21 +1919,21 @@ macro_rules! int_impl {
///
/// ```
/// #![feature(int_roundings)]
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")]
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")]
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(-8), 16);")]
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(-8), 16);")]
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(8), -16);")]
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(8), -16);")]
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(-8), -16);")]
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(-8), -24);")]
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(8), 16);")]
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(8), 24);")]
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(-8), 16);")]
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(-8), 16);")]
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").unstable_next_multiple_of(8), -16);")]
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").unstable_next_multiple_of(8), -16);")]
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").unstable_next_multiple_of(-8), -16);")]
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").unstable_next_multiple_of(-8), -24);")]
/// ```
#[unstable(feature = "int_roundings", issue = "88581")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn next_multiple_of(self, rhs: Self) -> Self {
pub const fn unstable_next_multiple_of(self, rhs: Self) -> Self {
// This would otherwise fail when calculating `r` when self == T::MIN.
if rhs == -1 {
return self;

View file

@ -1859,12 +1859,12 @@ macro_rules! uint_impl {
///
/// ```
/// #![feature(int_roundings)]
#[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_floor(4), 1);")]
#[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".unstable_div_floor(4), 1);")]
/// ```
#[unstable(feature = "int_roundings", issue = "88581")]
#[inline(always)]
#[rustc_inherit_overflow_checks]
pub const fn div_floor(self, rhs: Self) -> Self {
pub const fn unstable_div_floor(self, rhs: Self) -> Self {
self / rhs
}
@ -1880,12 +1880,12 @@ macro_rules! uint_impl {
///
/// ```
/// #![feature(int_roundings)]
#[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_ceil(4), 2);")]
#[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".unstable_div_ceil(4), 2);")]
/// ```
#[unstable(feature = "int_roundings", issue = "88581")]
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn div_ceil(self, rhs: Self) -> Self {
pub const fn unstable_div_ceil(self, rhs: Self) -> Self {
let d = self / rhs;
let r = self % rhs;
if r > 0 && rhs > 0 {
@ -1908,15 +1908,15 @@ macro_rules! uint_impl {
///
/// ```
/// #![feature(int_roundings)]
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")]
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")]
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(8), 16);")]
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(8), 24);")]
/// ```
#[unstable(feature = "int_roundings", issue = "88581")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn next_multiple_of(self, rhs: Self) -> Self {
pub const fn unstable_next_multiple_of(self, rhs: Self) -> Self {
match self % rhs {
0 => self,
r => self + (rhs - r)

View file

@ -294,33 +294,33 @@ macro_rules! int_module {
fn test_div_floor() {
let a: $T = 8;
let b = 3;
assert_eq!(a.div_floor(b), 2);
assert_eq!(a.div_floor(-b), -3);
assert_eq!((-a).div_floor(b), -3);
assert_eq!((-a).div_floor(-b), 2);
assert_eq!(a.unstable_div_floor(b), 2);
assert_eq!(a.unstable_div_floor(-b), -3);
assert_eq!((-a).unstable_div_floor(b), -3);
assert_eq!((-a).unstable_div_floor(-b), 2);
}
#[test]
fn test_div_ceil() {
let a: $T = 8;
let b = 3;
assert_eq!(a.div_ceil(b), 3);
assert_eq!(a.div_ceil(-b), -2);
assert_eq!((-a).div_ceil(b), -2);
assert_eq!((-a).div_ceil(-b), 3);
assert_eq!(a.unstable_div_ceil(b), 3);
assert_eq!(a.unstable_div_ceil(-b), -2);
assert_eq!((-a).unstable_div_ceil(b), -2);
assert_eq!((-a).unstable_div_ceil(-b), 3);
}
#[test]
fn test_next_multiple_of() {
assert_eq!((16 as $T).next_multiple_of(8), 16);
assert_eq!((23 as $T).next_multiple_of(8), 24);
assert_eq!((16 as $T).next_multiple_of(-8), 16);
assert_eq!((23 as $T).next_multiple_of(-8), 16);
assert_eq!((-16 as $T).next_multiple_of(8), -16);
assert_eq!((-23 as $T).next_multiple_of(8), -16);
assert_eq!((-16 as $T).next_multiple_of(-8), -16);
assert_eq!((-23 as $T).next_multiple_of(-8), -24);
assert_eq!(MIN.next_multiple_of(-1), MIN);
assert_eq!((16 as $T).unstable_next_multiple_of(8), 16);
assert_eq!((23 as $T).unstable_next_multiple_of(8), 24);
assert_eq!((16 as $T).unstable_next_multiple_of(-8), 16);
assert_eq!((23 as $T).unstable_next_multiple_of(-8), 16);
assert_eq!((-16 as $T).unstable_next_multiple_of(8), -16);
assert_eq!((-23 as $T).unstable_next_multiple_of(8), -16);
assert_eq!((-16 as $T).unstable_next_multiple_of(-8), -16);
assert_eq!((-23 as $T).unstable_next_multiple_of(-8), -24);
assert_eq!(MIN.unstable_next_multiple_of(-1), MIN);
}
#[test]

View file

@ -208,19 +208,19 @@ macro_rules! uint_module {
#[test]
fn test_div_floor() {
assert_eq!((8 as $T).div_floor(3), 2);
assert_eq!((8 as $T).unstable_div_floor(3), 2);
}
#[test]
fn test_div_ceil() {
assert_eq!((8 as $T).div_ceil(3), 3);
assert_eq!((8 as $T).unstable_div_ceil(3), 3);
}
#[test]
fn test_next_multiple_of() {
assert_eq!((16 as $T).next_multiple_of(8), 16);
assert_eq!((23 as $T).next_multiple_of(8), 24);
assert_eq!(MAX.next_multiple_of(1), MAX);
assert_eq!((16 as $T).unstable_next_multiple_of(8), 16);
assert_eq!((23 as $T).unstable_next_multiple_of(8), 24);
assert_eq!(MAX.unstable_next_multiple_of(1), MAX);
}
#[test]

View file

@ -248,7 +248,11 @@ impl<T> Packet<T> {
// Returns true if blocking should proceed.
fn decrement(&self, token: SignalToken) -> StartResult {
unsafe {
assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
assert_eq!(
self.to_wake.load(Ordering::SeqCst),
0,
"This is a known bug in the Rust standard library. See https://github.com/rust-lang/rust/issues/39364"
);
let ptr = token.cast_to_usize();
self.to_wake.store(ptr, Ordering::SeqCst);

@ -1 +1 @@
Subproject commit 86c7daa627aefda1371568b948eba21edf720747
Subproject commit cba558df777a045b5657d56c29944e9e8fd3a776

View file

@ -1,6 +1,6 @@
// aux-build:primitive-doc.rs
// compile-flags: --extern-html-root-url=primitive_doc=../ -Z unstable-options
// ignore-windows
// only-linux
#![feature(no_core)]
#![no_core]

View file

@ -1,7 +1,7 @@
// aux-build:my-core.rs
// build-aux-docs
// ignore-cross-compile
// ignore-windows
// only-linux
#![deny(broken_intra_doc_links)]
#![feature(no_core, lang_items)]

View file

@ -0,0 +1,8 @@
// normalize-stderr-test: "couldn't read.*" -> "couldn't read the file"
#![feature(extended_key_value_attributes)]
#![doc = include_str!("../not_existing_file.md")]
struct Documented {}
//~^^ ERROR couldn't read
fn main() {}

View file

@ -0,0 +1,10 @@
error: couldn't read the file
--> $DIR/extented-attribute-macro-error.rs:4:10
|
LL | #![doc = include_str!("../not_existing_file.md")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error

View file

@ -0,0 +1,19 @@
error[E0277]: the trait bound `(): std::error::Error` is not satisfied
--> $DIR/coerce-issue-49593-box-never.rs:17:53
|
LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
|
= note: required for the cast to the object type `dyn std::error::Error`
error[E0277]: the trait bound `(): std::error::Error` is not satisfied
--> $DIR/coerce-issue-49593-box-never.rs:22:49
|
LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
|
= note: required for the cast to the object type `(dyn std::error::Error + 'static)`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,5 +1,9 @@
// check-pass
#![feature(never_type, never_type_fallback)]
// revisions: nofallback fallback
//[fallback] check-pass
//[nofallback] check-fail
#![feature(never_type)]
#![cfg_attr(fallback, feature(never_type_fallback))]
#![allow(unreachable_code)]
use std::error::Error;
@ -11,10 +15,12 @@ fn raw_ptr_box<T>(t: T) -> *mut T {
fn foo(x: !) -> Box<dyn Error> {
/* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
//[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied
}
fn foo_raw_ptr(x: !) -> *mut dyn Error {
/* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
//[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied
}
fn no_coercion(d: *mut dyn Error) -> *mut dyn Error {

View file

@ -34,7 +34,7 @@ note: ...which requires type-checking `cycle1`...
|
LL | send(cycle2().clone());
| ^^^^
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
= note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
note: ...which requires computing type of `cycle2::{opaque#0}`...
--> $DIR/auto-trait-leak.rs:19:16
|
@ -70,7 +70,7 @@ note: ...which requires type-checking `cycle2`...
|
LL | send(cycle1().clone());
| ^^^^
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
= note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
= note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
note: cycle used when checking item types in top-level module
--> $DIR/auto-trait-leak.rs:1:1

View file

@ -2,6 +2,7 @@
// ignore-wasm32-bare compiled with panic=abort by default
// revisions: mir thir
// [thir]compile-flags: -Zthir-unsafeck
// ignore-tidy-linelength
// This test checks panic emitted from `mem::{uninitialized,zeroed}`.
@ -114,11 +115,11 @@ fn main() {
test_panic_msg(
|| mem::uninitialized::<*const dyn Send>(),
"attempted to leave type `*const dyn std::marker::Send` uninitialized, which is invalid"
"attempted to leave type `*const dyn core::marker::Send` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<*const dyn Send>(),
"attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid"
"attempted to zero-initialize type `*const dyn core::marker::Send`, which is invalid"
);
/* FIXME(#66151) we conservatively do not error here yet.
@ -145,12 +146,12 @@ fn main() {
test_panic_msg(
|| mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
"attempted to leave type `(std::ptr::NonNull<u32>, u32, u32)` uninitialized, \
"attempted to leave type `(core::ptr::non_null::NonNull<u32>, u32, u32)` uninitialized, \
which is invalid"
);
test_panic_msg(
|| mem::zeroed::<(NonNull<u32>, u32, u32)>(),
"attempted to zero-initialize type `(std::ptr::NonNull<u32>, u32, u32)`, \
"attempted to zero-initialize type `(core::ptr::non_null::NonNull<u32>, u32, u32)`, \
which is invalid"
);
@ -187,7 +188,7 @@ fn main() {
);
test_panic_msg(
|| mem::uninitialized::<ManuallyDrop<LR>>(),
"attempted to leave type `std::mem::ManuallyDrop<LR>` uninitialized, which is invalid"
"attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR>` uninitialized, which is invalid"
);
// Some things that should work.

View file

@ -1,5 +1,5 @@
error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied
--> $DIR/defaulted-never-note.rs:26:5
--> $DIR/defaulted-never-note.rs:30:5
|
LL | foo(_x);
| ^^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!`
@ -8,7 +8,7 @@ LL | foo(_x);
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information).
= help: did you intend to use the type `()` here instead?
note: required by a bound in `foo`
--> $DIR/defaulted-never-note.rs:21:11
--> $DIR/defaulted-never-note.rs:25:11
|
LL | fn foo<T: ImplementedForUnitButNotNever>(_t: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`

View file

@ -1,6 +1,10 @@
// revisions: nofallback fallback
//[nofallback] run-pass
//[fallback] check-fail
// We need to opt into the `never_type_fallback` feature
// to trigger the requirement that this is testing.
#![feature(never_type, never_type_fallback)]
#![cfg_attr(fallback, feature(never_type, never_type_fallback))]
#![allow(unused)]
@ -19,16 +23,16 @@ trait ImplementedForUnitButNotNever {}
impl ImplementedForUnitButNotNever for () {}
fn foo<T: ImplementedForUnitButNotNever>(_t: T) {}
//~^ NOTE required by this bound in `foo`
//~| NOTE required by a bound in `foo`
//[fallback]~^ NOTE required by this bound in `foo`
//[fallback]~| NOTE required by a bound in `foo`
fn smeg() {
let _x = return;
foo(_x);
//~^ ERROR the trait bound
//~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented
//~| NOTE this trait is implemented for `()`
//~| NOTE this error might have been caused
//~| HELP did you intend
//[fallback]~^ ERROR the trait bound
//[fallback]~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented
//[fallback]~| NOTE this trait is implemented for `()`
//[fallback]~| NOTE this error might have been caused
//[fallback]~| HELP did you intend
}
fn main() {

View file

@ -1,30 +1,28 @@
// revisions: nofallback fallback
// run-pass
#![allow(dead_code)]
#![allow(unused_assignments)]
#![allow(unused_variables)]
#![allow(unreachable_code)]
// Test various cases where we permit an unconstrained variable
// to fallback based on control-flow.
//
// These represent current behavior, but are pretty dubious. I would
// like to revisit these and potentially change them. --nmatsakis
// to fallback based on control-flow. In all of these cases,
// the type variable winds up being the target of both a `!` coercion
// and a coercion from a non-`!` variable, and hence falls back to `()`.
#![cfg_attr(fallback, feature(never_type, never_type_fallback))]
#![feature(never_type, never_type_fallback)]
trait BadDefault {
trait UnitDefault {
fn default() -> Self;
}
impl BadDefault for u32 {
impl UnitDefault for u32 {
fn default() -> Self {
0
}
}
impl BadDefault for ! {
fn default() -> ! {
impl UnitDefault for () {
fn default() -> () {
panic!()
}
}
@ -33,7 +31,7 @@ fn assignment() {
let x;
if true {
x = BadDefault::default();
x = UnitDefault::default();
} else {
x = return;
}
@ -45,13 +43,13 @@ fn assignment_rev() {
if true {
x = return;
} else {
x = BadDefault::default();
x = UnitDefault::default();
}
}
fn if_then_else() {
let _x = if true {
BadDefault::default()
UnitDefault::default()
} else {
return;
};
@ -61,19 +59,19 @@ fn if_then_else_rev() {
let _x = if true {
return;
} else {
BadDefault::default()
UnitDefault::default()
};
}
fn match_arm() {
let _x = match Ok(BadDefault::default()) {
let _x = match Ok(UnitDefault::default()) {
Ok(v) => v,
Err(()) => return,
};
}
fn match_arm_rev() {
let _x = match Ok(BadDefault::default()) {
let _x = match Ok(UnitDefault::default()) {
Err(()) => return,
Ok(v) => v,
};
@ -84,7 +82,7 @@ fn loop_break() {
if false {
break return;
} else {
break BadDefault::default();
break UnitDefault::default();
}
};
}
@ -94,9 +92,9 @@ fn loop_break_rev() {
if false {
break return;
} else {
break BadDefault::default();
break UnitDefault::default();
}
};
}
fn main() { }
fn main() {}

View file

@ -0,0 +1,18 @@
error[E0277]: the trait bound `!: Test` is not satisfied
--> $DIR/diverging-fallback-no-leak.rs:17:5
|
LL | unconstrained_arg(return);
| ^^^^^^^^^^^^^^^^^ the trait `Test` is not implemented for `!`
|
= note: this trait is implemented for `()`.
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information).
= help: did you intend to use the type `()` here instead?
note: required by a bound in `unconstrained_arg`
--> $DIR/diverging-fallback-no-leak.rs:12:25
|
LL | fn unconstrained_arg<T: Test>(_: T) {}
| ^^^^ required by this bound in `unconstrained_arg`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,19 @@
// revisions: nofallback fallback
//[nofallback] check-pass
#![cfg_attr(fallback, feature(never_type, never_type_fallback))]
fn make_unit() {}
trait Test {}
impl Test for i32 {}
impl Test for () {}
fn unconstrained_arg<T: Test>(_: T) {}
fn main() {
// Here the type variable falls back to `!`,
// and hence we get a type error.
unconstrained_arg(return);
//[fallback]~^ ERROR trait bound `!: Test` is not satisfied
}

View file

@ -0,0 +1,37 @@
// Variant of diverging-falllback-control-flow that tests
// the specific case of a free function with an unconstrained
// return type. This captures the pattern we saw in the wild
// in the objc crate, where changing the fallback from `!` to `()`
// resulted in unsoundness.
//
// check-pass
// revisions: nofallback fallback
#![cfg_attr(fallback, feature(never_type, never_type_fallback))]
fn make_unit() {}
trait UnitReturn {}
impl UnitReturn for i32 {}
impl UnitReturn for () {}
fn unconstrained_return<T: UnitReturn>() -> T {
unsafe {
let make_unit_fn: fn() = make_unit;
let ffi: fn() -> T = std::mem::transmute(make_unit_fn);
ffi()
}
}
fn main() {
// In Ye Olde Days, the `T` parameter of `unconstrained_return`
// winds up "entangled" with the `!` type that results from
// `panic!`, and hence falls back to `()`. This is kind of unfortunate
// and unexpected. When we introduced the `!` type, the original
// idea was to change that fallback to `!`, but that would have resulted
// in this code no longer compiling (or worse, in some cases it injected
// unsound results).
let _ = if true { unconstrained_return() } else { panic!() };
}

View file

@ -0,0 +1,23 @@
// This test verifies that never type fallback preserves the following code in a
// compiling state. This pattern is fairly common in the wild, notably seen in
// wasmtime v0.16. Typically this is some closure wrapper that expects a
// collection of 'known' signatures, and -> ! is not included in that set.
//
// This test is specifically targeted by the unit type fallback when
// encountering a set of obligations like `?T: Foo` and `Trait::Projection =
// ?T`. In the code below, these are `R: Bar` and `Fn::Output = R`.
//
// revisions: nofallback fallback
// check-pass
#![cfg_attr(fallback, feature(never_type_fallback))]
trait Bar { }
impl Bar for () { }
impl Bar for u32 { }
fn foo<R: Bar>(_: impl Fn() -> R) {}
fn main() {
foo(|| panic!());
}

View file

@ -0,0 +1,17 @@
error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 21:6] as FnOnce<()>>::Output == ()`
--> $DIR/fallback-closure-wrap.rs:18:31
|
LL | let error = Closure::wrap(Box::new(move || {
| _______________________________^
LL | |
LL | | panic!("Can't connect to server.");
LL | | }) as Box<dyn FnMut()>);
| |______^ expected `()`, found `!`
|
= note: expected unit type `()`
found type `!`
= note: required for the cast to the object type `dyn FnMut()`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0271`.

View file

@ -0,0 +1,30 @@
// This is a minified example from Crater breakage observed when attempting to
// stabilize never type, nstoddard/webgl-gui @ 22f0169f.
//
// This particular test case currently fails as the inference to `()` rather
// than `!` happens as a result of an `as` cast, which is not currently tracked.
// Crater did not find many cases of this occuring, but it is included for
// awareness.
//
// revisions: nofallback fallback
//[nofallback] check-pass
//[fallback] check-fail
#![cfg_attr(fallback, feature(never_type_fallback))]
use std::marker::PhantomData;
fn main() {
let error = Closure::wrap(Box::new(move || {
//[fallback]~^ ERROR type mismatch resolving
panic!("Can't connect to server.");
}) as Box<dyn FnMut()>);
}
struct Closure<T: ?Sized>(PhantomData<T>);
impl<T: ?Sized> Closure<T> {
fn wrap(data: Box<T>) -> Closure<T> {
todo!()
}
}

View file

@ -0,0 +1,17 @@
error[E0277]: the trait bound `E: From<()>` is not satisfied
--> $DIR/never-value-fallback-issue-66757.rs:27:5
|
LL | <E as From<_>>::from(never);
| ^^^^^^^^^^^^^^^^^^^^ the trait `From<()>` is not implemented for `E`
|
= help: the following implementations were found:
<E as From<!>>
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -4,12 +4,13 @@
// never) and an uninferred variable (here the argument to `From`) it
// doesn't fallback to `()` but rather `!`.
//
// run-pass
// revisions: nofallback fallback
//[fallback] run-pass
//[nofallback] check-fail
#![feature(never_type)]
// FIXME(#67225) -- this should be true even without the fallback gate.
#![feature(never_type_fallback)]
#![cfg_attr(fallback, feature(never_type_fallback))]
struct E;
@ -23,7 +24,7 @@ impl From<!> for E {
#[allow(dead_code)]
fn foo(never: !) {
<E as From<!>>::from(never); // Ok
<E as From<_>>::from(never); // Inference fails here
<E as From<_>>::from(never); //[nofallback]~ ERROR trait bound `E: From<()>` is not satisfied
}
fn main() { }

View file

@ -1,8 +1,8 @@
//~ ERROR cycle detected when computing layout of `S`
//~| NOTE ...which requires computing layout of `std::option::Option<<S as Mirror>::It>`...
//~| NOTE ...which requires computing layout of `std::option::Option<S>`...
//~| NOTE ...which requires computing layout of `core::option::Option<<S as Mirror>::It>`...
//~| NOTE ...which requires computing layout of `core::option::Option<S>`...
//~| NOTE ...which again requires computing layout of `S`, completing the cycle
//~| NOTE cycle used when computing layout of `std::option::Option<S>`
//~| NOTE cycle used when computing layout of `core::option::Option<S>`
// build-fail

View file

@ -1,9 +1,9 @@
error[E0391]: cycle detected when computing layout of `S`
|
= note: ...which requires computing layout of `std::option::Option<<S as Mirror>::It>`...
= note: ...which requires computing layout of `std::option::Option<S>`...
= note: ...which requires computing layout of `core::option::Option<<S as Mirror>::It>`...
= note: ...which requires computing layout of `core::option::Option<S>`...
= note: ...which again requires computing layout of `S`, completing the cycle
= note: cycle used when computing layout of `std::option::Option<S>`
= note: cycle used when computing layout of `core::option::Option<S>`
error: aborting due to previous error

View file

@ -0,0 +1,8 @@
// run-rustfix
fn two_type_params<A, B>(_: B) {}
fn main() {
two_type_params::<String, _>(100); //~ ERROR this function takes 2 generic arguments
two_type_params::<String, _>(100);
}

View file

@ -0,0 +1,8 @@
// run-rustfix
fn two_type_params<A, B>(_: B) {}
fn main() {
two_type_params::<String>(100); //~ ERROR this function takes 2 generic arguments
two_type_params::<String, _>(100);
}

View file

@ -0,0 +1,21 @@
error[E0107]: this function takes 2 generic arguments but 1 generic argument was supplied
--> $DIR/missing-type-param-used-in-param.rs:6:5
|
LL | two_type_params::<String>(100);
| ^^^^^^^^^^^^^^^ ------ supplied 1 generic argument
| |
| expected 2 generic arguments
|
note: function defined here, with 2 generic parameters: `A`, `B`
--> $DIR/missing-type-param-used-in-param.rs:3:4
|
LL | fn two_type_params<A, B>(_: B) {}
| ^^^^^^^^^^^^^^^ - -
help: add missing generic argument
|
LL | two_type_params::<String, _>(100);
| +++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0107`.

View file

@ -9,7 +9,7 @@ note: ...which requires type-checking `m::bar`...
|
LL | is_send(foo());
| ^^^^^^^
= note: ...which requires evaluating trait selection obligation `impl std::fmt::Debug: std::marker::Send`...
= note: ...which requires evaluating trait selection obligation `impl core::fmt::Debug: core::marker::Send`...
= note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
note: cycle used when checking item types in module `m`
--> $DIR/auto-trait-leakage3.rs:6:1

View file

@ -9,7 +9,7 @@ note: ...which requires type-checking `m::bar`...
|
LL | is_send(foo()); // Today: error
| ^^^^^^^
= note: ...which requires evaluating trait selection obligation `impl std::fmt::Debug: std::marker::Send`...
= note: ...which requires evaluating trait selection obligation `impl core::fmt::Debug: core::marker::Send`...
= note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
note: cycle used when checking item types in module `m`
--> $DIR/inference-cycle.rs:4:1