Auto merge of #91255 - b-naber:normalization-ice, r=jackh276
Implement version of normalize_erasing_regions that allows for normalization failure Fixes https://github.com/rust-lang/rust/issues/59324 Fixes https://github.com/rust-lang/rust/issues/67684 Fixes https://github.com/rust-lang/rust/issues/69398 Fixes https://github.com/rust-lang/rust/issues/71113 Fixes https://github.com/rust-lang/rust/issues/82079 Fixes #85103 Fixes https://github.com/rust-lang/rust/issues/88856 Fixes #91231 Fixes https://github.com/rust-lang/rust/issues/91234 Previously we called `normalize_erasing_regions` inside `layout_of`. `normalize_erasing_regions` assumes that the normalization succeeds. Since some `layout_of` calls happen before typecheck has finished, we introduce a new variant that allows for returning an error.
This commit is contained in:
commit
f04a2f4b8e
18 changed files with 600 additions and 5 deletions
|
@ -1337,7 +1337,9 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
|
||||||
let layout = match cx.layout_of(ty) {
|
let layout = match cx.layout_of(ty) {
|
||||||
Ok(layout) => layout,
|
Ok(layout) => layout,
|
||||||
Err(
|
Err(
|
||||||
ty::layout::LayoutError::Unknown(_) | ty::layout::LayoutError::SizeOverflow(_),
|
ty::layout::LayoutError::Unknown(_)
|
||||||
|
| ty::layout::LayoutError::SizeOverflow(_)
|
||||||
|
| ty::layout::LayoutError::NormalizationFailure(_, _),
|
||||||
) => return,
|
) => return,
|
||||||
};
|
};
|
||||||
let (variants, tag) = match layout.variants {
|
let (variants, tag) = match layout.variants {
|
||||||
|
|
|
@ -492,9 +492,6 @@ impl dyn MachineStopType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
|
||||||
static_assert_size!(InterpError<'_>, 64);
|
|
||||||
|
|
||||||
pub enum InterpError<'tcx> {
|
pub enum InterpError<'tcx> {
|
||||||
/// The program caused undefined behavior.
|
/// The program caused undefined behavior.
|
||||||
UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
|
UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
|
||||||
|
|
|
@ -1644,6 +1644,11 @@ rustc_queries! {
|
||||||
desc { "normalizing `{:?}`", goal }
|
desc { "normalizing `{:?}`", goal }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Implement `normalize_generic_arg_after_erasing_regions` and
|
||||||
|
// `normalize_mir_const_after_erasing_regions` in terms of
|
||||||
|
// `try_normalize_generic_arg_after_erasing_regions` and
|
||||||
|
// `try_normalize_mir_const_after_erasing_regions`, respectively.
|
||||||
|
|
||||||
/// Do not call this query directly: invoke `normalize_erasing_regions` instead.
|
/// Do not call this query directly: invoke `normalize_erasing_regions` instead.
|
||||||
query normalize_generic_arg_after_erasing_regions(
|
query normalize_generic_arg_after_erasing_regions(
|
||||||
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
|
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
|
||||||
|
@ -1658,6 +1663,20 @@ rustc_queries! {
|
||||||
desc { "normalizing `{}`", goal.value }
|
desc { "normalizing `{}`", goal.value }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
|
||||||
|
query try_normalize_generic_arg_after_erasing_regions(
|
||||||
|
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
|
||||||
|
) -> Result<GenericArg<'tcx>, NoSolution> {
|
||||||
|
desc { "normalizing `{}`", goal.value }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
|
||||||
|
query try_normalize_mir_const_after_erasing_regions(
|
||||||
|
goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
|
||||||
|
) -> Result<mir::ConstantKind<'tcx>, NoSolution> {
|
||||||
|
desc { "normalizing `{}`", goal.value }
|
||||||
|
}
|
||||||
|
|
||||||
query implied_outlives_bounds(
|
query implied_outlives_bounds(
|
||||||
goal: CanonicalTyGoal<'tcx>
|
goal: CanonicalTyGoal<'tcx>
|
||||||
) -> Result<
|
) -> Result<
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
|
use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
|
||||||
|
use crate::ty::normalize_erasing_regions::NormalizationError;
|
||||||
use crate::ty::subst::Subst;
|
use crate::ty::subst::Subst;
|
||||||
use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
|
use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
|
@ -199,6 +200,7 @@ pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
|
||||||
pub enum LayoutError<'tcx> {
|
pub enum LayoutError<'tcx> {
|
||||||
Unknown(Ty<'tcx>),
|
Unknown(Ty<'tcx>),
|
||||||
SizeOverflow(Ty<'tcx>),
|
SizeOverflow(Ty<'tcx>),
|
||||||
|
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> fmt::Display for LayoutError<'tcx> {
|
impl<'tcx> fmt::Display for LayoutError<'tcx> {
|
||||||
|
@ -208,16 +210,24 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
|
||||||
LayoutError::SizeOverflow(ty) => {
|
LayoutError::SizeOverflow(ty) => {
|
||||||
write!(f, "values of the type `{}` are too big for the current architecture", ty)
|
write!(f, "values of the type `{}` are too big for the current architecture", ty)
|
||||||
}
|
}
|
||||||
|
LayoutError::NormalizationFailure(t, e) => write!(
|
||||||
|
f,
|
||||||
|
"unable to determine layout for `{}` because `{}` cannot be normalized",
|
||||||
|
t,
|
||||||
|
e.get_type_for_failure()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(tcx, query), level = "debug")]
|
||||||
fn layout_of<'tcx>(
|
fn layout_of<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
|
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||||
) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
|
) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
|
||||||
ty::tls::with_related_context(tcx, move |icx| {
|
ty::tls::with_related_context(tcx, move |icx| {
|
||||||
let (param_env, ty) = query.into_parts();
|
let (param_env, ty) = query.into_parts();
|
||||||
|
debug!(?ty);
|
||||||
|
|
||||||
if !tcx.recursion_limit().value_within_limit(icx.layout_depth) {
|
if !tcx.recursion_limit().value_within_limit(icx.layout_depth) {
|
||||||
tcx.sess.fatal(&format!("overflow representing the type `{}`", ty));
|
tcx.sess.fatal(&format!("overflow representing the type `{}`", ty));
|
||||||
|
@ -229,7 +239,18 @@ fn layout_of<'tcx>(
|
||||||
ty::tls::enter_context(&icx, |_| {
|
ty::tls::enter_context(&icx, |_| {
|
||||||
let param_env = param_env.with_reveal_all_normalized(tcx);
|
let param_env = param_env.with_reveal_all_normalized(tcx);
|
||||||
let unnormalized_ty = ty;
|
let unnormalized_ty = ty;
|
||||||
let ty = tcx.normalize_erasing_regions(param_env, ty);
|
|
||||||
|
// FIXME: We might want to have two different versions of `layout_of`:
|
||||||
|
// One that can be called after typecheck has completed and can use
|
||||||
|
// `normalize_erasing_regions` here and another one that can be called
|
||||||
|
// before typecheck has completed and uses `try_normalize_erasing_regions`.
|
||||||
|
let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(normalization_error) => {
|
||||||
|
return Err(LayoutError::NormalizationFailure(ty, normalization_error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if ty != unnormalized_ty {
|
if ty != unnormalized_ty {
|
||||||
// Ensure this layout is also cached for the normalized type.
|
// Ensure this layout is also cached for the normalized type.
|
||||||
return tcx.layout_of(param_env.and(ty));
|
return tcx.layout_of(param_env.and(ty));
|
||||||
|
|
|
@ -8,10 +8,28 @@
|
||||||
//! or constant found within. (This underlying query is what is cached.)
|
//! or constant found within. (This underlying query is what is cached.)
|
||||||
|
|
||||||
use crate::mir;
|
use crate::mir;
|
||||||
|
use crate::traits::query::NoSolution;
|
||||||
use crate::ty::fold::{TypeFoldable, TypeFolder};
|
use crate::ty::fold::{TypeFoldable, TypeFolder};
|
||||||
use crate::ty::subst::{Subst, SubstsRef};
|
use crate::ty::subst::{Subst, SubstsRef};
|
||||||
use crate::ty::{self, Ty, TyCtxt};
|
use crate::ty::{self, Ty, TyCtxt};
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
|
||||||
|
pub enum NormalizationError<'tcx> {
|
||||||
|
Type(Ty<'tcx>),
|
||||||
|
Const(ty::Const<'tcx>),
|
||||||
|
ConstantKind(mir::ConstantKind<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> NormalizationError<'tcx> {
|
||||||
|
pub fn get_type_for_failure(&self) -> String {
|
||||||
|
match self {
|
||||||
|
NormalizationError::Type(t) => format!("{}", t),
|
||||||
|
NormalizationError::Const(c) => format!("{}", c),
|
||||||
|
NormalizationError::ConstantKind(ck) => format!("{}", ck),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> TyCtxt<'tcx> {
|
impl<'tcx> TyCtxt<'tcx> {
|
||||||
/// Erase the regions in `value` and then fully normalize all the
|
/// Erase the regions in `value` and then fully normalize all the
|
||||||
/// types found within. The result will also have regions erased.
|
/// types found within. The result will also have regions erased.
|
||||||
|
@ -32,6 +50,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
// Erase first before we do the real query -- this keeps the
|
// Erase first before we do the real query -- this keeps the
|
||||||
// cache from being too polluted.
|
// cache from being too polluted.
|
||||||
let value = self.erase_regions(value);
|
let value = self.erase_regions(value);
|
||||||
|
debug!(?value);
|
||||||
|
|
||||||
if !value.has_projections() {
|
if !value.has_projections() {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
|
@ -41,6 +61,39 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tries to erase the regions in `value` and then fully normalize all the
|
||||||
|
/// types found within. The result will also have regions erased.
|
||||||
|
///
|
||||||
|
/// Contrary to `normalize_erasing_regions` this function does not assume that normalization
|
||||||
|
/// succeeds.
|
||||||
|
pub fn try_normalize_erasing_regions<T>(
|
||||||
|
self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
value: T,
|
||||||
|
) -> Result<T, NormalizationError<'tcx>>
|
||||||
|
where
|
||||||
|
T: TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
debug!(
|
||||||
|
"try_normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
|
||||||
|
std::any::type_name::<T>(),
|
||||||
|
value,
|
||||||
|
param_env,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Erase first before we do the real query -- this keeps the
|
||||||
|
// cache from being too polluted.
|
||||||
|
let value = self.erase_regions(value);
|
||||||
|
debug!(?value);
|
||||||
|
|
||||||
|
if !value.has_projections() {
|
||||||
|
Ok(value)
|
||||||
|
} else {
|
||||||
|
let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env);
|
||||||
|
value.fold_with(&mut folder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// If you have a `Binder<'tcx, T>`, you can do this to strip out the
|
/// If you have a `Binder<'tcx, T>`, you can do this to strip out the
|
||||||
/// late-bound regions and then normalize the result, yielding up
|
/// late-bound regions and then normalize the result, yielding up
|
||||||
/// a `T` (with regions erased). This is appropriate when the
|
/// a `T` (with regions erased). This is appropriate when the
|
||||||
|
@ -91,11 +144,14 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
|
impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
|
||||||
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn normalize_generic_arg_after_erasing_regions(
|
fn normalize_generic_arg_after_erasing_regions(
|
||||||
&self,
|
&self,
|
||||||
arg: ty::GenericArg<'tcx>,
|
arg: ty::GenericArg<'tcx>,
|
||||||
) -> ty::GenericArg<'tcx> {
|
) -> ty::GenericArg<'tcx> {
|
||||||
let arg = self.param_env.and(arg);
|
let arg = self.param_env.and(arg);
|
||||||
|
debug!(?arg);
|
||||||
|
|
||||||
self.tcx.normalize_generic_arg_after_erasing_regions(arg)
|
self.tcx.normalize_generic_arg_after_erasing_regions(arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,3 +182,62 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
|
||||||
Ok(self.tcx.normalize_mir_const_after_erasing_regions(arg))
|
Ok(self.tcx.normalize_mir_const_after_erasing_regions(arg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
|
||||||
|
fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||||
|
TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
fn try_normalize_generic_arg_after_erasing_regions(
|
||||||
|
&self,
|
||||||
|
arg: ty::GenericArg<'tcx>,
|
||||||
|
) -> Result<ty::GenericArg<'tcx>, NoSolution> {
|
||||||
|
let arg = self.param_env.and(arg);
|
||||||
|
debug!(?arg);
|
||||||
|
|
||||||
|
self.tcx.try_normalize_generic_arg_after_erasing_regions(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
|
||||||
|
type Error = NormalizationError<'tcx>;
|
||||||
|
|
||||||
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
|
self.tcx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
||||||
|
match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) {
|
||||||
|
Ok(t) => Ok(t.expect_ty()),
|
||||||
|
Err(_) => Err(NormalizationError::Type(ty)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_const(
|
||||||
|
&mut self,
|
||||||
|
c: &'tcx ty::Const<'tcx>,
|
||||||
|
) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
|
||||||
|
match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
|
||||||
|
Ok(t) => Ok(t.expect_const()),
|
||||||
|
Err(_) => Err(NormalizationError::Const(*c)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_mir_const(
|
||||||
|
&mut self,
|
||||||
|
c: mir::ConstantKind<'tcx>,
|
||||||
|
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
|
||||||
|
// FIXME: This *probably* needs canonicalization too!
|
||||||
|
let arg = self.param_env.and(c);
|
||||||
|
match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) {
|
||||||
|
Ok(c) => Ok(c),
|
||||||
|
Err(_) => Err(NormalizationError::ConstantKind(c)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,14 @@ crate fn provide(p: &mut Providers) {
|
||||||
normalize_mir_const_after_erasing_regions: |tcx, goal| {
|
normalize_mir_const_after_erasing_regions: |tcx, goal| {
|
||||||
normalize_after_erasing_regions(tcx, goal)
|
normalize_after_erasing_regions(tcx, goal)
|
||||||
},
|
},
|
||||||
|
try_normalize_generic_arg_after_erasing_regions: |tcx, goal| {
|
||||||
|
debug!("try_normalize_generic_arg_after_erasing_regions(goal={:#?}", goal);
|
||||||
|
|
||||||
|
try_normalize_after_erasing_regions(tcx, goal)
|
||||||
|
},
|
||||||
|
try_normalize_mir_const_after_erasing_regions: |tcx, goal| {
|
||||||
|
try_normalize_after_erasing_regions(tcx, goal)
|
||||||
|
},
|
||||||
..*p
|
..*p
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -56,6 +64,38 @@ fn normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Cop
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(tcx))]
|
||||||
|
fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Copy>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
goal: ParamEnvAnd<'tcx, T>,
|
||||||
|
) -> Result<T, NoSolution> {
|
||||||
|
let ParamEnvAnd { param_env, value } = goal;
|
||||||
|
tcx.infer_ctxt().enter(|infcx| {
|
||||||
|
let cause = ObligationCause::dummy();
|
||||||
|
match infcx.at(&cause, param_env).normalize(value) {
|
||||||
|
Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
|
||||||
|
// We don't care about the `obligations`; they are
|
||||||
|
// always only region relations, and we are about to
|
||||||
|
// erase those anyway:
|
||||||
|
debug_assert_eq!(
|
||||||
|
normalized_obligations.iter().find(|p| not_outlives_predicate(&p.predicate)),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
|
||||||
|
// It's unclear when `resolve_vars` would have an effect in a
|
||||||
|
// fresh `InferCtxt`. If this assert does trigger, it will give
|
||||||
|
// us a test case.
|
||||||
|
debug_assert_eq!(normalized_value, resolved_value);
|
||||||
|
let erased = infcx.tcx.erase_regions(resolved_value);
|
||||||
|
debug_assert!(!erased.needs_infer(), "{:?}", erased);
|
||||||
|
Ok(erased)
|
||||||
|
}
|
||||||
|
Err(NoSolution) => Err(NoSolution),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool {
|
fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool {
|
||||||
match p.kind().skip_binder() {
|
match p.kind().skip_binder() {
|
||||||
ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false,
|
ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false,
|
||||||
|
|
|
@ -1769,6 +1769,13 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
|
||||||
the type was too big.</p>"
|
the type was too big.</p>"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Err(LayoutError::NormalizationFailure(_, _)) => {
|
||||||
|
writeln!(
|
||||||
|
w,
|
||||||
|
"<p><strong>Note:</strong> Encountered an error during type layout; \
|
||||||
|
the type failed to be normalized.</p>"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(w, "</div>");
|
writeln!(w, "</div>");
|
||||||
|
|
26
src/test/ui/associated-types/issue-59324.rs
Normal file
26
src/test/ui/associated-types/issue-59324.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
trait NotFoo {}
|
||||||
|
|
||||||
|
pub trait Foo: NotFoo {
|
||||||
|
type OnlyFoo;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Service {
|
||||||
|
type AssocType;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ThriftService<Bug: NotFoo>:
|
||||||
|
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
|
||||||
|
//~| ERROR the trait bound `Bug: Foo` is not satisfied
|
||||||
|
Service<AssocType = <Bug as Foo>::OnlyFoo>
|
||||||
|
{
|
||||||
|
fn get_service(
|
||||||
|
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
|
||||||
|
//~| ERROR the trait bound `Bug: Foo` is not satisfied
|
||||||
|
&self,
|
||||||
|
) -> Self::AssocType;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_factory<H>(factory: dyn ThriftService<()>) {}
|
||||||
|
//~^ ERROR the trait bound `(): Foo` is not satisfied
|
||||||
|
|
||||||
|
fn main() {}
|
69
src/test/ui/associated-types/issue-59324.stderr
Normal file
69
src/test/ui/associated-types/issue-59324.stderr
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
error[E0277]: the trait bound `Bug: Foo` is not satisfied
|
||||||
|
--> $DIR/issue-59324.rs:11:1
|
||||||
|
|
|
||||||
|
LL | / pub trait ThriftService<Bug: NotFoo>:
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
|
||||||
|
... |
|
||||||
|
LL | | ) -> Self::AssocType;
|
||||||
|
LL | | }
|
||||||
|
| |_^ the trait `Foo` is not implemented for `Bug`
|
||||||
|
|
|
||||||
|
help: consider further restricting this bound
|
||||||
|
|
|
||||||
|
LL | pub trait ThriftService<Bug: NotFoo + Foo>:
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `Bug: Foo` is not satisfied
|
||||||
|
--> $DIR/issue-59324.rs:11:1
|
||||||
|
|
|
||||||
|
LL | / pub trait ThriftService<Bug: NotFoo>:
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
|
||||||
|
... |
|
||||||
|
LL | | ) -> Self::AssocType;
|
||||||
|
LL | | }
|
||||||
|
| |_^ the trait `Foo` is not implemented for `Bug`
|
||||||
|
|
|
||||||
|
help: consider further restricting this bound
|
||||||
|
|
|
||||||
|
LL | pub trait ThriftService<Bug: NotFoo + Foo>:
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `Bug: Foo` is not satisfied
|
||||||
|
--> $DIR/issue-59324.rs:16:5
|
||||||
|
|
|
||||||
|
LL | / fn get_service(
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | &self,
|
||||||
|
LL | | ) -> Self::AssocType;
|
||||||
|
| |_________________________^ the trait `Foo` is not implemented for `Bug`
|
||||||
|
|
|
||||||
|
help: consider further restricting this bound
|
||||||
|
|
|
||||||
|
LL | pub trait ThriftService<Bug: NotFoo + Foo>:
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `Bug: Foo` is not satisfied
|
||||||
|
--> $DIR/issue-59324.rs:16:8
|
||||||
|
|
|
||||||
|
LL | fn get_service(
|
||||||
|
| ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
|
||||||
|
|
|
||||||
|
help: consider further restricting this bound
|
||||||
|
|
|
||||||
|
LL | pub trait ThriftService<Bug: NotFoo + Foo>:
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `(): Foo` is not satisfied
|
||||||
|
--> $DIR/issue-59324.rs:23:29
|
||||||
|
|
|
||||||
|
LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
62
src/test/ui/associated-types/issue-67684.rs
Normal file
62
src/test/ui/associated-types/issue-67684.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
trait ParseError {
|
||||||
|
type StreamError;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ParseError for T {
|
||||||
|
type StreamError = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Stream {
|
||||||
|
type Item;
|
||||||
|
type Error: ParseError;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Parser
|
||||||
|
where
|
||||||
|
<Self as Parser>::PartialState: Default,
|
||||||
|
{
|
||||||
|
type PartialState;
|
||||||
|
fn parse_mode(_: &Self, _: Self::PartialState) {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stream for () {
|
||||||
|
type Item = ();
|
||||||
|
type Error = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parser for () {
|
||||||
|
type PartialState = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AndThen<A, B>(core::marker::PhantomData<(A, B)>);
|
||||||
|
|
||||||
|
impl<A, B> Parser for AndThen<A, B>
|
||||||
|
where
|
||||||
|
A: Stream,
|
||||||
|
B: Into<<A::Error as ParseError>::StreamError>,
|
||||||
|
{
|
||||||
|
type PartialState = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expr<A>() -> impl Parser
|
||||||
|
where
|
||||||
|
A: Stream<Error = <A as Stream>::Item>,
|
||||||
|
{
|
||||||
|
AndThen::<A, ()>(core::marker::PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_mode_impl<A>()
|
||||||
|
where
|
||||||
|
<A as Stream>::Error: ParseError,
|
||||||
|
A: Stream<Error = <A as Stream>::Item>,
|
||||||
|
{
|
||||||
|
Parser::parse_mode(&expr::<A>(), Default::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
21
src/test/ui/associated-types/issue-69398.rs
Normal file
21
src/test/ui/associated-types/issue-69398.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
pub trait Foo {
|
||||||
|
type Bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Broken {
|
||||||
|
type Assoc;
|
||||||
|
fn broken(&self) where Self::Assoc: Foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Broken for T {
|
||||||
|
type Assoc = ();
|
||||||
|
fn broken(&self) where Self::Assoc: Foo {
|
||||||
|
let _x: <Self::Assoc as Foo>::Bar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _m: &dyn Broken<Assoc=()> = &();
|
||||||
|
}
|
16
src/test/ui/associated-types/issue-71113.rs
Normal file
16
src/test/ui/associated-types/issue-71113.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
enum _Recursive<'a>
|
||||||
|
where
|
||||||
|
Self: ToOwned<Owned=Box<Self>>
|
||||||
|
{
|
||||||
|
Variant(MyCow<'a, _Recursive<'a>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Wrapper<T>(T);
|
||||||
|
|
||||||
|
pub struct MyCow<'a, T: ToOwned<Owned=Box<T>> + 'a>(Wrapper<Cow<'a, T>>);
|
||||||
|
|
||||||
|
fn main() {}
|
121
src/test/ui/associated-types/issue-82079.rs
Normal file
121
src/test/ui/associated-types/issue-82079.rs
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
mod convenience_operators {
|
||||||
|
use crate::{Op, Relation};
|
||||||
|
use std::ops::AddAssign;
|
||||||
|
use std::ops::Mul;
|
||||||
|
|
||||||
|
impl<C: Op> Relation<C> {
|
||||||
|
pub fn map<F: Fn(C::D) -> D2 + 'static, D2: 'static>(
|
||||||
|
self,
|
||||||
|
f: F,
|
||||||
|
) -> Relation<impl Op<D = D2, R = C::R>> {
|
||||||
|
self.map_dr(move |x, r| (f(x), r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: 'static, V: 'static, C: Op<D = (K, V)>> Relation<C> {
|
||||||
|
pub fn semijoin<C2: Op<D = K, R = R2>, R2, R3: AddAssign<R3>>(
|
||||||
|
self,
|
||||||
|
other: Relation<C2>,
|
||||||
|
) -> Relation<impl Op<D = C::D, R = R3>>
|
||||||
|
where
|
||||||
|
C::R: Mul<R2, Output = R3>,
|
||||||
|
{
|
||||||
|
self.join(other.map(|x| (x, ()))).map(|(k, x, ())| (k, x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod core {
|
||||||
|
mod operator {
|
||||||
|
mod join {
|
||||||
|
use super::Op;
|
||||||
|
use crate::core::Relation;
|
||||||
|
use std::ops::{AddAssign, Mul};
|
||||||
|
struct Join<LC, RC> {
|
||||||
|
_left: LC,
|
||||||
|
_right: RC,
|
||||||
|
}
|
||||||
|
impl<
|
||||||
|
LC: Op<D = (K, LD), R = LR>,
|
||||||
|
RC: Op<D = (K, RD), R = RR>,
|
||||||
|
K: 'static,
|
||||||
|
LD: 'static,
|
||||||
|
LR: AddAssign<LR> + Mul<RR, Output = OR>,
|
||||||
|
RD: 'static,
|
||||||
|
RR: AddAssign<RR>,
|
||||||
|
OR: AddAssign<OR>,
|
||||||
|
> Op for Join<LC, RC>
|
||||||
|
{
|
||||||
|
type D = (K, LD, RD);
|
||||||
|
type R = OR;
|
||||||
|
}
|
||||||
|
impl<K: 'static, D: 'static, C: Op<D = (K, D)>> Relation<C> {
|
||||||
|
pub fn join<C2: Op<D = (K, D2)>, D2: 'static, OR: AddAssign<OR>>(
|
||||||
|
self,
|
||||||
|
other: Relation<C2>,
|
||||||
|
) -> Relation<impl Op<D = (K, D, D2), R = OR>>
|
||||||
|
where
|
||||||
|
C::R: Mul<C2::R, Output = OR>,
|
||||||
|
{
|
||||||
|
Relation {
|
||||||
|
inner: Join {
|
||||||
|
_left: self.inner,
|
||||||
|
_right: other.inner,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mod map {
|
||||||
|
use super::Op;
|
||||||
|
use crate::core::Relation;
|
||||||
|
use std::ops::AddAssign;
|
||||||
|
struct Map<C, MF> {
|
||||||
|
_inner: C,
|
||||||
|
_op: MF,
|
||||||
|
}
|
||||||
|
impl<
|
||||||
|
D1,
|
||||||
|
R1,
|
||||||
|
D2: 'static,
|
||||||
|
R2: AddAssign<R2>,
|
||||||
|
C: Op<D = D1, R = R1>,
|
||||||
|
MF: Fn(D1, R1) -> (D2, R2),
|
||||||
|
> Op for Map<C, MF>
|
||||||
|
{
|
||||||
|
type D = D2;
|
||||||
|
type R = R2;
|
||||||
|
}
|
||||||
|
impl<C: Op> Relation<C> {
|
||||||
|
pub fn map_dr<F: Fn(C::D, C::R) -> (D2, R2), D2: 'static, R2: AddAssign<R2>>(
|
||||||
|
self,
|
||||||
|
f: F,
|
||||||
|
) -> Relation<impl Op<D = D2, R = R2>> {
|
||||||
|
Relation {
|
||||||
|
inner: Map {
|
||||||
|
_inner: self.inner,
|
||||||
|
_op: f,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use std::ops::AddAssign;
|
||||||
|
pub trait Op {
|
||||||
|
type D: 'static;
|
||||||
|
type R: AddAssign<Self::R>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub use self::operator::Op;
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Relation<C> {
|
||||||
|
inner: C,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use self::core::Op;
|
||||||
|
pub use self::core::Relation;
|
||||||
|
|
||||||
|
fn main() {}
|
9
src/test/ui/associated-types/issue-85103.rs
Normal file
9
src/test/ui/associated-types/issue-85103.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
#[rustc_layout(debug)]
|
||||||
|
type Edges<'a, E> = Cow<'a, [E]>;
|
||||||
|
//~^ ERROR layout error: NormalizationFailure
|
||||||
|
|
||||||
|
fn main() {}
|
8
src/test/ui/associated-types/issue-85103.stderr
Normal file
8
src/test/ui/associated-types/issue-85103.stderr
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
error: layout error: NormalizationFailure(<[E] as std::borrow::ToOwned>::Owned, Type(<[E] as std::borrow::ToOwned>::Owned))
|
||||||
|
--> $DIR/issue-85103.rs:6:1
|
||||||
|
|
|
||||||
|
LL | type Edges<'a, E> = Cow<'a, [E]>;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
32
src/test/ui/associated-types/issue-88856.rs
Normal file
32
src/test/ui/associated-types/issue-88856.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(generic_const_exprs)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
pub trait Trait{
|
||||||
|
type R;
|
||||||
|
fn func(self)->Self::R;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TraitImpl<const N:usize>(pub i32);
|
||||||
|
|
||||||
|
impl<const N:usize> Trait for TraitImpl<N>
|
||||||
|
where [();N/2]:,
|
||||||
|
{
|
||||||
|
type R = Self;
|
||||||
|
fn func(self)->Self::R {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sample<P,Convert>(p:P,f:Convert) -> i32
|
||||||
|
where
|
||||||
|
P:Trait,Convert:Fn(P::R)->i32
|
||||||
|
{
|
||||||
|
f(p.func())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let t = TraitImpl::<10>(4);
|
||||||
|
sample(t,|x|x.0);
|
||||||
|
}
|
17
src/test/ui/associated-types/issue-91231.rs
Normal file
17
src/test/ui/associated-types/issue-91231.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(extern_types)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
extern {
|
||||||
|
type Extern;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn f<'a>(_: <&'a Extern as Trait>::Type) where &'a Extern: Trait {}
|
||||||
|
|
||||||
|
fn main() {}
|
13
src/test/ui/associated-types/issue-91234.rs
Normal file
13
src/test/ui/associated-types/issue-91234.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
struct Struct;
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Enum<'a> where &'a Struct: Trait {
|
||||||
|
Variant(<&'a Struct as Trait>::Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue