diff options
author | bors <bors@rust-lang.org> | 2021-12-01 13:33:33 +0000 |
---|---|---|
committer | bors <bors@rust-lang.org> | 2021-12-01 13:33:33 +0000 |
commit | f04a2f4b8e89eac1119061ea2055d33c97e618b4 (patch) | |
tree | 915594a7e1efa285136276bd9bd1a87b81be1365 | |
parent | 26b45573be204da2cc0db12828b7a03c41c73793 (diff) | |
parent | 6952470095180e74d59ae372d06a75818368000b (diff) | |
download | rust-f04a2f4b8e89eac1119061ea2055d33c97e618b4.tar.gz |
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.
18 files changed, 600 insertions, 5 deletions
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 708cd56e068..b20f7357b35 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1337,7 +1337,9 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { let layout = match cx.layout_of(ty) { Ok(layout) => layout, Err( - ty::layout::LayoutError::Unknown(_) | ty::layout::LayoutError::SizeOverflow(_), + ty::layout::LayoutError::Unknown(_) + | ty::layout::LayoutError::SizeOverflow(_) + | ty::layout::LayoutError::NormalizationFailure(_, _), ) => return, }; let (variants, tag) = match layout.variants { diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 7a51bb4a1f3..8e4a17bfa65 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -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> { /// The program caused undefined behavior. UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 268a66b9926..8667a6bea11 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1644,6 +1644,11 @@ rustc_queries! { 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. query normalize_generic_arg_after_erasing_regions( goal: ParamEnvAnd<'tcx, GenericArg<'tcx>> @@ -1658,6 +1663,20 @@ rustc_queries! { 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( goal: CanonicalTyGoal<'tcx> ) -> Result< diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index b87e23af72b..57506bc6834 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1,5 +1,6 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; +use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::subst::Subst; use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable}; use rustc_ast as ast; @@ -199,6 +200,7 @@ pub const MAX_SIMD_LANES: u64 = 1 << 0xF; pub enum LayoutError<'tcx> { Unknown(Ty<'tcx>), SizeOverflow(Ty<'tcx>), + NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>), } impl<'tcx> fmt::Display for LayoutError<'tcx> { @@ -208,16 +210,24 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { LayoutError::SizeOverflow(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>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> { ty::tls::with_related_context(tcx, move |icx| { let (param_env, ty) = query.into_parts(); + debug!(?ty); if !tcx.recursion_limit().value_within_limit(icx.layout_depth) { tcx.sess.fatal(&format!("overflow representing the type `{}`", ty)); @@ -229,7 +239,18 @@ fn layout_of<'tcx>( ty::tls::enter_context(&icx, |_| { let param_env = param_env.with_reveal_all_normalized(tcx); 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 { // Ensure this layout is also cached for the normalized type. return tcx.layout_of(param_env.and(ty)); diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index e6f67adae93..fce7cbfbb3d 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -8,10 +8,28 @@ //! or constant found within. (This underlying query is what is cached.) use crate::mir; +use crate::traits::query::NoSolution; use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::ty::subst::{Subst, SubstsRef}; 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> { /// Erase the regions in `value` and then fully normalize all the /// 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 // cache from being too polluted. let value = self.erase_regions(value); + debug!(?value); + if !value.has_projections() { value } 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 /// late-bound regions and then normalize the result, yielding up /// a `T` (with regions erased). This is appropriate when the @@ -91,11 +144,14 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> { } impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { + #[instrument(skip(self), level = "debug")] fn normalize_generic_arg_after_erasing_regions( &self, arg: ty::GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { let arg = self.param_env.and(arg); + debug!(?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)) } } + +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)), + } + } +} diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 61ab5e28b67..4f35909df7f 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -20,6 +20,14 @@ crate fn provide(p: &mut Providers) { normalize_mir_const_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 }; } @@ -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 { match p.kind().skip_binder() { ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index d3738cfa3e7..62fdec15af4 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1769,6 +1769,13 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) { 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>"); diff --git a/src/test/ui/associated-types/issue-59324.rs b/src/test/ui/associated-types/issue-59324.rs new file mode 100644 index 00000000000..9e68e9e7751 --- /dev/null +++ b/src/test/ui/associated-types/issue-59324.rs @@ -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() {} diff --git a/src/test/ui/associated-types/issue-59324.stderr b/src/test/ui/associated-types/issue-59324.stderr new file mode 100644 index 00000000000..2f430d3055e --- /dev/null +++ b/src/test/ui/associated-types/issue-59324.stderr @@ -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`. diff --git a/src/test/ui/associated-types/issue-67684.rs b/src/test/ui/associated-types/issue-67684.rs new file mode 100644 index 00000000000..49efe8a1bda --- /dev/null +++ b/src/test/ui/associated-types/issue-67684.rs @@ -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() {} diff --git a/src/test/ui/associated-types/issue-69398.rs b/src/test/ui/associated-types/issue-69398.rs new file mode 100644 index 00000000000..ca3d66b1c8e --- /dev/null +++ b/src/test/ui/associated-types/issue-69398.rs @@ -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=()> = &(); +} diff --git a/src/test/ui/associated-types/issue-71113.rs b/src/test/ui/associated-types/issue-71113.rs new file mode 100644 index 00000000000..48de89127f4 --- /dev/null +++ b/src/test/ui/associated-types/issue-71113.rs @@ -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() {} diff --git a/src/test/ui/associated-types/issue-82079.rs b/src/test/ui/associated-types/issue-82079.rs new file mode 100644 index 00000000000..590c799c2d7 --- /dev/null +++ b/src/test/ui/associated-types/issue-82079.rs @@ -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() {} diff --git a/src/test/ui/associated-types/issue-85103.rs b/src/test/ui/associated-types/issue-85103.rs new file mode 100644 index 00000000000..c5e13856178 --- /dev/null +++ b/src/test/ui/associated-types/issue-85103.rs @@ -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() {} diff --git a/src/test/ui/associated-types/issue-85103.stderr b/src/test/ui/associated-types/issue-85103.stderr new file mode 100644 index 00000000000..142f3c411ec --- /dev/null +++ b/src/test/ui/associated-types/issue-85103.stderr @@ -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 + diff --git a/src/test/ui/associated-types/issue-88856.rs b/src/test/ui/associated-types/issue-88856.rs new file mode 100644 index 00000000000..7cae7c71cd2 --- /dev/null +++ b/src/test/ui/associated-types/issue-88856.rs @@ -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); +} diff --git a/src/test/ui/associated-types/issue-91231.rs b/src/test/ui/associated-types/issue-91231.rs new file mode 100644 index 00000000000..3c1cb81f097 --- /dev/null +++ b/src/test/ui/associated-types/issue-91231.rs @@ -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() {} diff --git a/src/test/ui/associated-types/issue-91234.rs b/src/test/ui/associated-types/issue-91234.rs new file mode 100644 index 00000000000..2f6c2d3aebd --- /dev/null +++ b/src/test/ui/associated-types/issue-91234.rs @@ -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() {} |